knolleary / pubsubclient

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

Callback issue-subscribe topic receive the messages once in a while #277

Open darc76 opened 7 years ago

darc76 commented 7 years ago

Hi @knolleary I'm using the pububclient library on an arduino uno and a ESP8266 via software serial, I intend to do a multi sensor connected via MQTT, I followed the example with the DHT22 sensor, it works great, publishing the temperature and humidity every second, or less, but when I try to subscribe to a topic in my broker, the subscribe is ok, but the callback receive the messages once in a while at most, here is my code, may seems a little messy, but, I was the last three days trying to figured out what is the problem. Thanks in advance.

PS. I tried a solution from another user, to delay the client.loop and the client.connect. There is in the code. The subcribed topic is home y el outtopic es home/out

//ESTE PROGRAMA ESTA FUNCIONANDO ENVIANDO TEMPERATURA Y HUMEDAD AL MQTT SERVER
//ANTES DE SUSCRIBIRSE

#include <DHT.h>
#include <WiFiEspClient.h>
#include <WiFiEsp.h>
#include <PubSubClient.h>
#include <SoftwareSerial.h>

#define WIFI_AP "mywifi"
#define WIFI_PASSWORD "********"

//#define TOKEN "1"

// DHT
#define DHTPIN 4
#define DHTTYPE DHT22

char mqttserver[] = "mqttbrokerIP";

// Initialize the Ethernet client object

// Initialize DHT sensor.
DHT dht(DHTPIN, DHTTYPE);

SoftwareSerial soft(7, 8); // RX, TX

int status = WL_IDLE_STATUS;
unsigned long lastSend;
unsigned long lastConnected;
unsigned long lastLoop;
int cuantos=0;
int envios=0;
// Callback function header
void callback(char* topic, byte* payload, unsigned int length);

//Clientes WIFI y MQTT
WiFiEspClient espClient;
PubSubClient client(mqttserver, 1883, callback, espClient );

// Callback function
void callback(char* topic, byte* payload, unsigned int length) {
//  client.publish("home/out"), payload, length); 
  // In order to republish this payload, a copy must be made
  // as the orignal payload buffer will be overwritten whilst
  // constructing the PUBLISH packet.
     cuantos = cuantos + 1;
     Serial.print("Te tengo ");
     Serial.println(cuantos);

  // Allocate the correct amount of memory for the payload copy
  byte* p = (byte*)malloc(length);
  // Copy the payload to the new buffer
  memcpy(p,payload,length);
  client.publish("home/out", p, length);
  // Free the memory
  free(p);
}

void setup() {
  // initialize serial for debugging
  Serial.begin(9600);
  dht.begin();
  InitWiFi();
  //entrada original del sketch para conectarse al servidor
  //client.setServer( thingsboardServer, 1883 );

  // client.publish("home/out","hello world");
   //   
  lastSend = 0;
  lastConnected = 0;
  lastLoop = 0;

}

void loop() {
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    while ( status != WL_CONNECTED) {
      Serial.print("Attempting to connect to WPA SSID: ");
      Serial.println(WIFI_AP);
      // Connect to WPA/WPA2 network
      status = WiFi.begin(WIFI_AP, WIFI_PASSWORD);
      delay(500);
    }
    Serial.println("Connected to AP");
  }

 if ( millis() - lastConnected > 2000 ) {
  if ( !client.connected() ) {
    reconnect();
     }
 lastConnected = millis();
 }
  if ( millis() - lastSend > 30000 ) { // Update and send only after 1 seconds
    getAndSendTemperatureAndHumidityData();
    lastSend = millis();
  }
  if ( millis() - lastLoop > 2000 ) {
     client.loop();
     lastLoop = millis();
  }
}

void getAndSendTemperatureAndHumidityData()
{
  Serial.println("Collecting temperature data.");

  // Reading temperature or humidity takes about 250 milliseconds!
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" *C ");

  String temperature = String(t);
  String humidity = String(h);

  // Just debug messages
  Serial.print( "Sending temperature and humidity : [" );
  Serial.print( temperature ); Serial.print( "," );
  Serial.print( humidity );
  Serial.print( "]   -> " );

  // Prepare a JSON payload string
  String payload = "{";
  payload += "\"temperature\":"; payload += temperature; payload += ",";
  payload += "\"humidity\":"; payload += humidity;
  payload += "}";

  // Send payload
  char attributes[100];
  payload.toCharArray( attributes, 100 );
  client.publish( "home/site/sensors/temphum", attributes );
  Serial.println( attributes );
  envios= envios +1;
 Serial.print("publicaciones: ");
 Serial.println(envios);

}

void InitWiFi()
{
  // initialize serial for ESP module
  soft.begin(9600);
  // initialize ESP module
  WiFi.init(&soft);
  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue
    while (true);
  }

  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(WIFI_AP);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(WIFI_AP, WIFI_PASSWORD);
    delay(500);
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Connecting to Openhab MQTT Server node ...");
    // Attempt to connect (clientId, username, password)
    if ( client.connect("arduinoclient") ) {
    //agregada estas dos lineas del sketch mqtt_publish_in_callback
      client.subscribe("home", 1);
      Serial.println( "[DONE]" );
    } else {
      Serial.print( "[FAILED] [ rc = " );
      Serial.print( client.state() );
      Serial.println( " : retrying in 5 seconds]" );
      // Wait 5 seconds before retrying
      delay( 5000 );
    }
  }
}
knolleary commented 7 years ago

The client is only able to receive a message when you call client.loop.

If you are not calling it regularly, then you will see an apparent delay in receiving a message.

I'm not going to debug your code, but I suggest you add a Serial.println ahead of the call to client.loop so you can confirm how often you are calling it and how that relates to the receiving of messages.

darc76 commented 7 years ago

Thanks @knolleary, I wiil try that and let you know.

StefanHermannBerlin commented 6 years ago

What worked for me:

  1. calling client.loop() is mandatory (like @knolleary pointed out)
  2. having a delay(10) in the end of the loop (this actually changed everything)