Sming – MQTT (part 2)

While doing some test with MQTT using the Sming Framework for the ESP8266 I had some issues that are worthy to be documented.
The Sming Framework uses the libemqtt library for MQTT support, and it seems it works fine. Connection, subscribing and publishing work out of the box, and one important thing, the keep alive mechanism also works. We can see how MQTT can be used with the Sming framework in here.

But what is this keep alive mechanism on the MQTT protocol? The MQTT protocol specification defines this:

It is the responsibility of the Client to ensure that the interval between Control Packets being sent does not exceed the Keep Alive value. In the absence of sending any other Control Packets, the Client MUST send a PINGREQ Packet.

This means that before a keep alive time is reached the client must do a request to the MQTT broker, and in case it doesn’t, it should send a PINGREQ.

For example, on a Mosquitto broker with logs enabled I can have this:

1450189246: New client connected from 192.168.1.200 as ESP8266 (c1, k10)

It shows that a client connected from 192.168.1.200 with the client identification ESP8266 and it defined as the keep alive interval 10s.

This means that at least before a ten second period is reached, the esp8266 MQTT client should send a PINGREQ or do something, like publishing to a topic.

The above requirements are probably the root of my problems and the fact that the ESP8266 chip/firmware can’t do too many things at once….

The test that I was doing was that I didn’t published nothing from the ESP8266 to the MQTT broker. All I was doing was to subscribe some MQTT topic and print the messages on the I2C 16×02 LCD that I have connected to the ESP8266.

Without any activity the esp8266 stayed connected to broker without any problems.

If I published something to the topic subscribed by the esp8266, it worked fine.

But if I published something massively to the topic subscribed, then the broker would drop the connection:

1450190071: Socket error on client ESP8266, disconnecting.

And that was a bit odd…

So at a first approach, I added a check timer to see if the MQTT connection was valid, and to reconnect if it wasn’t:

// Connect to the MQTT broker.
// If BRUSER is not empty, connect with user and password.
void startMqttClient()
{
    Serial.println("Mqtt server connect & subscribe..");   
    String mqttId = "esp8266-" + String(system_get_chip_id());

    if ( strlen( BRUSER ) == 0 )   
        mqtt.connect( mqttId );
    else
        mqtt.connect( mqttId, BRUSER , BRPWD );
    
    // Let's subscribe topics    
    mqtt.subscribe("/data");
    
}

void checkMQTT() {
        if (mqtt.getConnectionState() != eTCS_Connected) {
            Serial.println("MQTT Server: Lost connection... ");
            Serial.println("MQTT Server: Reconnect");
            startMqttClient(); // Auto reconnect
        }
}

And the timer that is defined to check the MQTT connection:

Timer checkTimer;

void startMain() {
  //...
  //...
  
  startMqttClient();  // Connect to the MQTT broker.
  checkTimer.initializeMs( 60 * 1000 , checkMQTT).start();
}

So every minute the connection to the broker is checked, and the reconnection, if needed, happens automatically.

But this solution doesn’t explain why the connection is lost when the burst of messages arrive at the topic.

Anyway to keep the long story short, the burst duration of messages where superior to the keep alive interval. Since that during that period I didn’t publish nothing, AND, the Mqtt library was busy to receive the incoming data burst, the broker assumed that the esp8266 was dead, and drop the connection.

Since the default keep alive was 10s, that value was too short to keep the connection stable under load.

The real solution is to increase the MQTT keep alive interval, to something that is bigger that any duration of probable data bursts. So what is needed is to specify a higher keep alive interval:

void startMqttClient()
{
    Serial.println("Mqtt server connect & subscribe..");   
    String mqttId = "esp8266-" + String(system_get_chip_id());

    mqtt.setKeepAlive(180);  // Keep alive of 180 seconds...

    if ( strlen( BRUSER ) == 0 )   
        mqtt.connect( mqttId );
    else
        mqtt.connect( mqttId, BRUSER , BRPWD );
    
    // Let's subscribe topics    
    mqtt.subscribe("/data");
    
} 

And with this change we got at the broker:

1450190936: New client connected from 192.168.1.200 as ESP8266 (c1, k180)

I can now burst messages to the esp8266 MQTT client without the connection being dropped.

So as long that incoming burst of messages are under 180 seconds ( which is easy) or some publishing from the ESP8266 happens, the connection stays up. Anyway, if it fails, the check timer will reconnect again to the broker.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s