MQTT connection times out waiting for function

I need too program a bunch of ESP8266 modules and use them in my home automation system.
Essentially the program is very simple, when it receives a message it calls a function then it returns to the main loop and the program starts over.

The problem is that I need to stay inside the function for a long time (1 to 20 minutes) and the MQTT connection times out.

I modified the base code that I use for the ESP8266 module (criticisms and suggestions are appreciated) and I added a function that waits X minutes to simplify the debugging. After the function has been called the connection times out, I tried to reconnect to the server but I can only publish the message inside the function and when the program returns to the main loop it can’t receive any message.

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

const char* ssid = "UniFi-HomeKit"; // Enter WiFi name
const char* password =  ":)"; // Enter WiFi password
const char* mqttServer = "10.10.20.10";
const int mqttPort = 1883;
const char* mqttUser = "matteo";
const char* mqttPassword = ":)";



const int ledPin = 2;      // the number of the LED pin
const int buzzer = 12;     // the number of the BUZZER pin
const int button = 5;      // the number of the BUTTON pin


const int oneMinute = (1 * 60 * 1000);
const int twentyMinutes = (20 * 60 * 1000);
const int tenSeconds = 10000;


int buttonState = 0;

WiFiClient espClient;
PubSubClient client(espClient);


void connectToWiFi()
{
  WiFi.mode(WIFI_STA); //access point mode disabled
  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
    digitalWrite(ledPin, HIGH);
    delay(100);
    digitalWrite(ledPin, LOW);
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());

}

void connectToMQTT()
{
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
  Serial.println("");
  Serial.print("Connecting to MQTT server");
  delay(200);
  Serial.print(".");
  delay(200);
  Serial.print(".");
  delay(200);
  Serial.println(".");
  while (!client.connected()) {

    if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
      Serial.println("Connected to MQTT server");

    } else {
      delay(300);
      digitalWrite(ledPin, HIGH);
      delay(300);
      digitalWrite(ledPin, LOW);
      Serial.println("");
      Serial.print("failed with state ");
      Serial.print(client.state());

    }
  }
}

void startConnection()
{
  delay(2000);
  connectToWiFi();
  connectToMQTT();
}

void ledBlink (int interval)
{
  digitalWrite(buzzer, HIGH);
  digitalWrite(ledPin, LOW);
  
  delay(interval);
  digitalWrite(buzzer, LOW);
  digitalWrite(ledPin, HIGH);
  
  delay(interval);
}

void wait()
{
  delay(oneMinute);
  Serial.println("Time elapsed");

  if (!client.connected())
  {
    Serial.println("Not connected to MQTT server, connecting again");
    connectToMQTT();
  }

  client.publish("waitTest/START", "OFF");
  Serial.println("Publish OFF");


}

void callback(char* topic, byte* payload, unsigned int length) {

  Serial.print("Message arrived in topic: ");

  if (!strncmp((char *)payload, "ON", length))
  {
    Serial.println("ON");
    wait();
  }
  else
  {
    Serial.println("Invalid message");
  }
}

void setup() {

  Serial.begin(115200);

  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the BUZZER pin as an output:
  pinMode(buzzer, OUTPUT);
  // initialize the BUTTON pin as an input:
  pinMode(button, INPUT_PULLUP);

  startConnection();

  client.subscribe("waitTest/START");

}

void loop() {

  client.loop();

  if ((WiFi.status() == WL_CONNECTION_LOST) || (WiFi.status() == WL_DISCONNECTED))
  {
    Serial.println("WiFi connection lost, connecting again");
    connectToWiFi();
  }

  if (!client.connected())
  {
    Serial.println("MQTT connection lost, connecting again");
    connectToMQTT();
  }

  delay(300);
}

What can I do to resolve the problem?

Thanks

reduce delays and increase the number of time client loop is ran.

Example the keep alive function that I run that makes the WIFI and MQTT connection.

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
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 250; // 250mS
  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();
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete ( NULL );
}

Note the MQTT setting MQTTclient.setKeepAlive( 90 );. This setting will help with keeping open long sessions.

In the code above client loop is run 4 times a second.

The rate with which client loop is ran and the keep alive setting are the keys to maintaining an open connection

////
void connectToMQTT()
{
  // create client ID from mac address
  byte mac[5];
  int count = 0;
  WiFi.macAddress(mac); // get mac address
  String clientID = String(mac[0]) + String(mac[4]);
  log_i( "connect to mqtt as client %s", clientID );
  while ( !MQTTclient.connected() )
  {
    MQTTclient.disconnect();
    MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password );
    vTaskDelay( 250 );
    count++;
    if ( count == 5 )
    {
      ESP.restart();
    }
  }
  MQTTclient.setCallback( mqttCallback );
  MQTTclient.subscribe( topicOK );
}
////
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()

Instead of waiting one minute at a time I made a loop so it waits one second and then calls the client.loop(); function, repeated 60 times.

void wait(int i)
{
  while (i != 0)
  {
    Serial.println(i);
    delay(1000);
    client.loop();
    i--;
  }

  Serial.println("Time elapsed");

  if (!client.connected())
  {
    Serial.println("Not connected to MQTT server, connecting again");
    connectToMQTT();
  }

  client.publish("waitTest/START", "OFF");
  Serial.println("Publish OFF");

}

I don’t know if I like this solution or not but it works.

I had also thought of increasing the KeepAlive time before calling the function and then set it back to a few seconds when it’s done but, if I understand correctly, I would need to disconnect and reconnect too be effective, maybe that wouldn’t be a problem since the function is called once a day

This is blocking code:

  while (i != 0)
  {
    Serial.println(i);
    delay(1000);
    client.loop();
    i--;

Unless your ESP8266 has the freeRTOS OS delay(1000) will bring things to a grinding halt, an ESP8266 operating at 80Mhz and does nothing for one second is a 'lifetime' to the CPU. millis() in your main loop can be used to call client loop once a second. See the tutorial on this site about doing many things at once (millis()) or, if your ESP8266 has freeRTOS use the freeRTOS to multi-thread the client loop function.

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