ESP32 - Reboot on MQTT Callback

Hi everybody!

I hope you can help me.
I have an ESP32 set up with following functionality:

  • 3 RFID Readers
  • OTA Update
  • MQTT outbound Connection - whenever a new RFID chip is recognized, send an MQTT.
  • MQTT inbound Connection - whenever a message is sent to the topic the ESP subscribed to, it should forget its last RFID chip read, ergo reset.

This reset is necessary as the RFID Module resends the same chip id indefinitely in certain circumstances.

My Problem is: Every time the MQTT Callback method is called, the esp resets with following error message and i don't understand why AT ALL:

11:14:50.560 -> Backtrace: 0x53616863:0x3ffbe160 0x4008a590:0x3ffbe180 0x40088e8b:0x3ffbe1a0 0x4008b5a1:0x3ffbe1c0 0x4008499a:0x3ffbe1d0 0x401487db:0x3ffbbff0 0x400d9d4f:0x3ffbc010 0x4008a581:0x3ffbc030 0x40088d9d:0x3ffbc050
11:14:50.596 -> 
11:14:50.596 -> 
11:14:50.596 -> Backtrace: 0x00000000:0x00000000
11:14:50.596 -> 
11:14:50.596 -> Rebooting...
11:14:50.596 -> ets Jun  8 2016 00:22:57
11:14:50.596 -> 
11:14:50.596 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
11:14:50.596 -> configsip: 0, SPIWP:0xee
11:14:50.596 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
11:14:50.596 -> mode:DIO, clock div:1
11:14:50.632 -> load:0x3fff0018,len:4
11:14:50.632 -> load:0x3fff001c,len:1044
11:14:50.632 -> load:0x40078000,len:8896
11:14:50.632 -> load:0x40080400,len:5816
11:14:50.632 -> entry 0x400806ac

This is the code i use. In the MQTT Callback all relevant code for resetting the RFID is commented out, as it doesn't matter if its active or not, it will reboot - and a reboot solves the problem somehow :wink:

/* to use this



  install esp32 to use with arduino ide:
  preferences > https://dl.espressif.com/dl/package_esp32_index.json > boards manager > esp32 by espressif
  select board: esp32 dev module and set "flash mode" to "DIO"

  install ESPSoftwareSerial in library-manager



*/
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoOTA.h>
#include <Wire.h>  // This library is already built in to the Arduino IDE

#include <HardwareSerial.h>
#include <SoftwareSerial.h>

char tagNumber1[14];
char tagNumber2[14];
char tagNumber3[14];
SoftwareSerial Serial3;

// Update these with values suitable for your network.
const char* ssid = "xxxxxxxxx";//put your own wifi ssid here
const char* password = "xxxxxxxx";// put your wifi password here
const char* mqtt_server = "192.168.0.xx";
const char* topic = "RFID1";
const char* topic1 = "RFID1_1";
const char* topic2 = "RFID1_2";
const char* topic3 = "RFID1_3";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

String tagString1;
String tagString2;
String tagString3;

String tagString1_old;
String tagString2_old;
String tagString3_old;
boolean receivedTag1;
boolean receivedTag2;
boolean receivedTag3;

int rfidNR = 0;

void callback(char* topic, byte* payload, unsigned int length)
{
  //int cmd = String((char*)payload).substring(0, 1).toInt();

  //Serial.print(" => ");
  //String myTopic = String(topic);

  client.publish(topic, "i get a message");
  /*if (myTopic == topic)
    {

    //Serial.println(myMessage);

    if (cmd == 1)
    {
      tagString1_old = "resettet";
      tagString2_old = "resettet";
      tagString3_old = "resettet";
      client.publish(topic, "resettet");
    }

    }*/
} //end callback

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600, SERIAL_8N1, 14, 27);
  Serial2.begin(9600, SERIAL_8N1, 26, 25);
  Serial3.begin(9600, 33, 32, SWSERIAL_8N1, false, 95, 11);

  setup_wifi();
  client.setServer(mqtt_server, 1883);

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  ArduinoOTA.handle();

  if (!client.connected()) {
    reconnect();
  }

  client.setCallback(callback);
  client.loop();

  receivedTag1 = false;
  receivedTag2 = false;
  receivedTag3 = false;

  while (Serial1.available()) {
    int BytesRead = Serial1.readBytesUntil(3, tagNumber1, 15);//EOT (3) is the last character in tag
    Serial.println("1er Reader");
    Serial.println(tagNumber1);
    receivedTag1 = true;
    tagString1 = tagNumber1;
  }

  while (Serial2.available()) {
    int BytesRead = Serial2.readBytesUntil(3, tagNumber2, 15);//EOT (3) is the last character in tag
    Serial.println("2er Reader");
    Serial.println(tagNumber2);

    receivedTag2 = true;
    tagString2 = tagNumber2;
  }

  while (Serial3.available()) {
    int BytesRead = Serial3.readBytesUntil(3, tagNumber3, 15);//EOT (3) is the last character in tag
    Serial.println("3er Reader");
    Serial.println(tagNumber3);

    receivedTag3 = true;
    tagString3 = tagNumber3;
  }

  if (receivedTag1) {

    Serial.println();
    Serial.print("Tag Number: ");


    if (tagString1_old != tagString1) {
      client.publish(topic1, tagNumber1);
      Serial.println(tagString1);
      tagString1_old = tagString1;
    }
  }
  if (receivedTag2) {

    Serial.println();
    Serial.print("Tag Number: ");

    if (tagString2_old != tagString2) {
      client.publish(topic2, tagNumber2);
      Serial.println(tagString2);
      tagString2_old = tagString2;
    }
  }
  if (receivedTag3) {

    Serial.println();
    Serial.print("Tag Number: ");

    if (tagString3_old != tagString3) {
      client.publish(topic3, tagNumber3);
      Serial.println(tagString3);
      tagString3_old = tagString3;
    }
  }

  rfidNR = 0;

  //wait(1500); // a delay of 1500ms and a flush() seems to stop tag repeats
  //Serial1.flush();
  //Serial2.flush();
  //Serial3.flush();

  memset(tagNumber1, 0, sizeof(tagNumber1)); //erase tagNumber
  memset(tagNumber2, 0, sizeof(tagNumber2)); //erase tagNumber
  memset(tagNumber3, 0, sizeof(tagNumber3)); //erase tagNumber



}

void setup_wifi() {
  delay(100);
  // We start by connecting to a WiFi network
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    //String clientId = topic;
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect

    char buffer [50];
    sprintf(buffer, "%s is OFFLINE", topic);

    if (client.connect(clientId.c_str(), "Healthcheck", 1, true, buffer))
    {
      Serial.println("connected");
      //once connected to MQTT broker, subscribe command if any
      client.subscribe(topic);
      char buffer2 [16];
      WiFi.localIP().toString().toCharArray(buffer2, 16);
      sprintf(buffer, "%s: %s", buffer2, topic);
      client.publish("Healthcheck", buffer);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 6 seconds before retrying

      delay(6000);
    }
  }
} //end reconnect()

I'm at the end of my witt. If i remove all code in the callback method and just leave a Serial.println it appears that the method is called multiple times.

The whole code for OTA and MQTT is used with around 30 other modules on ESP32 and ESP8266 and works perfectly there, switching relays, lamps, connecting buttons, whatever.

Your help is highly appreciated,
Thank you!

Reported to moderator as follows :

Reported by genotix on Today at 21:08:04. They left the following message:

Since the person on this topic is using a long delay the FreeRTOS in the background doesn't get enough attention.

Using the mqtt.loop(); function frequently makes that this issue is avoided.

Instead of a delay() a special wait function should be used:

#include <SoftwareSerial.h> ,,,--- does not play nicely with a ESP32,

Before making a WIFI connection issue a WiFI disconnect. WiFI disconnect does 2 things. If connected, disconnect and MOST IMPORANTLY, the WiFi stack space is reset to all default values.

Use
void IRAM_ATTR callback(char* topic, byte* payload, unsigned int length) for a performance increase.

Really, serial prints in a callback routine?
An example of the MQTT callback.

void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
  xSemaphoreTake( sema_MQTT_Parser, portMAX_DELAY);
  str_eTopic = topic;
  int i = 0;
  for ( i; i < length; i++)
  {
    strPayload[i] = ((char)payload[i]);
  }
  strPayload[i] = NULL;
  //log_i( "topic %s payload %s" ,str_eTopicPtr, strPayloadPtr );
  xSemaphoreGive ( sema_MQTT_Parser );
  xEventGroupSetBits( eg, evtParseMQTT ); // trigger tasks
} // void mqttCallback(char* topic, byte* payload, unsigned int length)

Minimal work is done in the callback, the package is received and sent to a parser, running in another task.

I run the MQTT keep alive in its own task space

/*
    Important to not set vTaskDelay to less then 10. Errors begin to develop with the MQTT and network connection.
    makes the initial wifi/mqtt connection and works to keeps those connections open.
*/
void MQTTkeepalive( void *pvParameters )
{
  // setting must be set before a mqtt connection is made
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  for (;;)
  {
    //check for a is connected and if the WiFi thinks its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 250 ); //task runs approx every 250 mS
  }
  vTaskDelete ( NULL );
}
////

That client.loop() code makes a connection if not already made and keeps the connection open.

Install the ESP EXCEPTION Decoder. put your debug message into the decoder and lets see what the not about.

make a new tab, call it certs.h or bleep.h or what.h then put this stuff

// Update these with values suitable for your network.
const char* ssid = "xxxxxxxxx";//put your own wifi ssid here
const char* password = "xxxxxxxx";// put your wifi password here
const char* mqtt_server = "192.168.0.xx";
const char* topic = "RFID1";
const char* topic1 = "RFID1_1";
const char* topic2 = "RFID1_2";
const char* topic3 = "RFID1_3";

in the what ever you called it tab.

Include the file into your project and now your secret info in on a different page, Now you won't need to edit your thing before posting the thing.

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