ESP32 Temperature/Humidity sensor stops updates after several days

I am working on a simple project to take temperature and humidity from a DHT22 and post it to Thingspeak.

The code is intended to do the following:

  • Every 60 seconds, check to see if it's still connected to WiFi, and reconnect if not
  • Every hour, pull data from the DHT22 and Post that to Thingspeak
  • Reset the board

Problem:
Everything seems to run fine for 2 - 5 days and then it will just stop sending updates. If I reset the board, it jumps right back into things and goes along its merry way. I can't figure out any rhyme or reason for why it stops working.

Ask:
I have been bashing my head into a wall now for weeks trying to figure this out! Can anyone see something I'm missing or how I might go about troubleshooting this? I can't really leave it plugged into my computer with the serial monitor up for a week at a time to see why it fails. Is there another way to go about this?

My experience level:
I am an armature hobbyist, with some (but limited) programing experience. This project seemed like it would be pretty straight forward given my knowledge level . . . looks like I was wrong. :o

Hardware:

  • DHT22
  • 22k resistor
  • ESP32 Dev Board

Schematic:
(borrowed from Microcontrollerslab.com - thank you!)

#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
// Get ESP32Ping.h library here --> https://github.com/marian-craciunescu/ESP32Ping
#include <ESP32Ping.h>

const char* ssid = "*******";
const char* password = "*********";

// Service API Key
String apiKey = "*********************************";

#define DHTPIN 4     // Digital pin connected to the DHT sensor

#define DHTTYPE    DHT22     // DHT 22 (AM2302)

float t;
float h;

DHT dht(DHTPIN, DHTTYPE);

// Domain Name with full URL Path for HTTP POST Request
const char* serverName = "http://api.thingspeak.com/update";

// Check the humidity/temp every 1 hour (3600000 milliseconds)
unsigned long timerDelay = 3600000 ;
// Initially set to ensure a forced read as soon as first plugged in
unsigned long lastTime = 10;

//check wifi every 60 seonds
unsigned long check_wifi = 60000;
unsigned long last_wifi = 10000000;

void setup() {
  Serial.begin(115200);
  dht.begin();

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network, with Local IP address:");
  Serial.println(WiFi.localIP());
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);

  bool success = Ping.ping("www.google.com", 3);

  if (!success) {
    Serial.println("\nPing failed");
    return;
  }

  Serial.println("\nPing successful.");

  Serial.print("Humidity/Temp timer set to ");
  Serial.print(timerDelay);
  Serial.println("milliseconds using the [timerDelay] variable.");

  getReadings();
  sendReadings();

  // Random seed is a number used to initialize a pseudorandom number generator
  randomSeed(analogRead(33));
  delay(500);
}

void loop() {

  //Check WiFi connection status
  if (((millis() - last_wifi) > check_wifi)) {
    Serial.println("Q: is the device connected to your wifi?");

    //If not connected, try to reconnect
    if (WiFi.status() != WL_CONNECTED) {
      Serial.println("A: No. Trying to reconnect now . . . ");
      WiFi.reconnect();
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("");
      Serial.print("Reconnected to wifi with Local IP:");
      Serial.println(WiFi.localIP());
    }

    //If wifi is connected, reset last_wifi to millis() and keep going 
    Serial.println("A: Yes.");
    last_wifi = millis();

    //Send an HTTP POST request every [timerDelay] seconds
    if ((millis() - lastTime) > timerDelay) {
      //Check the DHT22 
      getReadings();
      //Send temp and humid to thingspeak
      sendReadings();
      //restart the timer
      lastTime = millis();
      delay(500);
      //rest the ESP32 
      ESP.restart();
    }
  }
}

void getReadings() {
  t = dht.readTemperature(true);
  // Check if any reads failed and exit early (to try again).
  if (isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
  }
  else {
    Serial.println(t);
  }

  h = dht.readHumidity();
  // Check if any reads failed and exit early (to try again).
  if (isnan(h)) {
    Serial.println("Failed to read from DHT sensor!");
  }
  else {
    Serial.println(h);
  }
}

void sendReadings() {
    //Before sendting data to thingspeak, doublecheck that you're still connected
    if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;

    // Your Domain name with URL path or IP address with path
    http.begin(serverName);

    // Specify content-type header
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    // Data to send with HTTP POST
    String httpRequestData = "api_key=" + apiKey + "&field1=" + String(t) + "&field2=" + String(h);
    // Send HTTP POST request
    int httpResponseCode = http.POST(httpRequestData);

    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    // Free resources
    http.end();
  }
}

Here is a connect to WiFi that I use

void connectToWiFi()
{
  int TryCount = 0;
  //log_i( "connect to wifi" );
  while ( WiFi.status() != WL_CONNECTED )
  {
    TryCount++;
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    //log_i(" waiting on wifi connection" );
    vTaskDelay( 4000 );
    if ( TryCount == 10 )
    {
      ESP.restart();
    }
  }
  //log_i( "Connected to WiFi" );
  WiFi.onEvent( WiFiEvent );
}

Note the WiFi.disconnect() that occurs before the connect. WiFi.disconnect does 2 things. If the WiFi is connected, disconnect. The other thing that WiFi.disconnect does is reset the WiFi stack to default values.

To check for a WiFi connection you may find that if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
will work a bit better.

Here is a ESP32 task using the equlivence of micros() to trigger a few events

void fDoMoistureDetector( void * parameter )
{
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  int      TimeToPublish = 5000000; //5000000uS
  int      TimeForADreading = 100 * 1000; // 100mS
  uint64_t TimePastPublish = esp_timer_get_time(); // used by publish
  uint64_t TimeADreading   = esp_timer_get_time();
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 10; //delay for 10mS
  float    RemainingMoisture = 100.0f; //prevents pump turn on during start up
  for (;;)
  {
    //read AD values every 100mS.
    if ( (esp_timer_get_time() - TimeADreading) >= TimeForADreading )
    {
      xEventGroupSetBits( eg, evtADCreading );
      TimeADreading = esp_timer_get_time();
    }
    xQueueReceive(xQ_RM, &RemainingMoisture, 0 ); //receive queue stuff no waiting
    //read gpio 0 is water level good. Yes: OK to run pump : no pump off.   remaining moisture good, denergize water pump otherwise energize water pump.
    if ( gpio_get_level( GPIO_NUM_0 ) )
    {
      if ( RemainingMoisture >= 40.0f ) {
        WaterPump0_off();
      }
      if ( RemainingMoisture <= 20.0f )
      {
        WaterPump0_on();
      }
      //xSemaphoreGive( sema_RemainingMoisture );
    } else {
      log_i( "water level bad " );
      WaterPump0_off();
    }
    // publish to MQTT every 5000000uS
    if ( (esp_timer_get_time() - TimePastPublish) >= TimeToPublish )
    {
      xQueueOverwrite( xQ_RemainingMoistureMQTT, (void *) &RemainingMoisture );// data for mqtt publish
      TimePastPublish = esp_timer_get_time(); // get next publish time
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
}// end fDoMoistureDetector()

Using the ESP32's esp_timer_get_time() does not suffer with the same issues that using millis() can have.

Here is a more extensive wifi call back that I have used for troubleshooting WiFi connections

void WiFiEvent(WiFiEvent_t event)
{
   log_i( "[WiFi-event] event: %d\n", event );
  switch (event) {
        case SYSTEM_EVENT_WIFI_READY:
          log_i("WiFi interface ready");
          break;
        case SYSTEM_EVENT_SCAN_DONE:
          log_i("Completed scan for access points");
          break;
        case SYSTEM_EVENT_STA_START:
          log_i("WiFi client started");
          break;
        case SYSTEM_EVENT_STA_STOP:
          log_i("WiFi clients stopped");
          break;
    case SYSTEM_EVENT_STA_CONNECTED:
      log_i("Connected to access point");
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      log_i("Disconnected from WiFi access point");
      break;
        case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
          log_i("Authentication mode of access point has changed");
          break;
        case SYSTEM_EVENT_STA_GOT_IP:
          log_i ("Obtained IP address: %s",  WiFi.localIP() );
          break;
        case SYSTEM_EVENT_STA_LOST_IP:
          log_i("Lost IP address and IP address is reset to 0");
          //      vTaskDelay( 5000 );
          //      ESP.restart();
          break;
        case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
          log_i("WiFi Protected Setup (WPS): succeeded in enrollee mode");
          break;
        case SYSTEM_EVENT_STA_WPS_ER_FAILED:
          log_i("WiFi Protected Setup (WPS): failed in enrollee mode");
          //      ESP.restart();
          break;
        case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
          log_i("WiFi Protected Setup (WPS): timeout in enrollee mode");
          break;
        case SYSTEM_EVENT_STA_WPS_ER_PIN:
          log_i("WiFi Protected Setup (WPS): pin code in enrollee mode");
          break;
        case SYSTEM_EVENT_AP_START:
          log_i("WiFi access point started");
          break;
        case SYSTEM_EVENT_AP_STOP:
          log_i("WiFi access point  stopped");
          //      WiFi.mode( WIFI_OFF);
          //      esp_sleep_enable_timer_wakeup( 1000000 * 2 ); // 1 second times how many seconds wanted
          //      esp_deep_sleep_start();
          break;
        case SYSTEM_EVENT_AP_STACONNECTED:
          log_i("Client connected");
          break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
      log_i("WiFi client disconnected");
          break;
        case SYSTEM_EVENT_AP_STAIPASSIGNED:
          log_i("Assigned IP address to client");
          break;
        case SYSTEM_EVENT_AP_PROBEREQRECVED:
          log_i("Received probe request");
          break;
        case SYSTEM_EVENT_GOT_IP6:
          log_i("IPv6 is preferred");
          break;
        case SYSTEM_EVENT_ETH_GOT_IP:
          log_i("Obtained IP address");
          break;
    default: break;
  }
}

An ESP32, using millis() does not need a, unsigned long timerDelay = 3600000 ;. ESP32 ints are large enough.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.