Arduino MQTT does not reconnect after connection loss

Hi,

I have an ESP32 logging data from my energy meter to an MQTT broker running on my Synology NAS. If I reboot my NAS or disconnect the ethernet, the ESP stop sending new data and I have to reboot the ESP to get it going again. I have programmed the onboard LED to indicate when it's sending data, and it is still flashing. I would like the ESP to resolve the connection loss automatically.

// HAN Reader/Parser for AMS meter.
// Tested on Kaifa MA105H2E
// Not tested on Kaifa 3-phase meter
//
// NodeMCU-32S
// UART2 RX = RX2, TX = TX2

#include <WiFi.h>
#include <ArduinoMqttClient.h>
#include <ArduinoJson.h>
#include <Arduino.h>
#include <ArduinoOTA.h>
#include <TON.h>
#include <AMS.h>
#include <CREDENTAILS.h>

AMS meter;

const char* ssid = WIFI_SSID;
const char* password = WIFI_PASS;
const char broker[] = "192.168.0.199";
int        port     = 1883;
WiFiClient espClient;
MqttClient mqttClient(espClient);

const char topic_AMS[]  = "AMS";

void setup()  {
  pinMode(BUILTIN_LED, OUTPUT);
  digitalWrite(BUILTIN_LED, LOW);
  Serial2.begin(2400);
  //Serial.swap(); // Use UART2 for ESP8266
  
  setup_wifi();

  setup_ota();
  
  mqttClient.connect(broker, port);
}

void setup_wifi() {

  delay(10);
  WiFi.begin(ssid, password);

  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    delay(5000);
    ESP.restart();
  }
}


void loop() {

  
  if (Serial2.available() > 0){
    uint8_t data = Serial2.read();
    uint8_t list = meter.han(data);
    if(list != 0){
      
      digitalWrite(BUILTIN_LED, HIGH);
      
      DynamicJsonDocument doc(1024);
      
      switch(list){
        case 0x1:
          doc["TS"] = meter.epoch;
          doc["ECH"] = meter.wh;
          
          doc["PAP"] = meter.powerPositiveActive;
          
          break;
                
        case 0x12:
          doc["TS"] = meter.epoch;
          doc["ECH"] = meter.wh;
          
          doc["PAP"] = meter.powerPositiveActive;
          doc["PAN"] = meter.powerNegativeActive;
          doc["PRP"] = meter.powerPositiveReactive;
          doc["PRN"] = meter.powerNegativeReactive;

          doc["L1C"] = meter.L1current;
          doc["L1V"] = meter.L1voltage;
          
          doc["OBIS"] = meter.OBIS_ver;
          doc["M_ID"] = meter.meterID;
          doc["M_Typ"] = meter.meterType;
          
          break;

        case 0x13:
          doc["TS"] = meter.epoch;
          doc["ECH"] = meter.wh;
          
          doc["PAP"] = meter.powerPositiveActive;
          doc["PAN"] = meter.powerNegativeActive;
          doc["PRP"] = meter.powerPositiveReactive;
          doc["PRN"] = meter.powerNegativeReactive;

          doc["L1C"] = meter.L1current;
          doc["L1V"] = meter.L1voltage;

          doc["EAP"] = meter.energyPositiveActive;
          doc["EAN"] = meter.energyNegativeActive;
          doc["ERP"] = meter.energyPositiveReactive;
          doc["ERN"] = meter.energyNegativeReactive;

          //doc["OBIS"] = meter.OBIS_ver;
          //doc["M_ID"] = meter.meterID;
          //doc["M_Typ"] = meter.meterType;

          break;
          
        case 0x32:

          doc["TS"] = meter.epoch;
          doc["ECH"] = meter.wh;
          
          doc["PAP"] = meter.powerPositiveActive;
          doc["PAN"] = meter.powerNegativeActive;
          doc["PRP"] = meter.powerPositiveReactive;
          doc["PRN"] = meter.powerNegativeReactive;

          doc["L1C"] = meter.L1current;
          doc["L1V"] = meter.L1voltage;
          doc["L2C"] = meter.L2current;
          doc["L2V"] = meter.L2voltage;
          doc["L3C"] = meter.L3current;
          doc["L3V"] = meter.L3voltage;

          doc["OBIS"] = meter.OBIS_ver;
          doc["M_ID"] = meter.meterID;
          doc["M_Typ"] = meter.meterType;
          
          break;

        case 0x33:

          doc["TS"] = meter.epoch;
          doc["ECH"] = meter.wh;
          
          doc["PAP"] = meter.powerPositiveActive;
          doc["PAN"] = meter.powerNegativeActive;
          doc["PRP"] = meter.powerPositiveReactive;
          doc["PRN"] = meter.powerNegativeReactive;

          doc["L1C"] = meter.L1current;
          doc["L1V"] = meter.L1voltage;
          doc["L2C"] = meter.L2current;
          doc["L2V"] = meter.L2voltage;
          doc["L3C"] = meter.L3current;
          doc["L3V"] = meter.L3voltage;

          doc["EAP"] = meter.energyPositiveActive;
          doc["EAN"] = meter.energyNegativeActive;
          doc["ERP"] = meter.energyPositiveReactive;
          doc["ERN"] = meter.energyNegativeReactive;

          //doc["OBIS"] = meter.OBIS_ver;
          //doc["M_ID"] = meter.meterID;
          //doc["M_Typ"] = meter.meterType;

          break;

        default:
          break;
      }
      
      uint8_t buff[1024];
      size_t n = serializeJson(doc, buff);

      mqttClient.beginMessage(topic_AMS);
      mqttClient.write(buff, n);
      mqttClient.endMessage();

      digitalWrite(BUILTIN_LED, LOW);
    }
  }

  ArduinoOTA.handle();
  
  mqttClient.poll();
 }


 void setup_ota(){
  ArduinoOTA.setHostname("AMS_ESP32");

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

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()

  });
  ArduinoOTA.onEnd([]() {

  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {

  });
  ArduinoOTA.onError([](ota_error_t error) {

    if (error == OTA_AUTH_ERROR) {

    } else if (error == OTA_BEGIN_ERROR) {

    } else if (error == OTA_CONNECT_ERROR) {

    } else if (error == OTA_RECEIVE_ERROR) {

    } else if (error == OTA_END_ERROR) {

    }
  });
  ArduinoOTA.begin();
  ArduinoOTA.handle();
 }

I use a different MQTT library but can you do something along these lines ?

#include <WiFi.h>
#include <credentials.h>
#include <PubSubClient.h>

WiFiClient client;
PubSubClient mqttClient(client);
const char* server = "192.168.1.112"; //Pi 4

char clientID[20];
char * reportTopic = "BBB/report";
char * requestTopic = "BBB/request";

void setup()
{
  Serial.begin(115200);
  while (!Serial) { }
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.print("MAC address: ");
  Serial.println(WiFi.macAddress());
  String mac = WiFi.macAddress();
  Serial.println(mac);
  connectWiFi();
  for (int c = 0; c < 8; c++) //create client ID
  {
    clientID[c] = random('A', 'Z' + 1);
    clientID[c + 1] = '\0';
  }
  Serial.printf("clientID : %s\n", clientID);
  connectMQTT();
}

void loop()
{
  mqttClient.loop();
  if (!mqttClient.connected())
  {
    connectMQTT();
  }
  sendMessage();
  delay(5000);
}

void connectWiFi()
{
  Serial.println("Setting up network connection");
  WiFi.begin(mySSID, myPASSWORD);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void connectMQTT()
{
  mqttClient.setServer(server, 1883);
  if (mqttClient.connect(clientID))
  {
    Serial.print("Connection has been established with ");
    Serial.println(server);
    mqttClient.subscribe(requestTopic);
  }
  else
  {
    Serial.println("The MQTT server connection failed...");
  }
  mqttClient.setCallback(callback);
}

void sendMessage()
{
  char stringOne[] = {"Hello String"};
  mqttClient.publish(reportTopic, stringOne);
  Serial.printf("publishing %s to %s\n\r", stringOne, reportTopic);
}

void callback(char* requestTopic, byte* payload, unsigned int length)
{
  char messageBuffer[30];
  memcpy(messageBuffer, payload, length);
  messageBuffer[length] = '\0';
  Serial.printf("%s\n", messageBuffer);
}

Note how the code checks whether MQTT is connected and if not how it reconnects

  if (!mqttClient.connected())
  {
    connectMQTT();
  }

I have used PubSubClient on som other projects with good results.
I wanted to test out this library because it looked like an offical Arduino library.
But you are right, I'm going back to PubSubClient.

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