Disconnecting and malfunctioning humidity sensors in a terrarium setup—seeking advice

Hello everyone,
I'm encountering repeated issues with humidity sensors in my small terrarium controlled by an Arduino Uno Rev3. The setup includes two AO3400 MOSFETs managing a 60mm CPU fan and a USB humidifier, both powered by Arduino 5V supply. While the fan and humidifier function without issues, my humidity sensors, all of which I’ve tried, gone through new, and now not working—two HDC1080s, two BME280s, and four SHT31s—disconnect after a few hours and cease functioning despite multiple restart attempts.
After excluding the humidifier to isolate the problem, a newly opened BME280 sensors still failed, leading me to suspect that the high humidity levels (70-80%, The edges of the enclosure are sealed with a hot glue gun for humidity to naturally rise) might be shorting the sensors. I'm considering using a SHT-30 mesh-protected sensor but want to avoid connecting it and thus damaging it before resolving the current issue. I can take a hit with the few few cheap sensors I had ran through before.

Here's a condensed version of my wiring and setup:

  1. Fan Wiring:
    • Red Wire (Positive): Connect to the Positive (+) terminal of the external 5V Arduino.
    • Black Wire (Negative): Connect to the Drain (D) of the N-MOSFET.
  2. MOSFET Wiring:
    • Source (S): Connect to the Ground (GND) of the Arduino.
    • Gate (G): Connect via a 220Ω resistor to Digital Pin 3 on the Arduino, with a 10kΩ pull-down resistor to GND.
  3. Flyback Diode: Across the fan terminals to protect against voltage spikes.

Here is the script used.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <math.h>  // Include math library for exp()

// Initialize Adafruit BME280 instance
Adafruit_BME280 bme; // Use I2C interface

#define FAN_CONTROL_PIN 3  // Control pin for the fan

// Target VPD range (in kPa) with deadband
const float VPD_MIN = 0.60; // Minimum target VPD
const float VPD_MAX = 0.70; // Maximum target VPD
const float DEADBAND = 0.05; // Deadband value (adjusted for finer control)
const float TARGET_VPD = (VPD_MIN + VPD_MAX) / 2.0; // Midpoint of target VPD range

const float Kp_fan = 100000.0;  // Proportional gain for the fan

unsigned long lastSensorReadTime = 0;
const unsigned long sensorReadInterval = 60000; // 60 seconds
const unsigned long minOnTime = 5000; // Minimum on-time set to 5 seconds
const unsigned long maxOnTime = 20000; // Maximum on-time set to 20 seconds

unsigned long fanOnUntil = 0;

float humidity = 0;
float tempC = 0;
float VPD = 0;
float VPD_error = 0;

void setup() {
  Serial.begin(9600);
  Wire.begin();

  // Initialize BME280 sensor
  bool status;
  status = bme.begin(0x76);  // BME280 default I2C address is 0x76 or 0x77
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1) delay(10); // Halt the program
  }
  Serial.println("BME280 initialized.");

  // Set up the fan control pin
  pinMode(FAN_CONTROL_PIN, OUTPUT);
  digitalWrite(FAN_CONTROL_PIN, LOW); // Ensure the fan is off at startup

  Serial.println("Setup complete. Entering main loop.");
}

void loop() {
  unsigned long currentMillis = millis();

  // Read sensors every 30 seconds
  if (currentMillis - lastSensorReadTime >= sensorReadInterval) {
    lastSensorReadTime = currentMillis;
    Serial.println("Reading sensors...");

    // Read humidity and temperature from BME280
    humidity = bme.readHumidity();
    tempC = bme.readTemperature();

    // Validate sensor readings
    if (isnan(humidity) || isnan(tempC)) {
      Serial.println("Error: Could not read temperature or humidity from BME280.");
      return; // Exit the loop early to avoid incorrect calculations
    }

    // Calculate Saturated Vapor Pressure (SVP) in kPa
    float SVP = 0.6108 * exp((17.27 * tempC) / (tempC + 237.3));

    // Calculate VPD
    VPD = SVP * (1 - (humidity / 100.0));

    // Calculate VPD error
    VPD_error = TARGET_VPD - VPD;

    // Adjust VPD error to incorporate deadband
    if (abs(VPD_error) < DEADBAND / 2.0) {
      VPD_error = 0; // Do nothing, within deadband
    }

    // Calculate target humidity based on TARGET_VPD
    float targetHumidity = (1 - (TARGET_VPD / SVP)) * 100.0;

    // Print the values
    Serial.print("Current VPD: ");
    Serial.print(VPD, 3);
    Serial.println(" kPa");

    Serial.print("Target VPD: ");
    Serial.print(TARGET_VPD, 3);
    Serial.println(" kPa");

    Serial.print("Current Humidity: ");
    Serial.print(humidity, 2);
    Serial.println(" %");

    Serial.print("Target Humidity: ");
    Serial.print(targetHumidity, 2);
    Serial.println(" %");

    Serial.print("Temperature: ");
    Serial.print(tempC, 2);
    Serial.println(" °C");

    Serial.print("VPD Error: ");
    Serial.print(VPD_error, 3);
    Serial.println(" kPa");

    if (VPD_error > 0) {
      unsigned long onTime = (unsigned long)(Kp_fan * VPD_error);
      onTime = constrain(onTime, minOnTime, maxOnTime);

      fanOnUntil = currentMillis + onTime;

      Serial.print("VPD too low (humidity too high). Fan scheduled to run for ");
      Serial.print(onTime);
      Serial.println(" ms.");
    } else {
      fanOnUntil = 0; // Ensure fan is turned off
      Serial.println("VPD within target range or too high. Fan will be turned off.");
    }

    Serial.println("-----------------------------------");
  }

  // Turn the fan ON or OFF based on the fanOnUntil time
  if (fanOnUntil > currentMillis) {
    digitalWrite(FAN_CONTROL_PIN, HIGH);
  } else {
    if (digitalRead(FAN_CONTROL_PIN) == HIGH) {
      digitalWrite(FAN_CONTROL_PIN, LOW);
      Serial.println("Fan turned OFF.");
    }
    fanOnUntil = 0;
  }

  // Optional: Small delay to prevent overwhelming the loop
  delay(100);
}

And the last read out from the newly installed HiLetgo BME280 3.3V that had only lasted one hour before disconnecting. Do note I did add two 10k resistors from SDA and SCL to 3.3v from recommendations of GPT

“23:57:07.876 -> BME280 initialized.
23:57:07.908 -> Setup complete. Entering main loop.
23:58:07.868 -> Reading sensors...
23:58:07.868 -> Current VPD: 0.584 kPa
23:58:07.915 -> Target VPD: 0.650 kPa
23:58:07.932 -> Current Humidity: 78.53 %
23:58:07.964 -> Target Humidity: 76.11 %
23:58:07.997 -> Temperature: 22.47 °C
23:58:07.997 -> VPD Error: 0.066 kPa
23:58:08.028 -> VPD too low (humidity too high). Fan scheduled to run for 6586 ms.
23:58:08.092 -> -----------------------------------
23:58:14.496 -> Fan turned OFF.

01:09:18.992 -> Fan turned OFF.
01:10:14.059 -> Reading sensors...
01:10:14.059 -> Current VPD: 0.613 kPa
01:10:14.106 -> Target VPD: 0.650 kPa
01:10:14.123 -> Current Humidity: 74.42 %
01:10:14.156 -> Target Humidity: 72.90 %
01:10:14.156 -> Temperature: 20.41 °C
01:10:14.189 -> VPD Error: 0.037 kPa
01:10:14.221 -> VPD too low (humidity too high). Fan scheduled to run for 5000 ms.
01:10:14.286 -> -----------------------------------
01:10:19.050 -> Fan turned OFF.
01:11:14.139 -> Reading sensors...
Ln 12, Col 50

Despite this, all sensors fail during the 'Reading sensors...' step and thus hanging indefinitely and causing plants to be very unhappy. Also as a side note, i did try another arduino rev4 wifi with same results.

Attached are images of the setup. I am a novice and did want to try different approaches before requesting help, so any insights or advice on preventing these frequent sensor failures would be greatly appreciated. Thank you!

Breadboards were never meant for permanent installation. Replace with real point-to-point wires and see if that helps.

would a solderable protoboard or PCB Solderable Breadboard suffice?

Okay, i can definitely work on a proper 5v power source for the CPU fan and the small USB humidifier. Would the sensor be okay drawing from the 3.3v arduino? Thanks

Sure! Much better, depending on the actual soldering!

Do you have sensors with or without level shifters (6-pin ants).
You shouldn't connect a sensor without that to a 5volt-logic Uno.

I suppose humidity doesn't change that fast. Some (Sensirion) sensors have a built-in heater (few mA), that can be turned on between measurements. Use it, turn off, wait a minute, measure.

I have a SHT-type sensor in my bathroom (shower) that I completely have covered in epoxy glue, including soldered wires, with only the sensor window exposed. I then have put a 5x5mm piece of Teflon tape (white, plumbers tape) over the sensor window when the epoxy was still tacky. Then another layer of epoxy, securing the edges of the tape. Teflon lets humidity through but stops condensation and doesn't affect RH readings.
Leo..

Edit: Example code to turn a SHT-21 heater on/off

  Wire.begin();
  Wire.beginTransmission(0x40);  // address
  Wire.write(0xFE);              // reset
  Wire.endTransmission();
  Wire.beginTransmission(0x40);
  Wire.write(0xE6);  // register#1
  Wire.write(0x3E);  // heater on
  Wire.endTransmission();
  delay(3e4);  // 30 sec
  Wire.beginTransmission(0x40);
  Wire.write(0xE6);
  Wire.write(0x3A);  // heater off
  Wire.endTransmission();

Assuming they are sensor issues not connections, you should use an SHT30 sensor in a protected housing.

This is only one, there are likely other sellers on ebay. The mesh is material that will let humidity through but not liquid. Unless you somehow cool the sensor very quickly when at high humidity you should be good.

I've had one of these outside my garage all through the summer where the humidity was in the high 90% range. Its still going strong.

I would also move the boards away from the moisture and make the sensor leads longer to a accommodate the move.