MQTT disconnects - Tried keepalive but no go. ESP8266 Board

Hi,

It looks like you are using the ESP8266 pub-sub client library. If so, you can call the loop() function as described at https://pubsubclient.knolleary.net/api.html if you don’t want to disconnect. Here is the description of that function:

boolean loop ()
This should be called regularly to allow the client to process incoming messages and maintain its connection to the server.
Returns:

  • false - the client is no longer connected
  • true - the client is still connected
2 Likes

What @old_fogey said - I had the exact same issues until I figured out that you need to allow some time for the PubSubClient library to do its own processing (including sending keepalives to the server).

So make sure that you call the mqtt loop() regularly. And also include a delay() in your Arduino loop() function - this allows the ESP SDK to perform its own processing (including network processing).

Thanks @old_fogey and @bogd

I did notice that send messages in MQTT kept those messages down, but not fully. I was sending “off” messages to my MQTT server once ever 2 seconds but was still getting disconnects.

My quesiton now is, although I’m not using loop() I am using the following

void loop(){
    Serial.println("Entering loop()");
// First make sure MQTT is connected 
  {
  if (!client.connected()) {
    reconnect();           }
  }  //Close If

Wouldn’t that accomplish the same?

No, it does not accomplish the same.

Your (Arduino) loop() just loops as quickly as it can, unless your MQTT client is disconnected. So while the client is still connected, the loop() just… loops very quickly, prints to the serial, and loops again. As a result, the MQTT client does not get a chance to send its keepalives, and the ESP does not get a chance to do its housekeeping.

As mentioned before, you should add two things:
a) a client.loop() call for the MQTT client
b) a delay(500) (or 100, or whatever suits your application) for the ESP

[ Edited to add: also, what’s with the extra braces in your code? You have one set of {} that seem to serve no purpose… ]

Thanks @bogd

it did seem that just publishing a message in every loop() seemed to keep MQTT stable. Maybe just that few extra 100th of a second made the different? But I noticed it would go minutes between those connecting messages.

Now, with the client.loop() in there, it’s working perfect (alongside a delay)

Thanks a bunch!

I think that it was more stable when sending messages because there was actually some communication between your client and the MQTT broker, and that prevented the broker from declaring the connection lost.

Either way, glad to hear that it is working now!

Hi !

I am srtuggeling with the same issue. I am not sure, where to insert the client.loop.
Can you please help?

Here is my code:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define LISTEN_PORT 80

//Pins
int relay_pin1 = 12;
int temp_pin1 = A0;

// WIFI
const char* ssid = “SSID”;
const char* password = “WIFI password”;

//MQTT
const char* mqtt_server = “servers IP”;
const int mqttPort = 1883;
const char* mqttUser = “user”;
const char* mqttPassword = “password”;

WiFiClient espClient;
PubSubClient client(espClient);
WiFiServer server(LISTEN_PORT);

void callback(char* topic, byte* payload, unsigned int length) {
Serial.print(“Message arrived [”);
Serial.print(topic);
Serial.print("] ");
for (int i=0;i<length;i++) {
char receivedChar = (char)payload[i];
Serial.print(receivedChar);
}
Serial.println();
}

//RECONNECT
void reconnect() {
// Loop until we’re reconnected
while (!client.connected()) {
Serial.print(“Attempting MQTT connection…”);
// Attempt to connect
if (client.connect(“AKAC_ESP8266_1”, mqttUser, mqttPassword, “AKAC/ESP8266_1/Status”, 2, 1,“OFFLINE” )) {
Serial.println(“connected”);
// … and subscribe to topic
client.subscribe(“X”);
} else {

//RC descriptions

//-4 : MQTT_CONNECTION_TIMEOUT - the server didn’t respond within the keepalive time
//-3 : MQTT_CONNECTION_LOST - the network connection was broken
//-2 : MQTT_CONNECT_FAILED - the network connection failed
//-1 : MQTT_DISCONNECTED - the client is disconnected cleanly
//0 : MQTT_CONNECTED - the client is connected
//1 : MQTT_CONNECT_BAD_PROTOCOL - the server doesn’t support the requested version of MQTT
//2 : MQTT_CONNECT_BAD_CLIENT_ID - the server rejected the client identifier
//3 : MQTT_CONNECT_UNAVAILABLE - the server was unable to accept the connection
//4 : MQTT_CONNECT_BAD_CREDENTIALS - the username/password were rejected
//5 : MQTT_CONNECT_UNAUTHORIZED - the client was not authorized to connect

Serial.print(“failed, rc=”);
Serial.print(client.state());
if (client.state() == -4){Serial.print (“MQTT_CONNECTION_TIMEOUT - the server didn’t respond within the keepalive time”);}
if (client.state() == -3){Serial.print (“MQTT_CONNECTION_LOST - the network connection was broken”);}
if (client.state() == -2){Serial.print (“MQTT_CONNECT_FAILED - the network connection failed”);}
if (client.state() == -1){Serial.print (“MQTT_DISCONNECTED - the client is disconnected cleanly”);}
if (client.state() == 0){Serial.print (“MQTT_CONNECTED - the client is connected”);}
if (client.state() == 1){Serial.print (“MQTT_CONNECT_BAD_PROTOCOL - the server doesn’t support the requested version of MQTT”);}
if (client.state() == 2){Serial.print (“MQTT_CONNECT_BAD_CLIENT_ID - the server rejected the client identifier”);}
if (client.state() == 3){Serial.print (“MQTT_CONNECT_UNAVAILABLE - the server was unable to accept the connection”);}
if (client.state() == 4){Serial.print (“MQTT_CONNECT_BAD_CREDENTIALS - the username/password were rejected”);}
if (client.state() == 4){Serial.print (“MQTT_CONNECT_UNAUTHORIZED - the client was not authorized to connect”);}

Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}

//SETUP
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
client.setServer(mqtt_server, mqttPort);
client.setCallback(callback);

//PINMODES
pinMode(relay_pin1, OUTPUT);
pinMode(temp_pin1, INPUT);

}

//LOOP
void loop() {
// put your main code here, to run repeatedly:
if (!client.connected()) {
reconnect();
}
client.loop();
client.publish(“X”, “online”);
delay(1000);
}

Your client.loop() seems to be in the right place (so that shouldn’t be the problem). The other thing to check is that your mqtt.client name is unique on your network as it will disconnect each time it loops if a different device has the same name.

In your sample code AKAC_ESP8266_1 must be unique.

You mean, there should be not other device connected, or trying to connect with the same client ID?

That is not the case, there is only one client named “AKAC_ESP8266_1” in my system. Every other client has his own unique name, client ID.

However they all login with the same user/pass to the broker, but that should be no problem I guess.

First of all most of the problems with mqtt disconnecting is because bugged esp core. Simply not working good with some wifi chips. The most stable are Core 2.3 and the newest, prerelease 2.6.x. Forget about core 2.4 and 2.5…

Hi guys.
I have the same connection problem, identical to you. What changes is that I use the Arduino Mega with an ENC28j60 ethernet board. I actually use two Arduino Mega boards each with the ENC28j60 ethernet. The two have practically the same Scheduler, carrying one of them after a few touches on the switches or using the HA for some command disconnects, the other card is stable and working perfectly. I have already changed the plates, I have rewritten the codes, I have left only one connection on the network, I have done the cabling inspection, replaced the number of IPs and there is no way to be revolved. Follow my schedule, if anyone can help me. And I use a different name for each board.

#include <PubSubClient.h>
#include <UIPEthernet.h>

byte mac[] = {0x80, 0x7D, 0x3A, 0x69, 0x20, 0xC8 }; //physical mac address
byte ip[] = {192, 168, 0, 202 }; // ip in lan

int botao[] =                    {      11,              12,                10,                 9,              8,                7,            6,                 5,             4,              3,              27,               14,              17,              16,              15,             18,           22,              21,                20,            19,             23,               26,               25,           24        };//PORTAS DOS INTERRUPTORES
int rele[] =                     {      A11,             A10,               A12,               A13,            A14,              A15,           A6,               A5,             A4,             A3,             49,               48,              45,              46,              47,             44,           40,              41,                42,            43,             39,               36,               37,           38        }; //PORTAS DOS RELES
const char* TOPIC_PUBLISH [] =   {"ha/v_principal","ha/v_cabeceira",  "ha/v_acessoria", "ha/c_principal", "ha/c_acessoria", "ha/c_parede", "ha/q_principal", "ha/q_parede", "ha/q_entrada", "ha/q_esquerda", "ha/q_direita", "ha/q_arandela", "ha/m_principal", "ha/m_acessoria", "ha/m_parede", "ha/m_sacada", "ha/lustre", "ha/jantar_indireta", "ha/s_indireta", "ha/mezanino", "ha/v_sacada", "ha/porta_arandela", "ha/calcada", "ha/j_frente"  };
String strTopic []=              {"ha/v_principal","ha/v_cabeceira",  "ha/v_acessoria", "ha/c_principal", "ha/c_acessoria", "ha/c_parede", "ha/q_principal", "ha/q_parede", "ha/q_entrada", "ha/q_esquerda", "ha/q_direita", "ha/q_arandela", "ha/m_principal", "ha/m_acessoria", "ha/m_parede", "ha/m_sacada", "ha/lustre", "ha/jantar_indireta", "ha/s_indireta", "ha/mezanino", "ha/v_sacada", "ha/porta_arandela", "ha/calcada", "ha/j_frente"  };
String Switch[] =                {  "v_principal" ,  "v_cabeceira" ,   "v_acessoria"  ,  "c_principal"  ,   "c_acessoria" ,   "c_parede" ,  "q_principal"  ,  "q_parede"  ,   "q_entrada" ,   "q_esquerda" ,  "q_direita"  ,   "q_arandela" ,   "m_principal" ,   "m_acessoria" ,   "m_parede" ,   "m_sacada" ,   "lustre" ,   "j_indireta"      ,   "s_indireta" ,   "mezanino" ,  "v_sacada"  ,   "porta_arandela" ,  "calcada"  ,   "j_frente"   };
boolean statusrele[] =           {        1,              2,                3,                  4,              5,                 6,            7,                8,             9,              10,             11,                12,              13,              14,             15,              16,          17,              18,                 19,            20,             21,              22,               23,           24,       };
static unsigned long debounceInterruptor[]={1,            2,                3,                  4,              5,                 6,            7,                8,             9,              10,             11,                12,              13,              14,             15,              16,          17,              18,                 19,            20,             21,              22,               23,           24,       };
  
int relecont = 24; // NR DE PORTAS USADAS RELES OU INTERRUPETORES PARA O INDICE (i)
int i;

const char* mqtt_server = "192.168.xxx.xxx";
const char* mqttUser = "amkoxxxxxx";
const char* mqttPassword = "xxxxxxxxx";

EthernetClient espClient;
PubSubClient client(espClient);

String strTopic1;
String strPayload;



void interruptor(int i)  // FUNCAO PARA LIGAR/DESLIGAR LAMPADAS
{
   for (int i = 0; i < relecont; i++){
   if (  (millis() - debounceInterruptor[i]) > 30 ) {
    if((digitalRead(botao[i]) == HIGH))
    {
      while(digitalRead(botao[i]) == HIGH){};
        digitalWrite(rele[i],!statusrele[i]);
        statusrele[i] = !statusrele[i];
        if (statusrele[i]==false){
        client.publish(TOPIC_PUBLISH[i], "OFF");}
         if (statusrele[i]==true){
        client.publish(TOPIC_PUBLISH[i], "ON");}
       delay(350);
    }
   }
   }
   
   }


void setup_inicio() {

 
 Serial.begin(115200);
  delay(100);
 
   Ethernet.begin(mac,ip);
}

void callback(char* topic, byte* payload, unsigned int length) {
  payload[length] = '\0';
  strTopic1 = String((char*)topic);

  for (int i = 0; i < relecont; i++) 
{
  if(strTopic1 == strTopic[i])
    {
    Switch[i] = String((char*)payload);
    if(Switch[i] == "ON")
      {statusrele[i] = true;
        Serial.println("ON");
        digitalWrite(rele[i], HIGH);
        delay(350);
      }
    else
      {statusrele[i] = false;
        Serial.println("OFF");
        digitalWrite(rele[i], LOW);
        delay(350);
      }
    }
}
}
 
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("arduinoClientSuperior",mqttUser, mqttPassword)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.subscribe("ha/#");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      
      delay(5000);
    }
    
  }
  
}
 
void setup()
{
Serial.begin(115200);
for (int i = 0; i < relecont; i++) 
{
  pinMode(rele[i],OUTPUT); //DEFINI PORTAS RELE COMO PORTA DE SAIDA
  pinMode(botao[i],INPUT); //DEFINE PORTAS DE INTERRUPTORES COMO PORTA DE ENTRADA
  digitalWrite(rele[i],HIGH); // DEFINIE ESTADO HIGH PARA PORTAS DE RELE
  statusrele[i] = true; // DEFINE O STATUS RELE COMO TRUE  
 }



 
  setup_inicio(); 
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  


}
 
void loop()
{
  if (!client.connected()) {
 
    reconnect();
  }
  
  interruptor(i);
  client.loop();


      
}

Suggest you to make your own thread @amkochaki as my thread was years ago.

1 Like

Hi @amkochaki,

which keepalive did you configure in PubSubClient?
I used it a while ago in ESP8266 and could mitigate this issue by switching to ArduinoMQTT but I think your problem is a more basic one.

Here is a list of findings regarding the posted code:

  1. You call Serial.begin() twice
  2. You use a global variable i that is not initialized.
  3. You use local scope variable i in for loops which is not a good practice.
  4. You pass global i into interruptor but for uses a local scoped i
  5. What is the purpose of the delay in interruptor?
  6. I’d avoid using delay() in the MQTT callback since it blocks MQTT loop. Also I do not see the use case for that.

Assumption:
Depending on the number of MQTT callbacks I assume that your keep alive expires.
interruptor delay() alone sums up to 8.4 seconds every loop. (relecont = 24 x 350 ms)

Recommendation:
In a first step I’d just add some timestamps to measure the time between the client.loop calls to see if this is the issues.
In a second step I’d change the code to strictly avoid the usage of delay().

P.S. I read this on my mobile so I might have missed something in the code due to the small screen.

Hi @eXtatic
Thanks for your return

I removed all the delays and left a delay (100) in the loop for, because without this the switch on the Arduino doesn’t work properly. Programming in this way worked better. I accessed the PuSubClient.h library and can see the following: #define MQTT_KEEPALIVE 15 and #define MQTT_SOCKET_TIMEOUT 15 the two items were 15 seconds old KEEPALIVE I changed to 60 and MQTT_SOCKET_TIMEOUT I put 80 for the purposes of these, it took a breather when disconnecting, I can switch on and off my lamps, but after 80 seconds the disconnection happens. What I don’t understand is that I have the same programming in another square that works perfectly, I have already tested it only with a connected board but even then disconnections occur.

I did some more tests regarding the disconnections by timeout, I put an Arduino mega Wifi and the disconnections remained the same, but I noticed some things, for example if I modify the state of the lamps in a slower way, that is, by spacing the time with each lamp that ascending the connection remains alive for longer, if I do it quickly the disconnection is instantaneous. The switches in position zero and position 17 of ARRAY [] never disconnect the board or if I can turn it off very quickly that the Arduino Mega remains connected with the broker. I tried to use the ArduinoMqtt Library but I confess that I didn’t understand them very well. I keep looking for a solution to my problem.

hello
merry Christmas
kindly asking, if you solve your problem please leave a comment on this post

hello,
have you find a solution to the problem ?
I am keep getting the following and it drives me mad.

1609092244: New client connected from 192.168.70.161 as plant-esp32 (p2, c1, k60, u'local-user').
1609092335: Client plant-esp32 has exceeded timeout, disconnecting.

Olá
Sim consegui resolver meu problema. Era a fonte de energia que alimentava. Os fios negativos da fonte do arduino deve estar ligados ao fio negativo da fonte de energia do raspberry. No meu caso isso resolveu o problema. Pelo que vi voce está usando um esp32 é wifi então nao sei comutar as fontes de energia resolveria o problema.

This really leads me to wonder how many people are here solely for plant and garden use. Im one of them! (Also have experienced a never ending headache with mqtt disconnects and reconnects lately, not sure how it went away, wish I could help.)

have you found a solution?