ArduinoMqttClient issue

Hello.

I am using a Raspberry Pi 4 to install an MQTT broker so that I can send messages to it from an ESP01 device.
I have setup the broker correctly and I'm also able to subscribe to the topic (from within the Raspberry itself) successfully, using the mosquitto_sub application . I can publish messages, also from the Raspberry by using mosquitto_pub and I see them on the subscriber.

On the ESP01, I am using the library ArduinoMqttClient and I could connect to the broker and send 2 messages and get them on the subsctiber, but then, in the broker logs, I see the ESP01 client simply disconnects and no more messages are seen in the subscriber.

This is the subscriber:

ubuntu@ubuntu:~$ sudo mosquitto_sub -h 127.0.0.1 -p 58999 -t "CCS811/test"
hello 0
hello 1
^Cubuntu@ubuntu:~$ mosquitto_sub -h 127.0.0.1 -p 58999 -t "CCS811/test"
CCS881 testing message
CCS881 testing message 1
CCS881 testing message 2
CCS881 testing message 3

The first 2 Hello messages were sent from the ESP01 device. The other ones were sent from the Raspberry Pi 4 itself using:

ubuntu@ubuntu:~$ mosquitto_pub -d -h 127.0.0.1 -p 58999 -t "CCS811/test" -m "CCS
881 testing message"
Client mosq-oN5sPpVtULNAnxmy3Z sending CONNECT
Client mosq-oN5sPpVtULNAnxmy3Z received CONNACK (0)
Client mosq-oN5sPpVtULNAnxmy3Z sending PUBLISH (d0, q0, r0, m1, 'CCS811/test', ... (22 bytes))
Client mosq-oN5sPpVtULNAnxmy3Z sending DISCONNECT
ubuntu@ubuntu:~$ mosquitto_pub -d -h 127.0.0.1 -p 58999 -t "CCS811/test" -m "CCS881 testing message 1"
Client mosq-Qu4Y9VG3KnEvilLVkG sending CONNECT
Client mosq-Qu4Y9VG3KnEvilLVkG received CONNACK (0)
Client mosq-Qu4Y9VG3KnEvilLVkG sending PUBLISH (d0, q0, r0, m1, 'CCS811/test', ... (24 bytes))
Client mosq-Qu4Y9VG3KnEvilLVkG sending DISCONNECT
ubuntu@ubuntu:~$ mosquitto_pub -d -h 127.0.0.1 -p 58999 -t "CCS811/test" -m "CCS881 testing message 2"
Client mosq-Co0e2NeBcC3y3NYBbP sending CONNECT
Client mosq-Co0e2NeBcC3y3NYBbP received CONNACK (0)
Client mosq-Co0e2NeBcC3y3NYBbP sending PUBLISH (d0, q0, r0, m1, 'CCS811/test', ... (24 bytes))
Client mosq-Co0e2NeBcC3y3NYBbP sending DISCONNECT
ubuntu@ubuntu:~$ mosquitto_pub -d -h 127.0.0.1 -p 58999 -t "CCS811/test" -m "CCS881 testing message 3"
Client mosq-evJAJMTRE1c9xWlgzI sending CONNECT
Client mosq-evJAJMTRE1c9xWlgzI received CONNACK (0)
Client mosq-evJAJMTRE1c9xWlgzI sending PUBLISH (d0, q0, r0, m1, 'CCS811/test', ... (24 bytes))
Client mosq-evJAJMTRE1c9xWlgzI sending DISCONNECT
ubuntu@ubuntu:~$

In the mosquitto logs I see the following:

1663853975: New connection from 127.0.0.1 on port 58999.
1663853975: New client connected from 127.0.0.1 as mosq-sGpmPzl2otVMREzWnH (p2,                                                                                                              c1, k60).
1663854348: New connection from 192.168.1.128 on port 58999.
1663854348: New client connected from 192.168.1.128 as Arduino-00005284 (p2, c1,                                                                                                              k60).
1663854441: Client Arduino-00005284 has exceeded timeout, disconnecting.
1663854640: Client mosq-sGpmPzl2otVMREzWnH disconnected.

So, the 192.168.1.128 is the ESP01 device and it ends up disconnecting.
I am using the basic example from Arduino IDE examples and only changed needed configuration parameters.
In the loop function, there is a call to a poll() function to, supposedly keep the connection alive and be able to communicate with the broker, but somehow the connection seems to drop and no more messages are seen in the subscriber!

Any help would be appreciated!
Psy

Please post a sketch that illustrates the problem although the problem may, of course, be hardware related

I have never used the library that you are using but have had good success with the PubSubClient library should the problem turn out to be software related

Hi, thanks for replying.

The sketch is literally the one from Examples -> Arduino MqttClient -> WiFiSimpleSender

And here it is:

/*
  ArduinoMqttClient - WiFi Simple Sender
  This example connects to a MQTT broker and publishes a message to
  a topic once a second.
  The circuit:
  - Arduino MKR 1000, MKR 1010 or Uno WiFi Rev2 board
  This example code is in the public domain.
*/

#include <ArduinoMqttClient.h>
#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_AVR_UNO_WIFI_REV2)
  #include <WiFiNINA.h>
#elif defined(ARDUINO_SAMD_MKR1000)
  #include <WiFi101.h>
#elif defined(ARDUINO_ARCH_ESP8266)
  #include <ESP8266WiFi.h>
#elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_ARCH_ESP32)
  #include <WiFi.h>
#endif

#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;    // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

// To connect with SSL/TLS:
// 1) Change WiFiClient to WiFiSSLClient.
// 2) Change port value from 1883 to 8883.
// 3) Change broker value to a server with a known SSL/TLS root certificate
//    flashed in the WiFi module.

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char broker[] = "192.168.1.157";
int        port     = 58999;
const char topic[]  = "CCS811/test";

const long interval = 1000;
unsigned long previousMillis = 0;

int count = 0;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // attempt to connect to WiFi network:
  Serial.print("Attempting to connect to WPA SSID: ");
  Serial.println(ssid);
  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    // failed, retry
    Serial.print(".");
    delay(20000);
  }

  Serial.println("You're connected to the network");
  Serial.println();

  // You can provide a unique client ID, if not set the library uses Arduino-millis()
  // Each client must have a unique client ID
  // mqttClient.setId("clientId");

  // You can provide a username and password for authentication
  // mqttClient.setUsernamePassword("username", "password");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }

  Serial.println("You're connected to the MQTT broker!");
  Serial.println();
}

void loop() {
  // call poll() regularly to allow the library to send MQTT keep alives which
  // avoids being disconnected by the broker
  mqttClient.poll();

  // to avoid having delays in loop, we'll use the strategy from BlinkWithoutDelay
  // see: File -> Examples -> 02.Digital -> BlinkWithoutDelay for more info
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time a message was sent
    previousMillis = currentMillis;

    Serial.print("Sending message to topic: ");
    Serial.println(topic);
    Serial.print("hello ");
    Serial.println(count);

    // send message, the Print interface can be used to set the message contents
    mqttClient.beginMessage(topic);
    mqttClient.print("hello ");
    mqttClient.print(count);
    mqttClient.endMessage();

    Serial.println();

    count++;
  }
}

Well, I just changed to the pubsubclient library and the basic code worked like a charm. However, it seems to have a drawback regarding to the loop() function. It seems it blocks the loop() function. Is that it?

I tried this other sketch named mqtt_reconnect_nonblocking.ino but with this code, I can't even see where to put the WiFi credentials. It also asks for the mac addr of the WiFi hardware. But which one? My local WiFi or my ESP Mac Addr?
Nonetheless, it doesn't work.

I'm not sure this is supposed to be changed to fit the ESP8266 chip or if it was supposed to work out of the box. I guess I have to adapt the working code to this one so that the loop() function isn't blocked, because I'm going to need to do other stuff in the loop() function!

You mean your code, that we have not seen, blocks the loop() function. Please post your sketch, using code tags when you do

No, I mean that the library itself has an example for non-blocking the loop() function. At least is what I understand from what is written in the comments here.

I'm now trying to adapt / merge the 2 codes to see if I can get it working.
I mean this code and this code.

I didn't understood for sure what gets locked / blocked. I'm assuming it's the loop() function, but would need clarification though!

Written properly the sketch should not block the free running of loop() unless something very odd is going on

Did you check the code line I mentioned above? This is a comment of the library itself. And there is a non-blocking version / example. So, I assume this is something expected.

Regarding posting the code - the code is exactly the same as the examples but the IP of the server and port where the daemon is listening!

Which example exactly ?

The non blocking example relates to not blocking whilst reconnecting following a disconnection from the broker so you need to investigate why the disconnection is occurring

I have run an MQTT broker on a Pi in the past and I am not aware of any disconnection problems

This example.

I mentioned it here in post #4 already.

What I'm still not absolutely clarified is what gets blocked! I mean, if I have other code running inside the loop() function, will that code run freely ?

What blocks when a reconnection occurs is the while loop that does not exit until the WiFi is connected

From the ESP8266 example

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str()))
    {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

Whereas the non blocking version does this

boolean reconnect() {
  if (client.connect("arduinoClient")) {
    // Once connected, publish an announcement...
    client.publish("outTopic","hello world");
    // ... and resubscribe
    client.subscribe("inTopic");
  }
  return client.connected();
}

so does not block the free running of loop() and returns true if a connection is made

However, that has other implications because it is a waste of time attempting to communicate with the broker if you are not connected

As I believe I said earlier, the blocking is not the fault of the sketch, rather it is the fact that a disconnection occurs

1 Like

Wait.
Let's take a step back.
The disconnecting behaviour I started this topic with was related to the ArduinoMqttClient library.

At some point of this thread, I quit using this library and started to use the pubsubclient.
From this point on, I don't have that disconnecting problem anymore.

If I use the basic example code specific to the ESP8266, the thing works fine.
But then, I tried to use the non-blocking code to see if there was any difference. And at this point, I adapted the non-blocking example to work with the ESP8266 and I can't make it to reconnect, for some reason I can't figure out.

I'll leave here the exact code I'm using, which is already a merge between the ESP8266 basic example and the non-blocking code.

/*
 Reconnecting MQTT example - non-blocking

 This sketch demonstrates how to keep the client connected
 using a non-blocking reconnect function. If the client loses
 its connection, it attempts to reconnect every 5 seconds
 without blocking the main loop.

*/

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

#define MSG_BUFFER_SIZE 50

const char* ssid = "xxxxxxxxxx";
const char* passwd = "xxxxxxxxxx";
const char* mqtt_server = "192.168.1.157";

WiFiClient espClient;
PubSubClient client(espClient);

char msg[MSG_BUFFER_SIZE];
int value = 0;
long lastReconnectAttempt = 0;

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to: ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, passwd);

  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 callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
  Serial.print("Message arrived [");
  Serial.println(topic);
  Serial.print("] ");
  for(unsigned int i = 0; i < length; i++)
    Serial.print((char) payload[i]);
  Serial.println();
}

boolean reconnect() {
  String clientID = "ESP01_1m_client-";
  clientID += String(random(0xffff), HEX);
  Serial.print("Attempting to connect ");
  Serial.print( clientID.c_str() );
  Serial.println( " to the MQTT broker!" );
  if ( client.connect( clientID.c_str()) ) {
    Serial.println("Here");
    Serial.print(clientID.c_str());
    Serial.println(" connected!");
    // Once connected, publish an announcement...
    client.publish("CCS811/test", "hello from pubsubclient");
    // ... and resubscribe
    // client.subscribe("CCS811/test");
  }
  return client.connected();
}

void setup() {
  delay(20000);
  Serial.begin(115200);
  Serial.println("Serial Started!");
  client.setServer(mqtt_server, 58999);
  Serial.println("MQTT broker!");
  client.setCallback(callback);
  delay(1500);
  lastReconnectAttempt = 0;
}


void loop() {
  if (!client.connected()) {
    long now = millis();
    if (now - lastReconnectAttempt > 5000) {
      lastReconnectAttempt = now;
      // Attempt to reconnect
      if (reconnect()) {
        lastReconnectAttempt = 0;
      }
    }
  } else {
    // Client connected
    client.loop();
  }

}

What I did was just start with the non-blocking code, remove the Ethernet connection part and add the WiFi connection part from the basic example code for the ESP8266.

However, the output is always:

Serial Started!
MQTT broker!
Attempting to connect ESP01_1m_client-e5d5 to the MQTT broker!
Attempting to connect ESP01_1m_client-ddb9 to the MQTT broker!
Attempting to connect ESP01_1m_client-8fbb to the MQTT broker!
Attempting to connect ESP01_1m_client-a555 to the MQTT broker!

I use ESP32's and freeRTOS to get around the client.loop() being a blocking function. The only thing is publishing a payload must not occur during client.loop so I use a semaphore. I found the 'slowest'

Another setting I make is MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made. with PubSubClient. The setting must be made before the 1st client connection.

1 Like

Hum, ok. So, If I understand correctly, this is just a problem if, for some reason, the WiFi connection fails too many times, yes? Other than that, the basic code should work with no problems, right? Or am I wrong? I don't want to complicate things. If I assume the WiFi connection is stable and mostly on, then, the reconnecting procedure won't be a problem, and I'll be able to run any other code I have in the loop() function.

Please correct me if I'm wrong!

Your summary sounds about right

1 Like

I found that WiFi may not be as stable a connection as is thought.

Here is my mqtt keep alive, mqtt connect, and WiFI connect code.

void MQTTkeepalive( void *pvParameters )
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  // 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 MQTTlient.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 ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 250 ); //task runs approx every 250 mS
  }
  vTaskDelete ( NULL );
}
////
void connectToWiFi()
{
  int TryCount = 0;
  while ( WiFi.status() != WL_CONNECTED )
  {
    TryCount++;
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    vTaskDelay( 4000 );
    if ( TryCount == 10 )
    {
      ESP.restart();
    }
  }
  WiFi.onEvent( WiFiEvent );
} // void connectToWiFi()
////
void connectToMQTT()
{
  MQTTclient.setKeepAlive( 90 ); // needs be made before connecting
  byte mac[5];
  WiFi.macAddress(mac);
  String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
  while ( !MQTTclient.connected() )
  {
    // boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
    MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password, NULL , 1, true, NULL );
    vTaskDelay( 250 );
  }
  MQTTclient.setCallback( mqttCallback );
  MQTTclient.subscribe( topicOK );
} // void connectToMQTT()

Notice I check to see if the WiFi is connected before trying to client.loop()?

I also use a MQTT watchdog routine to keep track of MQTT broker responses. If the thinges are connected to the Broker and the Broker is reset the thignes keep on trying to connect to the broker using the old security token.

Any other code can be run in the loop() function.

Notice I issue a WiFI disconnect before connection? The disconnect reset the WiFi stack, the most common WiFI issue with small micro-controllers.

1 Like

Is that from PubSubclient library?

Yes

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