ESP8266 verbindet sich nicht mit MQTT

Hallo Community,

ich bin noch wackeliger Anfänger und mein erstes Projekt soll ein ESP8266 Modul sein, welches Temperatur und Luftfeuchte mit dem DHT11 misst und die Werte an meinen lokalen ioBroker, welcher auf einem Pi4 läuft, übermitteln.

Läuft auch soweit, nur zickt der ESP manchmal rum und möchte sich einfach nicht mit dem MQTT Server auf dem Pi verbinden, "failed with -2".
Am Anfang hatte ich parallel noch etwas am MQTT auf dem ioBroker gespielt oder bereits übermittelte Werte einfach gelöscht, das fand der wohl nicht so gut (hatte ich irgendwo gelesen). Irgendwann ging es dann wieder.

Seit Sonntag lief mein Prototyp nun über Batterie und übermittelte brav alle 2 Minuten die Werte, als ich ihn zur Verbesserung des Codes gestern Abend aus dem Bad in die Küche holte und er von jetzt auf gleich wieder rumzickte.

Auf meinem Smartphone habe ich ein MQTTtool laufen und von dort verbindet er sich wunderbar mit dem lokalen MQTT und ich kann Werte veröffentlichen - sprich, der MQTT Server sollte in Ordnung sein?

Sind die ESP8266 (von AZDelivery) vielleicht für Zicken bekannt?

Das hier ist mein Code, ich komme bis

Serial.print("failed with state ");
Serial.println(client.state());

und dann bleibt er in der Schleife und zeigt nur Code -2 an.

WLAN ist währenddessen aber immer aktiv und verbunden.


#include "ESP8266WiFi.h"
#include "PubSubClient.h"
#include "DHT.h"

#define DHTPIN 5 //Der Sensor wird an PIN D1 angeschlossen, wird aber in der Arduino Software als "5" bezeichnet. Siehe AZ Datasheet    

#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

// WiFi
const char *ssid = "XXXX"; // Enter your Wi-Fi name
const char *password = "XXXXXXX";  // Enter Wi-Fi password

// MQTT Broker
const char *mqtt_broker = "192.168.178.19";
const char *mqtt_username = "muser";
const char *mqtt_password = "XXXXXX";
const int mqtt_port = 1883;

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {

 dht.begin(); //DHT11 Sensor starten

  Serial.begin(115200);

  client.setServer(mqtt_broker, mqtt_port);


  WiFi.mode( WIFI_OFF );

  WiFi.forceSleepBegin();

  delay( 1 );

  WiFi.begin(ssid, password);
}


void loop() {
  float hum = dht.readHumidity(); 
  float tem = dht.readTemperature();

  WiFi.forceSleepWake();

  delay( 1 );

  WiFi.mode( WIFI_STA );

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

      delay(500);

      Serial.println("Connecting to WiFi..");

    }

    Serial.println("Connected to the Wi-Fi network");


  while (!client.connected()) {

     String client_id = "ESP32-Bad";

     Serial.println("connecting to IObroker");

     if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {

       Serial.println("IObroker connected");

        } 

        else {

            Serial.print("failed with state ");

            Serial.println(client.state());

            Serial.print("WiFi Status: ");

            Serial.println(WiFi.status());

            delay(1000);

          }

    }


  

  Serial.print("Luftfeuchtigkeit: "); //Im seriellen Monitor den Text und 

  Serial.print(hum); //die Dazugehörigen Werte anzeigen

  Serial.println(" %");

  Serial.print("Temperatur: ");

  Serial.print(tem);

  Serial.println(" Grad Celsius");

  Serial.print("WiFi Status: ");

  Serial.println(WiFi.status());

  Serial.print("MQTT Status: ");

  Serial.println(client.connected());


  String topic1 = "Klima/Bad/Temperatur";       //Topic wird oben definiert aber als Char!

  String payload1 = String(tem);

  client.publish(topic1.c_str(), payload1.c_str());


  String topic2 = "Klima/Bad/Luftfeuchte";       //Topic wird oben definiert aber als Char!

  String payload2 = String(hum);

  client.publish(topic2.c_str(), payload2.c_str());


  client.disconnect();


  WiFi.mode( WIFI_OFF );

  WiFi.forceSleepBegin();

  delay( 1 );


  delay(30000); //Sekunden Vorlaufzeit bis zur Messung (der Sensor ist etwas träge)


}

Deine WiFi Anmeldung solltest du im Setup machen und das "delay(30000)" in der loop() wird weiteres verhindern bzw. blockieren.
Das solltest du da raus nehmen.

ich würde es nach diesem Muster aufbauen:

pubsubclient/examples/mqtt_esp8266/mqtt_esp8266.ino at master · knolleary/pubsubclient · GitHub

Es fehlt ein client.loop(); im Loop!
Diese Methode muss regelmäßig aufgerufen werden, damit die Verbindung bestehen bleibt. (Und der Client auf Nachrichten reagieren kann).

Warum machst du ein?
client.disconnect();
Normalerweise lässt man die Verbindung zum Server bestehen.

Gibt es mehrere Clienten mit der gleichen Client-ID? Das wirft einen der beiden Clienten aus dem MQTT Netzwerk.

-2 Bedeutet nur Verbindung fehlgeschlagen.

// Possible values for client.state()
#define MQTT_CONNECTION_TIMEOUT     -4
#define MQTT_CONNECTION_LOST        -3
#define MQTT_CONNECT_FAILED         -2
#define MQTT_DISCONNECTED           -1
#define MQTT_CONNECTED               0
#define MQTT_CONNECT_BAD_PROTOCOL    1
#define MQTT_CONNECT_BAD_CLIENT_ID   2
#define MQTT_CONNECT_UNAVAILABLE     3
#define MQTT_CONNECT_BAD_CREDENTIALS 4
#define MQTT_CONNECT_UNAUTHORIZED    5

HAllo HotSystems,

ich würde gerne zwischendurch das WiFi Modul abschalten, um Strom zu sparen, und das geht ja nur innerhalb des Loop-Teils, oder nicht?

Was genau wird der delay verhindern? Kennst du eine bessere Möglichkeit, den DSP ein paar Minuten zu pausieren?

LG,

Antalus

Hallo Plumps,

Es fehlt ein client.loop(); im Loop!
Diese Methode muss regelmäßig aufgerufen werden, damit die Verbindung bestehen bleibt. (Und der Client auf Nachrichten reagieren kann).

Was genau macht die Loop bzw wie kommt der aus der Loop wieder raus? Ich finde dazu leider nichts.
Die Verbindung soll nicht immer bestehen, denn um Strom zu sparen (soll auf Akku laufen) soll der nur alle 4-5 Minuten Verbindung aufbauen, Werte senden und wieder beenden.
So zumindest mein Plan.

Warum machst du ein?
client.disconnect();
Normalerweise lässt man die Verbindung zum Server bestehen.

Alles zum Stromsparen :slight_smile: Der soll ja auch nur Werte senden und nichts empfangen.

Gibt es mehrere Clienten mit der gleichen Client-ID? Das wirft einen der beiden Clienten aus dem MQTT Netzwerk.

Nein, gibt nur den einen. :frowning:

LG,

Antalus

Sieht man in der *.cpp

Was meinst mit rauskommen? Es ist eine Methode wie andere. Wird abgearbeitet.

Strom sparst du nicht wenn die Verbindung ab und wieder aufbaust. Da musst du schon dein μC in ein Sleep schicken.

Zumal ein Ab- und Aufbau länger dauert als ein halten.

Dann setze diese Prozedur in eine eigene Funktion. Dann kannst du die jederzeit beenden und auch wieder starten.

Das delay() stoppt an der stelle den Lauf der loop() und damit wird nichts mehr ausgeführt, was du in der loop() laufen lassen möchtest. Dies mal einfach formuliert. Die kannst das delay() durch eine eigene Funktion mit den millis ersetzen. Sieh dir dazu das Beispiel BlinkWithoutDelay an.

Überarbeite deinen Sketch entsprechend unseren Vorschlägen.
Dann wird es sicher einfacher, weitere Fehler zu beheben.
Das delay() in deiner loop() macht einen Großteil deines Problems aus.

Du wirst vermutlich nirgend ein funktionierenden Sketch finden, der ein derartig großes delay() in der loop() hat.

Die loop() ist, wie der Name schon sagt, eine Schleife. Diese "muss" immer laufen, ohne größere Verzögerung und möglichst schnell.
Und raus kommst du da, in dem du aus der loop() entsprechende Funktionen (Unterprogramme) aufrufst. Nach Beendigung dieser Funktion gehts wieder zurüch in die loop(). Wenn kein Problem erfolgt, geht es immer so weiter.

Sorry, habe mich vertan, ich dachte client.loop() wäre eine klassische Loop.

OK, ich werde mein Sketch mal überarbeiten :slight_smile:

Hallo,
eventuell schaust Du dir auch mal die Möglichkeit an mit deepSleep zu arbeiten. Das würde in dem Fall sicher mehr Sinn ergeben.

Hi Rentner,

danke, ja, lese ich mir gerade durch :slight_smile:

-Anta

So, zum Abschluss des Threads mein aktueller Code mit DeepSleep statt delay.
Ich hatte bis dato keine Verbindungsprobleme mehr. Ob es an den verschiedenen Client-Namen liegt, kann ich nciht genau sagen. Jedenfalls türmen sich jetzt nun natürlich die Client-Einträge im ioBroker. Muss mal schauen, ob ich nicht doch immer den gleichen Clientnamen verwenden kann.
Mein DSP wacht nun auf, misst die Werte, schickt sie an den MQTT Server und legt sich schlafen für 10 Minuten.
Aktuell hält der mit 18650 Akku schon sieben Tage durch, mal sehen wie lange noch.


#include "ESP8266WiFi.h"
#include "PubSubClient.h"
#include "DHT.h"

#define DHTPIN 5 //Der Sensor wird an PIN D1 angeschlossen, wird aber in der Arduino Software als "5" bezeichnet. Siehe AZ Datasheet    
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

// WiFi
const char *ssid = "*****"; // Enter your Wi-Fi name
const char *password = "*******";  // Enter Wi-Fi password

// MQTT Broker
const char *mqtt_broker = "********";
const char *mqtt_username = "****";
const char *mqtt_password = "*****";
const int mqtt_port = 1883;

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  
  dht.begin(); //DHT11 Sensor starten
  Serial.begin(115200);
  while(!Serial) { }
  client.setServer(mqtt_broker, mqtt_port);

  
  WiFi.mode( WIFI_STA );
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.println("Connecting to WiFi..");
    }
    Serial.println("Connected to the Wi-Fi network");


  float hum = dht.readHumidity(); 
  float tem = dht.readTemperature();

  
  while (!client.connected()) {
     String client_id = "ESP32-Bad-";
     client_id += String(random(0xffff), HEX);
     Serial.println("connecting to IObroker");
     if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
       Serial.println("IObroker connected");
        } 
        else {
            Serial.print("failed with state ");
            Serial.println(client.state());
            delay(1000);
          }
    }

  Serial.print("Luftfeuchtigkeit: "); 
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temperatur: ");
  Serial.print(tem);
  Serial.println(" Grad Celsius");
  

  String topic1 = "Klima/Bad/Temperatur";       //Topic wird oben definiert aber als Char!
  String payload1 = String(tem);
  client.publish(topic1.c_str(), payload1.c_str());

  String topic2 = "Klima/Bad/Luftfeuchte";       //Topic wird oben definiert aber als Char!
  String payload2 = String(hum);
  client.publish(topic2.c_str(), payload2.c_str());

  client.disconnect();
  
  WiFi.mode( WIFI_OFF );
  WiFi.forceSleepBegin();
  delay( 1 );

  ESP.deepSleep(600e6);   //1e6 = 1* 10^6 = 1 sekunde
      
}


void loop() {
  
  

}