MQTT publishing problem

I have a problem and frankly, I don’t know if it is an Arduino or a MQTT related problem. Maybe I can find an expert in both in here. I’ll give it a try…

I have a Wemos D1 mini ESP8266 with four DS18B20 temperture sensors connected to it. As I’m fairly new to Arduino, I did some cuting and pasting from other sketches to create my own sketch that connects to my WiFi, connects to my broker (in Home Assistant), measures the temperature and publish to the broker in a loop.

Under the construction I sat the loop time to 5000 ms to see the result quickly. When it worked and I was happy, I changed the time to 120000 ms (2 minutes). Then the publishing suddenly stopped! The sketch continues to work. It connects to the WiFI, the broker and measured every 2 minutes and prints the values to serial monitor, but it just don’t publish, as far as I can understand.

I used MQTT Explorer to make sure that it wasn’t an subscribing issue in HA, but it wasn’t published to MQTT Explorer either.
I changed back to 5 sec and it started to publish again. I did some testing and it seems like it works up to 30 sec but above that, nothing…

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


const int oneWireBus = 2;     


// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);


// Pass our oneWire reference to Dallas Temperature sensor 
DallasTemperature sensors(&oneWire);


// Array for defining sensor addresses
DeviceAddress sensor1 = { 0x28, 0xA2, 0x1E, 0x07, 0xD6, 0x01, 0x3C, 0x65 };  // outdoor
DeviceAddress sensor2 = { 0x28, 0xF5, 0x1E, 0x07, 0xD6, 0x01, 0x3C, 0xCE };  // stair
DeviceAddress sensor3 = { 0x28, 0x72, 0x7D, 0x07, 0xD6, 0x01, 0x3C, 0xFE };  // garret
DeviceAddress sensor4 = { 0x28, 0xF7, 0xED, 0x07, 0xD6, 0x01, 0x3C, 0x48 };  // basement


// WiFi
const char* ssid = "[SSID]";
const char* wifi_password = "[PASSWORD]";


// Timer loop from http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
long previousMillis = 0;
// Checking temperature every 2 minutes
long interval = 120000;


// MQTT
const char* mqtt_server = "[IP_ADDRESS]";                   // IP address of MQTT broker
const char* clientID = "Wemos D1";                          // Unique client name
const char* mqtt_user = "[USERNAME]";                       // MQTT username
const char* mqtt_password = "[PASSWORD]";                   // MQTT passsword
const char* tempSensor1 = "hass/temp/outside";              // Topic for publishing sensor data
const char* tempSensor2 = "hass/temp/stair";                // Topic for publishing sensor data
const char* tempSensor3 = "hass/temp/garret";               // Topic for publishing sensor data
const char* tempSensor4 = "hass/temp/basement";             // Topic for publishing sensor data


// Initialise the WiFi and MQTT Client objects
WiFiClient wifiClient;
PubSubClient client(mqtt_server, 1883, wifiClient);         // 1883 is the listener port for the Broker


void setup() {
  // Start the Serial Monitor
  Serial.begin(115200);


  Serial.print("Connecting to ");
  Serial.println(ssid);


  // Connect to the WiFi
  WiFi.begin(ssid, wifi_password);


  // Wait until the connection has been confirmed before continuing
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }


   // Debugging - Output the IP Address of the ESP8266
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());


   // Connect to MQTT Broker
  if (client.connect(clientID, mqtt_user, mqtt_password)) {
    Serial.println("Connected to MQTT Broker!");
  }
  else {
    Serial.println("Connection to MQTT Broker failed...");
  }


  // Start the DS18B20 sensor
  sensors.begin();
}


void loop() {
    unsigned long currentMillis = millis();


  if (currentMillis - previousMillis >= interval) {    
  sensors.requestTemperatures(); 
  float t1 = sensors.getTempC(sensor1);
  float t2 = sensors.getTempC(sensor2);
  float t3 = sensors.getTempC(sensor3);
  float t4 = sensors.getTempC(sensor4);


     // Set timer to publish to broker
    previousMillis = currentMillis;
    client.publish(tempSensor1, String(t1).c_str());
    client.publish(tempSensor2, String(t2).c_str());
    client.publish(tempSensor3, String(t3).c_str());
    client.publish(tempSensor4, String(t4).c_str());
    Serial.print("Temperatur ute: ");
    Serial.println(String(t1).c_str());
    Serial.print("Temperatur trappan: ");  
    Serial.println(String(t2).c_str());
    Serial.print("Temperatur vinden: ");   
    Serial.println(String(t3).c_str());
    Serial.print("Temperatur källaren: ");  
    Serial.println(String(t4).c_str());
  }
}

Could someone please give me an helping hand. I have no clue…

As I said I’m new to Arduino and this is my first post in this forum, so please bare with me…

Thanx!

MQTT doesn't want to get overwhelmed with connections from clients that are no longer active so that it can service the ones that are.

To that end, if you haven't talked to it for a while (often 60 seconds) it will send a keep alive message to you so you can demonstrate that you're still active. If it doesn't get a reply, your connection is dropped.

It sounds as though your timeout is 30 seconds and that your client doesn't get or doesn't respond to keep alive requests.

If you control the MQTT broker, you can run it in verbose mode and see from the progress messages whether this is the case.

Look at MQTT example code. Usually they have some provision to reconnect if there's a problem. Yours connects once only so if something goes wrong, there's no recovery.

Here is an MQTT keep alive task that I use:

/*
  Important to not set vTaskDelay to less then 10. Errors begin to develop with the MQTT and network connection.
  makes the initial wifi/mqtt connection and works to keeps those connections open.
*/
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; //delay for ms
  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 line: MQTTclient.setKeepAlive( 90 );, which is set before the connection is made.

My client loop task runs once every 250ms.

I don't see client.loop() in your loop() function.

Here's how I handle it.
I start the loop() with:

//Make sure we stay connected to the mqtt broker
  if (!client.connected()) {
    mqttConnect();
  }
  if (!client.loop()) {
    client.connect(connectName);
  }

My mqttConnect() function:

void mqttConnect() {
  while (!client.connected()) {
    Serial.print(F("MQTT connection..."));
    if (client.connect(connectName)) {
      Serial.println(F("connected"));

      //Subscriptions here:
      client.subscribe(cmndTopic);
      Serial.print(F("Subscribing to "));
      Serial.println(cmndTopic);
    } else {
      Serial.print(F("failed, rc="));
      Serial.print(client.state());
      Serial.println(F("- trying again in 5-seconds."));
      delay(5000);
    }
  }
}

Oh, I also put a call to mqttConnect() in setup(), but that may be redundant because without it, mqttConnect() is called the first time through loop().

Thank you all!

I wasn't aware that MQTT did a keep alive check.
I have implemented a reconnect routine now and it works great!
I've learned something new :slight_smile:

Thanx again!

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