MQTT2 - Taster über ESP8266 einbinden -> connection lost

Begonnen von Leinad, 06 Dezember 2023, 10:53:21

Vorheriges Thema - Nächstes Thema

Leinad

Hallo zusammen,

ich möchte über einen ESP8266 eine Aussenklingel mit Torüberwachung realisieren.

Nach Recherchen im Internet und herumprobieren konnte ich einen Code zusammentragen, der grundsätzlich funktioniert.

Das Problem scheint jedoch, dass beim Absetzen des Befehls an FHEM (MQTT2) gerade die Verbindung nicht richtig steht und dadurch die Information in FHEM nicht ankommt. In meinem Beispiel, wird das Kommando nur einmal abgesetzt, da anschließend die Bedingung für den ESP erfüllt ist. Sollte ich hier ansetzen?

Meine Fragen dazu:

1)Steht bei MQTT mit ESP die Verbindung dauerhaft, oder wird erst beim Auslösen eines Ereignisses, die Verbindung zum Server aufgebaut? (Ich würde bei meinem Codebeispiel davon ausgehen, dass die Verbindung dauerhaft steht?

2) Habt ihr einen Verbesserungsvorschlag für meinen Code? Im Idealfall würde der ESP ja prüfen, ob das Kommando bei FHEM angekommen ist. Also Rückantwort, wie könnte ich sowas einfach umsetzen?

Hat jemand Ideen oder im Idealfall Codeschnipsel, die ich mir ansehen kann?




Hier noch mein Code auf dem ESP:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
//###########################################################################
#define button0 4   
#define button2 5
#define mqtt_user "XXXXXXX" //MQTT Broker User
#define mqtt_password "xXXXXXX" //MQTT Broker Password
//###########################################################################
// Wifi
const char* ssid = "XXXXXXXXXXXXXXX"; //WLAN SSID
const char* password = "XXXXXXXXXXXX"; //WLAN Password
IPAddress ip(XXXXXXXXXX); //Anzupassen
IPAddress gateway(xxxxxxxxx);
IPAddress subnet(255,255,255,0);

// MQTT
const char* mqtt_server = "xxxxxxxxxxx"; //IP Address MQTT Broker
const char* mqtt_clientId = "fence";
const char* outTopicTor = "fence/Tor";
const char* outTopicVCC = "fence/vcc";
const char* outTopicKlingel= "fence/Klingel";
int Tor_state = 0;
int Klingel_state = 0;
long previousMillis = 0;

// Misc
char msg[50];                       // message for mqtt publish
//###########################################################################

ADC_MODE (ADC_VCC);                 // VCC Read

WiFiClient espClient;
PubSubClient client(espClient);

void setup(){

  pinMode(button0, INPUT);
  pinMode(button2, INPUT); 
                         
  Serial.begin(115200); 

// Setup Wifi
  setup_wifi();

// Setup MQTT
  client.setServer(mqtt_server, 1883);
}

void setup_wifi() {
  int wifiCounter = 0;
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet);

  while (WiFi.status() != WL_CONNECTED) {
    if(wifiCounter < 100){
      delay(500);
      Serial.print(".");
    }else{}
    wifiCounter++;
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");
    // Client ID connected
    if (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.print(mqtt_clientId);
      Serial.println(" connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

//###########################################################################

void loop(){
  // MQTT Client
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
// Read the VCC from Battery
  float vcc = ESP.getVcc() / 1000.0;
  vcc = vcc - 0.12;     // correction value from VCC



 // unsigned long Millis = millis();
 // if (Millis - previousMillis >= 1000)
 // {
 //   previousMillis = Millis;
 // }
 
  if (!client.connected())
  {
    reconnect();
  }
  client.loop();
 
  if(digitalRead(button0) == LOW)
  {
    if(Tor_state == 1)
    {
      client.publish(outTopicTor, "false");
      Tor_state = 0;
      Serial.println("Tor false");
      delay(50);
      dtostrf(vcc, sizeof(vcc), 2, msg);
      client.publish(outTopicVCC, msg);
      delay(50);
    }
  }
 
  if(digitalRead(button0) == HIGH)
  {
    if(Tor_state == 0)
    {
   
      client.publish(outTopicTor, "true");
      Tor_state = 1;
      Serial.println("Tor true");
      delay(50);
      dtostrf(vcc, sizeof(vcc), 2, msg);
      client.publish(outTopicVCC, msg);
      delay(50);
    }
  }

if(digitalRead(button2) == LOW)
  {
    if(Klingel_state == 1)
    {
     
      client.publish(outTopicKlingel, "false");
      Klingel_state = 0;
      Serial.println("Klingel false");
      delay(50);
      dtostrf(vcc, sizeof(vcc), 2, msg);
      client.publish(outTopicVCC, msg);
      delay(50);
    }
  }
 
  if(digitalRead(button2) == HIGH)
  {
    if(Klingel_state == 0)
    {
 
      client.publish(outTopicKlingel, "true");
      Klingel_state = 1;
      Serial.println("Klingel true");
      delay(50);
      dtostrf(vcc, sizeof(vcc), 2, msg);
      client.publish(outTopicVCC, msg);
      delay(50);
    }
  }
      dtostrf(vcc, sizeof(vcc), 2, msg);
      client.publish(outTopicVCC, msg);
      delay(50);
}

rabehd

Zitat von: Leinad am 06 Dezember 2023, 10:53:211)Steht bei MQTT mit ESP die Verbindung dauerhaft, oder wird erst beim Auslösen eines Ereignisses, die Verbindung zum Server aufgebaut?
Das mußt Du festlegen. Wenn der ESP schlafen darf, dann wohl nicht. Eine Prüfung der Verbindung vor dem Senden ist nicht falsch.
Auch funktionierende Lösungen kann man hinterfragen.

betateilchen

Zitat von: Leinad am 06 Dezember 2023, 10:53:21Nach Recherchen im Internet und herumprobieren konnte ich einen Code zusammentragen, der grundsätzlich funktioniert.

Naja, das "Zusammentragen von Code" hat noch nie zu wirklich stabilen Ergebnissen geführt, so auch hier. Offenbar fehlt einfach das Grundverständnis dafür, was man da zusammengetragen hat und was da im Code eigentlich passiert.

  • die Überprüfung, ob die MQTT Verbindung überhaupt noch besteht, ist in deiner loop() doppelt und direkt nacheinander vorhanden. Macht keinen Sinn.
  • das publish der Batteriespannung kommt insgesamt 5 Mal in Deinem code vor - warum? es reicht doch einmal.
  • Du flutest den MQTT Server mit viel zu vielen publishes. Bei jedem (!) Durchlauf durch loop() schickst Du ein publish mit der Batteriespannung. Das passiert also pro Sekunde mehrere tausend Mal - ein solches Bombardement hält kein Server lange aus, da darfst Du Dich nicht wundern, wenn die Verbindung abbricht.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

#3
Probiers mal so:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
//###########################################################################
#define button0 4   
#define button2 5
#define mqtt_user "XXXXXXX" //MQTT Broker User
#define mqtt_password "xXXXXXX" //MQTT Broker Password
//###########################################################################
// Wifi
const char* ssid = "XXXXXXXXXXXXXXX"; //WLAN SSID
const char* password = "XXXXXXXXXXXX"; //WLAN Password
IPAddress ip(XXXXXXXXXX); //Anzupassen
IPAddress gateway(xxxxxxxxx);
IPAddress subnet(255,255,255,0);

// MQTT
const char* mqtt_server = "xxxxxxxxxxx"; //IP Address MQTT Broker
const char* mqtt_clientId = "fence";
const char* outTopicTor = "fence/Tor";
const char* outTopicVCC = "fence/vcc";
const char* outTopicKlingel= "fence/Klingel";
int Tor_state = 0;
int Klingel_state = 0;
long previousMillis = 0;

// Misc
char msg[50];                       // message for mqtt publish
//###########################################################################

ADC_MODE (ADC_VCC);                 // VCC Read

WiFiClient espClient;
PubSubClient client(espClient);

void setup(){

  pinMode(button0, INPUT);
  pinMode(button2, INPUT);

  Serial.begin(115200);

  // Setup Wifi
  setup_wifi();

  // Setup MQTT
  client.setServer(mqtt_server, 1883);
}

void setup_wifi() {
  int wifiCounter = 0;
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet);

  while (WiFi.status() != WL_CONNECTED) {
    if(wifiCounter < 100){
      delay(500);
      Serial.print(".");
    }
    wifiCounter++;
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");
    // Client ID connected
    if (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.print(mqtt_clientId);
      Serial.println(" connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

//###########################################################################

void loop(){
  // MQTT Client
  if (!client.connected()) { reconnect(); }
  client.loop();

  if (millis() - previousMillis >= 180000) { // send battery voltage every 3 minutes
    previousMillis = millis();
    // Read the VCC from Battery
    float vcc = ESP.getVcc() / 1000.0;
    // correction value from VCC
    vcc -= .12;     
    dtostrf(vcc, sizeof(vcc), 2, msg);
    client.publish(outTopicVCC, msg);
  }

if(digitalRead(button0) == LOW && Tor_state == 1) {
client.publish(outTopicTor, "false");
Tor_state = 0;
Serial.println("Tor false");
}

if(digitalRead(button0) == HIGH && Tor_state == 0) {
client.publish(outTopicTor, "true");
Tor_state = 1;
Serial.println("Tor true");
}

if(digitalRead(button2) == LOW && Klingel_state == 1) {
client.publish(outTopicKlingel, "false");
Klingel_state = 0;
Serial.println("Klingel false");
}

if(digitalRead(button2) == HIGH && Klingel_state == 0) {
client.publish(outTopicKlingel, "true");
Klingel_state = 1;
Serial.println("Klingel true");
}

}

Der Code ist noch nicht endgültig optimiert, aber doch schon um einiges übersichtlicher als Dein Original.
Beispielsweise würde ich die beiden xxx_state nicht als int definieren, sondern als boolean, das würde bei den Abfragen noch einiges einfacher machen.
Außerdem würde ich auch die reconnects nonblocking ausführen, aber das sind Details.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Leinad

#4
Danke für deine Antwort!

Ich habe mich heute noch etwas reingefuchst und auch deine Antwort berücksichtigt. Die größte Änderung ist allerdings, dass ich nun oneButton.h verwende, um auch zwischen kurzen und langen Tastendrücken zu unterscheiden. Im SerialMonitor funktioniert das ganze einwandfrei. Über MQTT habe ich leider die gleichen Probleme wie mit dem alten Code. (D.h. es funktioniert nur sporadisch, und hängt sich scheinbar dann auf, wobei die Ausgaben im SerialMonitor weiterhin ankommen und Ok aussehen.)

Als nächstes werde ich wohl einen externen MQTT Server testen, habe die Vermutung, dass es an meiner FHEM Installation liegt?


Vielleicht hast du noch einen Tip?

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
#include <OneButton.h>

//###########################################################################
#define input1 4   
#define input2 0
#define mqtt_user "xx" //MQTT Broker User
#define mqtt_password "xx" //MQTT Broker Password
//###########################################################################

// Wifi
const char* ssid = "xxx"; //WLAN SSID
const char* password = "xxx"; //WLAN Password
IPAddress ip(192,1x,x,x); //Anzupassen
IPAddress gateway(192,x,x,x);
IPAddress subnet(255,255,255,0);

// MQTT
const char* mqtt_server = "192.x.x.x"; //IP Address MQTT Broker
const char* mqtt_clientId = "fence";
const char* outTopicButton1 = "fence/Tor";
const char* outTopicButton2= "fence/Klingel";
const char* outTopicVCC = "fence/vcc";
char msg[50];                       // message for mqtt publish

// Misc
float vcc = 3.3;

unsigned long previousMillis = 0;
const long interval = 300000;


OneButton button1 (input1, true);
OneButton button2 (input2, true);

//###########################################################################

ADC_MODE (ADC_VCC);                 // VCC Read

WiFiClient espClient;
PubSubClient client(espClient);
   

void setup(){
  Serial.begin(115200); 
 
  pinMode(input1, INPUT_PULLUP);
  pinMode(input2, INPUT_PULLUP); 


button1.attachClick(clickedButton1);
button2.attachClick(clickedButton2);
button1.attachLongPressStart(longPressButton1);
button2.attachLongPressStart(longPressButton2);

 
// Setup Wifi
  setup_wifi();

// Setup MQTT
  client.setServer(mqtt_server, 1883);
}

void setup_wifi() {
  int wifiCounter = 0;
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet);

  while (WiFi.status() != WL_CONNECTED) {
    if(wifiCounter < 100){
      delay(500);
      Serial.print(".");
    }else{}
    wifiCounter++;
  }
}

 
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");
    // Client ID connected
    if (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) {
      Serial.print(mqtt_clientId);
      Serial.println(" connected");
      // Once connected, publish an announcement...
      delay(50);
      client.publish("outTopic", "connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


void clickedButton1(){   
      client.publish(outTopicButton1, "click_false");
      Serial.println("click1 false");
      delay(50);
    }

void clickedButton2(){
  client.publish(outTopicButton2, "click_false");
      Serial.println("click2 false");
      delay(50);
}

void longPressButton1(){
  client.publish(outTopicButton1, "long_false");
      Serial.println("long1 false");
      delay(50);
}


void longPressButton2(){
  client.publish(outTopicButton2, "long_false");
      Serial.println("long2 false");
      delay(50);
}



//###########################################################################

void loop(){
  // MQTT Client
  if (!client.connected()) {
    reconnect();
  }

// Read the VCC from Battery
  vcc = ESP.getVcc() / 1000.0;
  vcc = vcc - 0.12;     // correction value from VCC

      button1.tick();
      button2.tick();


unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      dtostrf(vcc, sizeof(vcc), 2, msg);
      client.publish(outTopicVCC, msg);
      Serial.println(vcc);
      delay(50);
  }

   if (WiFi.status() != WL_CONNECTED){
    Serial.println("lost WiFi");
    delay(50);
   }
  }

 

 

betateilchen

Zitat von: Leinad am 06 Dezember 2023, 21:07:50Vielleicht hast du noch einen Tip?

Ja, aber eigentlich habe ich keine Lust mehr.

Anstatt erstmal Schritt für Schritt vorzugehen und die Grundaufgabe vernünftig zu lösen, baust Du plötzlich noch eine externe Library ein, die im Moment überhaupt nicht notwendig gewesen wäre.

So wirst Du vermutlich nicht wirklich weiterkommen, auch nicht mit einem externen mqtt-Server.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Leinad

#6
Zitat von: betateilchen am 06 Dezember 2023, 22:14:29
Zitat von: Leinad am 06 Dezember 2023, 21:07:50Vielleicht hast du noch einen Tip?

Ja, aber eigentlich habe ich keine Lust mehr.



Ok,  danke trotzdem. Werd mal schauen wie ich weiter vorgehe.

DasQ

Fhem on MacMini/Ubuntu.
Absoluter Befürworter der Konsequenten-Kleinschreibung https://de.wikipedia.org/wiki/Kleinschreibung
Infos zu Klimawandel http://www.globalcarbonatlas.org

Leinad

#8
Zitat von: DasQ am 07 Dezember 2023, 18:11:45Probier mal ESPeasy

Hi, danke für deine Antwort. Ich habe es mittlerweile am laufen.

Im loop hat ein delay gefehlt, die ESP reagieren da scheinbar etwas merkwürdig.
 

DasQ

Und ich würde auf delay in Gänze verzichten :'( .


Man muß nicht ständig das Rad neu erfinden. Zum lernen mag das ok sein ...
Fhem on MacMini/Ubuntu.
Absoluter Befürworter der Konsequenten-Kleinschreibung https://de.wikipedia.org/wiki/Kleinschreibung
Infos zu Klimawandel http://www.globalcarbonatlas.org

betateilchen

Zitat von: DasQ am 08 Dezember 2023, 13:05:49Und ich würde auf delay in Gänze verzichten

Ich auch, stattdessen würde ich einfach ein yield(); am Ende in die loop() setzen.

Aber dazu müsste man das eigentliche Problem verstanden haben, anstatt nur mit copy&paste irgendwas zusammenzufrickeln.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

DasQ

Das mit dem delay (aus Blink) ist wie JavaScript

Hast damit einmal angefangen, biste auf ewig versaut. ;D
Fhem on MacMini/Ubuntu.
Absoluter Befürworter der Konsequenten-Kleinschreibung https://de.wikipedia.org/wiki/Kleinschreibung
Infos zu Klimawandel http://www.globalcarbonatlas.org

betateilchen

Zitat von: DasQ am 08 Dezember 2023, 13:27:36Das mit dem delay (aus Blink) ist wie JavaScript

Dinge, die die Welt nicht braucht...
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Beta-User

Zitat von: DasQ am 08 Dezember 2023, 13:27:36Das mit dem delay (aus Blink) ist wie JavaScript

Hast damit einmal angefangen, biste auf ewig versaut. ;D
Noch schöner ist nur noch sleep(), besonders, wenn man es mit millis() verbindet...

*duckundweg*
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files