Mqtt blockiert den Code wenn Brocker nicht sendet

Hallo,
eventuell kennt jemand dieses Problem und hat dazu eine Lösung:
Ich benutze die Bibliothek ArduinoMqttClient.h und mein Code läuft.
Mein Problem ist folgendes, wenn ich den Brocker abstelle, bleibt meine Code an mqttClient.poll(); hängen.
Wieso auch nicht, poll() wartet ja auf die Daten vom Brocker.
In der Bibliothek gebt es noch mqttClient.setConnectionTimeout(?);
Kennt sich jemand mit dieser Bibliothek aus? Hat jemand ein Lösung, das beim Timeout vom der Abfrage, dem Warten der Code weiter läuft?
Mein Code merkt nicht, das der Brocker nichts sendet, aber er merkt, das er noch da ist.

Der Code ist nur auf die Schnelle hier entworfen :slight_smile:

#include <ArduinoMqttClient.h>
#include <WiFi.h>


const char ssid[] = "xxx";
const char password[] = "xxx";
const char hostname[] = "xxx";
WiFiClient wlan;

MqttClient mqttClient(wlan);
const char broker[] = "xxx";
int port = 1883;
const char topic[] = "xxx";

void setup() {
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    digitalWrite(LED_RESET, HIGH);
    delay(500);
    digitalWrite(LED_RESET, LOW);
    delay(500);
  }
  Serial.println("WiFi verbunden");

  // Connect to MQTT broker
  mqttClient.connect(broker, port);
  mqttClient.subscribe("soc");
  mqttClient.setConnectionTimeout(100);
  // set the message receive callback
  mqttClient.onMessage(onMqttMessage);


}

void loop(){

  //Steuerung, mqtt-Abfrage einschalten
  if (digitalRead(Eingang[0]) == HIGH) {
    if (!mqttClient.connected()) {
      Serial.print("MQTT connection failed! Error code = ");
      Serial.println(mqttClient.connectError());
      delay(5000);
      soc = 0;
      allesaus();
      digitalWrite(LED_USER, HIGH);
    } else if (mqttClient.connected()) {
      mqttClient.poll();
      digitalWrite(LED_USER, LOW);
    }
  } else {
    **//Wenn poll() ausfällt,sollte es hier weiter gehen.**

    soc = 0;
  }

}

Schau dir mal ArduinoMqttClient/examples/WiFiSimpleReceiveCallback/WiFiSimpleReceiveCallback.ino at master · arduino-libraries/ArduinoMqttClient · GitHub an, wie Poll verwendet wird.

Dir fehlt auch

void onMqttMessage(int messageSize) {.....

Ich verwende das Beispiel ja auch so, war mir jetzt nicht bewusst, das der Fehler in "void onMqttMessage(int messageSize)" liegen sollte.
Deshalb habe ich es hier nicht mit aufgeführt.
Hab da viel ausgeklammert, weil ich der Meinung bin, es bringt mir für meine Zwecke nichts. Irre ich mich hier?


void onMqttMessage(int messageSize) {
  buff = "";
  // we received a message, print out the topic and contents
  //Serial.print("Received a message with topic '");
  //Serial.print(mqttClient.messageTopic());
  //Serial.print("', length ");
  //Serial.print(messageSize);
  //Serial.println(" bytes:");

  // use the Stream interface to print the contents
  while (mqttClient.available()) {

    char c = mqttClient.read();
    buff += c;
  }
  soc = buff.toInt();
  lauflicht();
}

Bin der Meinung, das beim aussetzen des Brockers eine Möglichkeit geben sollte um einen Ausweg zu fahren.

Gruß Ralf

void onMqttMessage(int messageSize)
{
  const uint32_t timeOut = 1000;
  uint32_t startZeit = millis();
  buff = "";
  // we received a message, print out the topic and contents
  //Serial.print("Received a message with topic '");
  //Serial.print(mqttClient.messageTopic());
  //Serial.print("', length ");
  //Serial.print(messageSize);
  //Serial.println(" bytes:");

  // use the Stream interface to print the contents
  while (mqttClient.available() &&
         millis() - startZeit < timeOut)
  {
    char c = mqttClient.read();
    buff += c;
  }

  soc = buff.toInt();
  lauflicht();
}
1 Like

Schaut interessant aus. Teste ich morgen.

Danke !!!

ist nur eine Notlösung.
Du hast mit

etwas drin, was Dir auf die Füsse fallen kann.
Machen wir aber dann....

Danke, bin daran interessiert.

Wenn der Broker mehr sendet, als in buf passt, kommt es zum Überlauf.
Da kann alles mögliche passieren - bis hin zu irgendwelchen anderen Variablen die überschrieben werden...

Aber teste das erst mal mit dem Timeout - dann bau ich Dir das.

Hi,
also das mit dem Timer, funktioniert so nicht.
Ich habe noch ein Serial.print("-"); hinter den Variablen eingeschoben, es taucht nicht auf wenn ich das Python-Script zum Test, senden abschalte.
Der Broker läuft, jedoch wird nichts in den Broker zum versenden geschoben und somit wartet scheinbar mqttClient.poll();.

Ich glaube das mqttClient.poll(); auf eine Info vom Broker wartet. Und somit steht mein Code.

#include <ArduinoMqttClient.h>
//#include <Ethernet.h>
#include <WiFi.h>

const char ssid[] = "xxx";
const char password[] = "xxx?";
const char hostname[] = "xxx";
WiFiClient wlan;

//Ethernet
//const char hostname[] = "xxx";
//EthernetClient lanclient;

//MQTT
MqttClient mqttClient(wlan);
const char broker[] = "xxx";
int port = 1883;
const char topic[] = "xxx";


//LED
const int StatusLed[] = { LED_D0, LED_D1, LED_D2, LED_D3 };

const int SocSchaltpunkt[] = { 20, 50};  // SOC-Schaltpunkt
const int NUM_LED_and_Relais = 4;

//Inputs
const int Eingang[] = { A0, A1, A2 };
const int NUM_PINS = 3;

// Relais
int relais[] = { D0, D1, D2, D3 };

String buff = "";
int soc = 0;
int stufe = 2;
int umschaltsperre = 0;
int speicherMin = 80;



void setup() {
  Serial.begin(9600);
  // Initialize LED_BUILTIN as an output
  pinMode(LED_RESET, OUTPUT);
  pinMode(LED_USER, OUTPUT);
  // Initialize LED_D0-D3 as an output
  for (int i = 0; i < NUM_LED_and_Relais; i++) {
    pinMode(StatusLed[i], OUTPUT);
    pinMode(relais[i], OUTPUT);
  }
  pinMode(BTN_USER, INPUT);

  for (int i = 0; i < NUM_PINS; i++) {
    pinMode(Eingang[i], INPUT);
  }

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    digitalWrite(LED_RESET, HIGH);
    delay(500);
    digitalWrite(LED_RESET, LOW);
    delay(500);
  }
  Serial.println("WiFi verbunden");


  // Ethernet
  //Ethernet.setHostname(hostname);
  //Ethernet.begin();

  // Connect to MQTT broker
  mqttClient.connect(broker, port);
  mqttClient.subscribe("soc");
  // set the message receive callback
  mqttClient.onMessage(onMqttMessage);
}



void loop() {


  //Steuerung, mqtt-Abfrage einschalten
  if (digitalRead(Eingang[0]) == HIGH) {
    if (!mqttClient.connected()) {
      Serial.print("MQTT connection failed! Error code = ");
      Serial.println(mqttClient.connectError());
      delay(5000);
      soc = 0;
      digitalWrite(LED_USER, HIGH);
    } else if (mqttClient.connected()) {
      mqttClient.poll();
      digitalWrite(LED_USER, LOW);
    }
  } else {
    soc = 0;
  }


  //Ladestärke UMschaltung 2 Stufen
  if (digitalRead(Eingang[1]) == LOW) { umschaltsperre = 0; }

  if (digitalRead(Eingang[1]) == HIGH && stufe == 1 && umschaltsperre == 0) {
    digitalWrite(relais[1], HIGH);
    delay(500);
    digitalWrite(relais[1], LOW);
    stufe = 2;
    umschaltsperre = 1;
  }
  if (digitalRead(Eingang[1]) == HIGH && stufe == 2 && umschaltsperre == 0) {
    digitalWrite(relais[1], HIGH);
    delay(500);
    digitalWrite(relais[1], LOW);
    delay(500);
    digitalWrite(relais[1], HIGH);
    delay(500);
    digitalWrite(relais[1], LOW);

    stufe = 1;
    umschaltsperre = 1;
  }

  if (digitalRead(Eingang[2]) == HIGH) {
    speicherMin = SocSchaltpunkt[0];

  } else {
    speicherMin = SocSchaltpunkt[1];;
  }


  // Freigabe zum Laden
  if (speicherMin <= soc) {
    digitalWrite(relais[0], HIGH);
  } else if (speicherMin - 1 > soc) {
    digitalWrite(relais[0], LOW);
  }

  if (digitalRead(relais[0]) == HIGH) {
    digitalWrite(StatusLed[0], HIGH);
  } else {
    digitalWrite(StatusLed[0], LOW);
  }

  if (digitalRead(relais[1]) == HIGH) {
    digitalWrite(StatusLed[1], HIGH);
  } else {
    digitalWrite(StatusLed[1], LOW);
  }

  if (digitalRead(relais[2]) == HIGH) {
    digitalWrite(StatusLed[2], HIGH);
  } else {
    digitalWrite(StatusLed[2], LOW);
  }

  if (digitalRead(relais[3]) == HIGH) {
    digitalWrite(StatusLed[3], HIGH);
  } else {
    digitalWrite(StatusLed[3], LOW);
  }
}

void onMqttMessage(int messageSize) {
  const uint32_t timeOut = 1000;
  uint32_t startZeit = millis();

  Serial.println(startZeit);
  buff = "";
  // we received a message, print out the topic and contents
  //Serial.print("Received a message with topic '");
  //Serial.print(mqttClient.messageTopic());
  //Serial.print("', length ");
  //Serial.print(messageSize);
  //Serial.println(" bytes:");

  // use the Stream interface to print the contents
  while (mqttClient.available() &&
         millis() - startZeit < timeOut)
  {
    char c = mqttClient.read();
    buff += c;
    Serial.print("+");
  }
  soc = buff.toInt();
  lauflicht();
}


void lauflicht() {
  delay(100);
  digitalWrite(StatusLed[0], LOW);
  digitalWrite(StatusLed[1], LOW);
  digitalWrite(StatusLed[2], LOW);
  digitalWrite(StatusLed[3], LOW);
  delay(100);
  digitalWrite(StatusLed[0], HIGH);
  delay(25);
  digitalWrite(StatusLed[1], HIGH);
  delay(25);
  digitalWrite(StatusLed[2], HIGH);
  digitalWrite(StatusLed[0], LOW);
  delay(25);
  digitalWrite(StatusLed[3], HIGH);
  digitalWrite(StatusLed[1], LOW);
  delay(25);
  digitalWrite(StatusLed[2], LOW);
  digitalWrite(StatusLed[3], LOW);
  delay(25);
}



Eigentlich nicht. Ich kenn zwar diese Bibliothek nicht. Aber eine andere (pubsubclient) nutzt auch eine ähnliche Funktion. Diese Funktion sollte kontinuierlich im Loop aufgerufen werden.

Bei dir wird die Funktion aber nur aufgerufen, wenn Eingang[0] HIGH ist. Das kann ein Fehler sein.

Hallo, Ralle66!
Ich hatte ein ähnliches Problem.
Füge eine Überprüfung des Verbindungsstatus hinzu:

Dadurch wird verhindert, dass das Python-Skript bei einer Unterbrechung der Verbindung einfriert

if (!client.connected()) {
    reconnect();
} else {
    // Daten senden
    Serial.print("-");  // Ihre Debug-Ausgabe
}

Verwenden Sie für das nächste Mal eine nicht blockierende, asynchrone MQTT-Bibliothek wie den neuen und verbesserten AsyncMqttClient. So verwenden Sie ihn async-mqtt-client/examples/FullyFeatured-ESP32/FullyFeatured-ESP32.ino at master · marvinroger/async-mqtt-client · GitHub

Ich glaub Deine delay()s brechen Dir das Genick.
Ohne waa genaueres jetzt direkt sagen zu können, aber Du hast da mehrere Dinge, die arg komisch aussehen.
Ich schau nachher mal drauf, wenn sich noch etwas Zeit findet.

Sage mal, auf was für einem board soll das laufen und wo kommen die Konstanten her?

Board ist ein Finder Opta... So etwas wie eine Siemens Logo nur eben mit Arduino

1 Like

Hätt ich drauf kommen müssen :man_facepalming: wegen der USER_LED :slight_smile:
Na mal sehen...

@Plumps
Dieser Teil funktioniert und steht aktuell immer auf HIGH :wink:

Ich hab mal kurz in die lib geschaut und halte das ganze construct um den mqttClient.poll(); für überflüssig.

Dann hast Du beim connect im setup() keine Routine dabei, wenn es keinen connect gibt. Die würde ich nicht raus lassen....

Mir ist noch nicht ganz klar, was Du mit den 4 LED's veranstaltest.

Zum einen lässt Du Dir die Zustände der Relais ausgeben, aber im gleichem Atemzug bastelst Du ein Lauflicht drauf...

Ich würde den ganzen Kram mal weg lassen und nur auf das notwendigste mit dem example "WifiSimpleReceive" zurück gehen und mit geänderten Zugangs und Brokerdaten versuchen, ob es überhaupt eine Verarbeitung gibt und dann von dort aus loslegen.

Ich habe Deinen mal bis hierhin umgebaut - noch nicht fertig, aber ich brauch den Rechner jetzt :slight_smile:

#include <ArduinoMqttClient.h>
//#include <Ethernet.h>
#include <WiFi.h>

const char ssid[] = "xxx";
const char password[] = "xxx?";
const char hostname[] = "xxx";
WiFiClient wlan;

//Ethernet
//const char hostname[] = "xxx";
//EthernetClient lanclient;

//MQTT
MqttClient mqttClient(wlan);
const char broker[] = "xxx";
int port = 1883;
const char topic[] = "xxx";

//LED
const int StatusLed[] = { LED_D0, LED_D1, LED_D2, LED_D3 };

const int SocSchaltpunkt[] = { 20, 50};  // SOC-Schaltpunkt
const int NUM_LED_and_Relais = 4;

//Inputs
const int Eingang[] = { A0, A1, A2 };
const int NUM_PINS = 3;

// Relais
int relais[] = { D0, D1, D2, D3 };

String buff = "";
int soc = 0;
int stufe = 2;
int umschaltsperre = 0;
int speicherMin = 80;

void setup()
{
  Serial.begin(9600);
  // Initialize LED_BUILTIN as an output
  pinMode(LED_RESET, OUTPUT);
  pinMode(LED_USER, OUTPUT);

  // Initialize LED_D0-D3 as an output
  for (int i = 0; i < NUM_LED_and_Relais; i++)
  {
    pinMode(StatusLed[i], OUTPUT);
    pinMode(relais[i], OUTPUT);
  }

  pinMode(BTN_USER, INPUT);

  for (int i = 0; i < NUM_PINS; i++)
  {
    pinMode(Eingang[i], INPUT);
  }

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED)
  {
    digitalWrite(LED_RESET, HIGH);
    delay(500);
    digitalWrite(LED_RESET, LOW);
    delay(500);
  }

  Serial.println("WiFi verbunden");
  // Ethernet
  //Ethernet.setHostname(hostname);
  //Ethernet.begin();
  // Connect to MQTT broker
  Serial.print("MQTT connection ");

  if (!mqttClient.connect(broker, port))
  {
    Serial.print("failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }
  else
  {
    Serial.println("succesfull");
  }

  Serial.print("MQTT Subscribe: ");
  Serial.println(mqttClient.subscribe("soc"));
  // set the message receive callback
  mqttClient.onMessage(onMqttMessage);
}

void getMQTTConnect()
{
  //Steuerung, mqtt-Abfrage einschalten
  if (mqttClient.connected())
  {
    digitalWrite(LED_USER, LOW);
  }
  else
  {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    digitalWrite(LED_USER, HIGH);
    delay(5000);
    soc = 0;
  }
}

void loadType()
{
  if (digitalRead(Eingang[1]) == LOW)
  {
    umschaltsperre = 0;
  }

  if (umschaltsperre == 0)
  {
    switch (stufe)
    {
      case 1:
        digitalWrite(relais[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        stufe = 2;
        umschaltsperre = 1;
        break;

      case 2:
        digitalWrite(relais[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        delay(500);
        digitalWrite(relais[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        stufe = 1;
        umschaltsperre = 1;
        break;

      default:
        stufe = 1;
        break;
    }
  }
}

void lauflicht()
{
  digitalWrite(StatusLed[0], LOW);
  digitalWrite(StatusLed[1], LOW);
  digitalWrite(StatusLed[2], LOW);
  digitalWrite(StatusLed[3], LOW);
  delay(100);
  digitalWrite(StatusLed[0], HIGH);
  delay(25);
  digitalWrite(StatusLed[1], HIGH);
  delay(25);
  digitalWrite(StatusLed[2], HIGH);
  digitalWrite(StatusLed[0], LOW);
  delay(25);
  digitalWrite(StatusLed[3], HIGH);
  digitalWrite(StatusLed[1], LOW);
  delay(25);
  digitalWrite(StatusLed[2], LOW);
  digitalWrite(StatusLed[3], LOW);
}

void onMqttMessage(int messageSize)
{
  const uint32_t timeOut = 1000;
  uint32_t startZeit = millis();
  uint8_t idx = 0;
  Serial.println(startZeit);
  buff = "";
  // we received a message, print out the topic and contents
  //Serial.print("Received a message with topic '");
  //Serial.print(mqttClient.messageTopic());
  //Serial.print("', length ");
  //Serial.print(messageSize);
  //Serial.println(" bytes:");

  // use the Stream interface to print the contents
  while (mqttClient.available() &&
         idx < messageSize &&
         millis() - startZeit < timeOut
        )
  {
    char c = mqttClient.read();
    buff += c;
    idx++;
    Serial.print(idx); Serial.print(", ");
  }

  soc = buff.toInt();
  lauflicht();
}

void loop()
{
  if (digitalRead(Eingang[0]) == HIGH)
  {
    mqttClient.poll();
    getMQTTConnect();
    loadType();
  }
  else
  {
    soc = 0;
  }

  // Freigabe zum Laden
  if (speicherMin <= soc)
  { digitalWrite(relais[0], HIGH); }
  else if (speicherMin - 1 > soc)
  { digitalWrite(relais[0], LOW); }

  for (byte b = 0; b < NUM_LED_and_Relais; b++)
  {
    digitalWrite(StatusLed[b], digitalRead(relais[b]));
  }
}
1 Like

@my_xy_projekt

Hi, ich habe deinen Code mal fix in den Opta geladen und den Broker nicht mit Information zum versenden versorgt.
Der Opta läuft, klickt ein wenig hin und her, was ja nicht das Problem ist, aber es läuft durch.
Die mqtt-Abfrage stört jetzt nicht mehr den Ablauf.
Hast du fein gemacht :slight_smile:

Was bezwecke ich mit meinem Code überhaupt.

Es soll eine Steuerung meiner Laderegelung vom E-Auto werden.

digitalRead(Eingang[0]

  • Freigabe zum Laden

digitalRead(Eingang[1] =

  • Auswahl des Ladestromes 10A = 1x klicken
  • Auswahl des Ladestromes 16A = 2x klicken
  • eventuell wird dies noch über den Hausverbrauch geregelt

digitalRead(Eingang[2]

  • wie weit darf der Speicher im Haus aus entladen werden. 20 oder 50%

Relais 0

  • Freigabe für Ladesteuerung

Relais 1

  • Steuerungsimpuls für Ladestufe der Ladesteurung

Und ja, Lauflicht sieht geil aus, aber es stört :slight_smile:

Das hat auch noch keiner zu mir gesagt :joy:

Ok, wenn ich jetzt weiss, was das wird, kann ich ja ggfls. nochmal drauf schaun.
Das Klackern der relais ist richtig, das kann man lösen.

Wenn ich den nochmal aufnehme..., um das sinnvoll zu machen brauch ich mal ein paar Infos:

Ist das ein Schalter oder ein Taster?

Und wie sind die Taster/Schalter verkabelt?
Einfach wärs, wenn die nur nach GND auslösen.

Mit dem Wissen lässt sich jetzt auch sinnvoll mit den Relais und LED's umgehen :wink: