0
votes

Good afternoon, I want to make a continuously operable gateway that measures temperature with esp32. The device sends data via MQTT every 1.5 seconds. Esp freezes after 12 - 24 hours. I read that some users operate the device every 6-7 months without resetting, how can I operate the device for a long time without resetting it?

Note1: As a workaround in the code I reset the device with MQTT, Ethernet and ESP.restart () every 12 hours before it can freeze.

Note2: LEDs indicate that the system is working.

  • Red lights when ethernet or MQTT cannot be connected.
  • Blue indicates trying to connect to MQTT or ethernet.
  • Green indicates that the system is active. When the device was frozen, the green led was still on.

Versions of libraries I use:

  • Arduino IDE == 1.8.14
  • ESP Library Version == 1.0.6
  • MQTT Library Version == 2.5.0
  • ESP Library Version == 2.0.9

ESP Link: https://www.direnc.net/esp32-wroom-32u-wifi-bluetooth-gelistirme-modulu-en

The code:

#include <UIPEthernet.h>
#include <ArduinoJson.h>
#include <MQTT.h>
#include <DHT.h>
//////////////////////// ETHERNET CONFİG //////////////////////////
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
//////////////////////// ETHERNET CONFİG //////////////////////////


//////////////////////// LED & DHT22 CONFİG //////////////////////////
byte red = 2;
byte green = 0;
byte blue = 4;
byte temp = 15;
#define DHTTYPE DHT22
DHT dht = DHT(temp, DHTTYPE);
//////////////////////// LED & DHT22 CONFİG //////////////////////////


//////////////////////// MQTT CONFİG //////////////////////////
#define mqttServer IPAddress(xxx,xxx,xx,xxx)
const char* mqttUser = "test";
const char* mqttPassword = "test";
const char* deviceId = "Ai-Sens 1";
//////////////////////// MQTT CONFİG //////////////////////////


unsigned long lastMillis = 0;
byte x;
byte y;
EthernetClient net;
MQTTClient client;


//Receives an external reset command every 12 hours
void callback(String &topic, String &payload) { 
  if (payload == "1")
  {
    ESP.restart(); // This is just a workaround to avoid the freezing issue
  }  
}


void setup_eth() {
  delay(10);
  digitalWrite(blue, HIGH); // turn the LED on
  //Serial.print("connecting ethernet...");
  if (Ethernet.begin(mac) == 0) {
    // Serial.println("Failed to configure Ethernet using DHCP");
    for (;;)
      ;
  }
  Ethernet.begin(mac, Ethernet.localIP());
  digitalWrite(blue, LOW);
}


void connect() {
  //Serial.print("connecting mqtt...");
  digitalWrite(blue, HIGH);
  while (!client.connected()) {

    if (client.connect(deviceId, mqttUser, mqttPassword)) {
      // Subscribe

      //client.subscribe("esp/data1");
    } else {
      delay(500);
    }
  }
  //Serial.println("\nconnected!");
  digitalWrite(blue, LOW);
  //client.subscribe("esp/data1");
}



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

  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  digitalWrite(red, LOW);
  digitalWrite(green, LOW);
  digitalWrite(blue, LOW);

  dht.begin();
  setup_eth();

  client.setHost(mqttServer, 1883);
  client.setKeepAlive(90);
  client.begin(mqttServer, net);

  connect();

}

void loop() {
  client.loop();
  delay(10);
  
  client.subscribe("esp/rst");
  client.onMessage(callback);
  
  StaticJsonBuffer<300> JSON;
  JsonObject& JSONencoder = JSON.createObject();

  if (millis() - lastMillis > 1500) {
    digitalWrite(green, LOW);
    digitalWrite(blue, LOW);
    digitalWrite(red, LOW);
    if (!client.connected()) {
      digitalWrite(red, HIGH);
      if (y == 5) {

        //Serial.println("Reboot System Now....");
        ESP.restart();
        y = 0;
      }
      y++;
      connect();
    }

    if (Ethernet.linkStatus() == LinkON) {
      // Serial.println("On");
      digitalWrite(green, HIGH);
    }
    else {
      digitalWrite(red, HIGH);

      if (x == 5) {
        //Serial.println("Reboot System Now....");
        ESP.restart();
        x = 0;
      }
      x++;
    }
    lastMillis = millis();
    //Serial.println(Ethernet.maintain ());

    JSONencoder["DEVICE = "] = deviceId;
    JSONencoder["USER = "]   = mqttUser;
    JSONencoder["TEMP = "]   = dht.readTemperature();
    JSONencoder["HUMD = "]   = dht.readHumidity();
    JSONencoder["STATE = "]  = true;

    char JSONmessageBuffer[100];
    JSONencoder.printTo(JSONmessageBuffer, sizeof(JSONmessageBuffer));

    client.publish("esp/data1", JSONmessageBuffer);
  }
}
2
What you need is to read the example that come with the MQTT library to understand how to use the library properly. There is a reason why publish and subscribe should only done within the connect() function only when if(client.connect()) is true. ESP.restart() should never be considered as a solution, a good IoT system can run for years without reset.hcheung

2 Answers

2
votes

It would be helpful to have the output of device from the moment it reboots - this might describe what caused it.

Without that, the best guess is that you're depleting the RAM. To check for this, you should periodically print out the available heap space (the FreeRTOS function to do it is xPortGetFreeHeapSize()).

I notice that with each iteration of loop() you do things which should be done only once - the calls to subscribe() and onMessage() are very likely not needed every time you want to publish data, and they likely allocate new heap memory to store the relevant context.

0
votes

My bet is that you are restarting the device too much. You need to implement different failure modes and different fail-safes than restarting the device on each issue. Likely the device is in a funny state while restart is triggered and then using the device after restart might not behave the way the drivers expect from the device and get stuck.

And I would also remove the comments with the printf and replace it with a #ifdef then having #define VERBOSE_DEBUG_PRINT so you can enable/disable the debugging quickly.

Another thing I would do is add to the loop this:

Serial.println(ESP.getFreeHeap());

If this is changing between the iterations of the loop, then that is not a good sign and something might be leftover.

I would go over the MQTT library documentation and examples as you might be abusing the library and calling things more frequently or in unexpected places as it was intended. And there might be side effect that I might work most of the times but once in a while either leak a bit of a heap, or get stuck.

You are asking about other projects being able to run without crashes, then look at them and how they are using the MQTT. My guess is that they do not restart device in so many branches and do calls like subscribe in a specific place (like inside the connect, but not inside the main loop). Likely you might be subscribing too much and leaking the memory.

Is 500ms delay for reconection good enough, doesn't it leave the device sometimes in a funny state, it might have be a race condition which happens only sometimes, would increase existing delays by 4x (like 500 to 2000) and add new delays in some places just in case the device expects sometime after the command, and was not expecting to be used in such way like its here (stuff in the loop etc...)