knolleary / pubsubclient

A client library for the Arduino Ethernet Shield that provides support for MQTT.
http://pubsubclient.knolleary.net/
MIT License
3.85k stars 1.48k forks source link

25+ redundant publish messages from MQTT broker #779

Closed baqwas closed 4 years ago

baqwas commented 4 years ago

Hello,

I used the following code successfully to publish messages from MKR1000 (via MKR ETH) to an internal MQTT broker. On the other side, a nominal Node-RED flow received each message (at the transmitted interval of ~1 min).

                                     //!< override connectivity configuration settings
  MQTTclient.setKeepAlive(120);       // keep alive interval is changed 120 seconds from default 15
  MQTTclient.setSocketTimeout(120);   // socket timeout is changed to 120 seconds from default 15
  MQTTclient.setServer(MQTTserver, 1883);//!< default port
  MQTTclient.setCallback(callbackSub);

  while (!ENV.begin())                //!< initialize the sensors on MKR ENV shield
    ;                                 //!< =0, failure; =1, success
                                      //!< TODO: status code(s) for LED to avoid the need for Serial
  pinMode(pinBLINK, OUTPUT);          //!< initialize digital pin LED_BUILTIN as an output
  digitalWrite(pinBLINK, pinState);   //!< apply default state to pin controlling LED
}

/*!
 * @brief loop run many
 */
void loop()                           //!< run many
{
  if (MQTTclient.connected())
  {
    digitalWrite(pinBLINK, LOW);
  } else {
    reconnect();
    digitalWrite(pinBLINK, HIGH);
  }

  if ((millis() - lastFrame) > blinkInterval)
  {
    pinState = !pinState;                           //!< flip the state for the LED setting
    digitalWrite(pinBLINK, pinState);               //!< transmit the setting to the pin for correponding action on LED
    MQTTmsg["DeviceName"]  = "ENV-M1K-1";           //!< device name for external reference
    MQTTmsg["Humidity"]    = ENV.readHumidity();    //!< read temperature sensor's humidity value
    MQTTmsg["Illuminance"] = ENV.readIlluminance(); // read illuminance
    MQTTmsg["Pressure"]    = ENV.readPressure(unitPressure);// read pressure sensor's value in specified units (default kPa)
    MQTTmsg["Temperature"] = ENV.readTemperature(unitTemperature);// read temperature sensor's temperature value
    MQTTmsg["UVa"]         = ENV.readUVA();         //!< UV A value
    MQTTmsg["UVb"]         = ENV.readUVB();         //!< UV B value
    MQTTmsg["UVindex"]     = ENV.readUVIndex();     //!< UV Index value
    MQTTclient.publish(pubTopic, ((String)JSON.stringify(MQTTmsg)).c_str());

    lastFrame = millis();             //!< update marker to avoid including processing time in interval
                                      // of course, "true" constant interval would not be preserved in this mode
                                      // owing to processing overhead
  }
  MQTTclient.loop();                  //!< maintain connection to broker to process inbound messages
}

When I use a similar code (see below), the Node-RED flows seems to receive 25+ messages for each publish operation. In the second case, I am using Arduino UNO R3 with Wiz550io as the Ethernet interface.

                                      //!< override connectivity configuration settings
  MQTTclient.setKeepAlive(120);       // keep alive interval is changed 120 seconds from default 15
  MQTTclient.setSocketTimeout(120);   // socket timeout is changed to 120 seconds from default 15
  MQTTclient.setServer(MQTTserver, 1883);//!< default port
  MQTTclient.setCallback(callbackSub);

}

void loop()                             // run many
{
  if (MQTTclient.connected())
  {
    digitalWrite(pinBLINK, LOW);
  } else {
    reconnect();
    digitalWrite(pinBLINK, HIGH);
  }

  if ((millis() - lastFrame) > blinkInterval)
  {
    pinState = !pinState;                           //!< flip the state for the LED setting
    digitalWrite(pinBLINK, pinState);               //!< transmit the setting to the pin for correponding action on LED
    myDHT22_1.read();
    MQTTmsg["DeviceName"]  = "ENV-A4-1";            //!< device name for external reference
    MQTTmsg["Humidity"]    = myDHT22_1.getHumidity();//!< read temperature sensor's humidity value
    MQTTmsg["Temperature"] = myDHT22_1.getTemperature();// read temperature sensor's temperature value
    MQTTclient.publish(pubTopic, ((String)JSON.stringify(MQTTmsg)).c_str());

    lastFrame = millis();             //!< update marker to avoid including processing time in interval
                                      // of course, "true" constant interval would not be preserved in this mode
                                      // owing to processing overhead
  }
  MQTTclient.loop();                  //!< maintain connection to broker to process inbound messages
}

Obviously, there is a BIG gap in my understanding of PubSub messaging but I can confirm based on pseudo-debug statements to the Serial Monitor that the publish statement is executed per blinkInterval settings (viz. 1 minute in the examples). What would cause 25+ redundant/identical messages to be published by the broker?

Owing to the richness of Node-RED there are many things that can be done to insulate oneself from the effects of the redundant transmissions but perhaps some astute reader can help me understand my mistake. Thanks.

Kind regards.

P.S. The code snippet for the PubSubClient library usage is:

EthernetClient LANclient;                             // instantiate Ethernet network client

char MQTTserver[] = MY_BROKER;        //!< defined in header file
char MQTTuser[] = USER_ID;            //!< defined in header file
char MQTTcred[] = USER_CREDENTIAL;    //!< defined in header file
const uint16_t MQTTport = 1883;       //!< unlikely to change for most infrastructure
const char* MQTTclientId = "UNO-1";   //!< just to have some semblance of standard nomenclature
                                      //!< https://duckduckgo.com/search?q=arduino
char pubTopic[]   = "arduino/uno/pub";
char pubMessage[] = "{\"DeviceName\":\"\"}";
char subTopic[]   = "arduino/mkreth/sub";
char subMessage[] = "MQTT subscribe test";
JSONVar MQTTmsg;                      //!< MQTT message buffer

void callbackSub(char* topic, byte* payload, unsigned int length);//!< old school declaration for proper instantiation of client entity
PubSubClient MQTTclient(MQTTserver, 1883, callbackSub, LANclient);//!< partially initialized client instance

The Ethernet library in use is the standard Arduino library with the define for the Wiz550io module as communicated by Wiznet technical support:

#include <Ethernet.h>
#define W5500_ETHERNET_SHIELD
#ifdef W5500_ETHERNET_SHIELD
#define WIZ550io_WITH_MACADDRESS
#include "w5500.h"
#endif
baqwas commented 4 years ago

Hello! Yet another false alarm by a newbie!! Was using unsigned int instead of unsigned long for the variables lastFrame & blinkInterval. Sorry.