MQTT Pushbutton mit ESP-01

Hallöchen,

ich versuche schon seit Tagen einen Pushbutton zu Basteln.
Als Basis dient dieser Code:

Grundsätzlich funktioniert das ganze. Doch leider schickt er bei einem Tastendruck BEIDE Befehle an den MQTT Broker. Also er schickt ON und dann direkt OFF.

Nun dachte ich mir:

  1. Ich speichere den letzten Wert (ON oder OFF) in eine Variable in den ESP. Diese sollte ja solange leben bleiben bis die Batterie leer ist.

oder

  1. Ich rufe den MQTT Topic mit dem aktuelen Status ab (ON oder OFF) und lasse den entsprechend Befehle per IF-Schleife den gegengesetzt Befehl senden, bei ON sende OFF usw.

Ich habe mich an beiden sachen bereits versucht. Variante 1 war mir zu kompliziert und kann nicht mal sagen ob das überhaupt geht.

Variante 2 hat da mehr gefruchtet. Ich konnte das Topic abfragen, und das ergebnis in eine Variable geschrieben. Tja.. Doch in den Rules unten bei case konnte ich das nicht umsetzten, weil er den Callback vom MQTT wohl NACH den Rules ausgeführt hat und somit hat er immer ein ON gesendet...

Jetzt bin ich mit meinem Latain am Ende.
Ich merke an: Ich bin FiSi und lernwillig und habe mich mit Arduino und der Sprache dazu erst seit ein paar tagen beschäftig, doch nun bin ich am Ende und habe aus Frust alles verworfen und meinen Code gelöscht -.-

Dann habe ich es mit ESPEasy versucht, damit funktioniert es, doch da bekomme ich den ESP aus dem DeepSleep nicht mehr raus. Und das liegt an dem ESP-01. Aber das gehört hier nicht hin.

Hat jemand einen heißen Tipp für mich? Hab ich einen Denkfehler?
Oder kann mir jemand sogar den Code etwas umbasteln, dass Variante 1 oder 2 ausgeführt wird?
Danke!!

Hi

    case 1:    // Give out the message "ON"
        client.publish(outTopicMsg, "ON");
        Serial.println("Send: ON");
        state = 2;
      break;
    case 2:    // Give out the message "OFF"
        client.publish(outTopicMsg, "OFF");
        Serial.println("Send: OFF");
        state = 3;
      break;

Das ist ein Auszug aus der switch.
Was denkst Du, passiert, wenn case 1 zutrifft?
Ja, Es wird 'ON' gesendet und der status auf 3 2 umgestellt.
Was denkst Du passiert, wenn wir in 0,2344323 Sekunden hier wieder vorbei kommen?
Ich denke, daß dann der Status OFF gesendet wird.
Die gleiche Zeit später gibt's die Spannung und noch etwas später geht's ins Bett.

Wo hier Rules sind oder wie MQTT im Allgemeinen abläuft - keine Ahnung, aber der Switch Block MUSS den Kram direkt nacheinander so ausgeben - steht ja so da.
Einzig das delay(100) begrenzt die Ausgabe zeitlich etwas.

MfG

Edit
Der Status wird im case auf Zwei, nicht Drei (wie ich Es schrieb) gesetzt.
Dadurch laufen die einzelnen Status auch nacheinander ab, sobald Diese 'losgelöst' wurden.

Sorry. Entweder habe ich gerade Hirnfrost oder ich raff es einfach nicht.

Da fällt mir ein... Kann ich bei der MQTT Abfrage nicht den switch-state auf 2 bzw. 1 setzen?!
Das ganze müsste dann im loop passieren... mhh. Ich muss da nochmal drüber nachdenken.

Hier nochmal mein Code mit MQTT Abfrage/subscribe.
Nun komme ich nicht weiter.

Damit der Ablauf im switch korrekt funktioniert, muss ich ja irgendwie den Variable state dauerhaft speichern. Dann kann ich ja mit einer if schleife die cases abarbeiten.

Also: Wie kann man eine Variable dauerhaft speichern?
Dann würde ich eine variable erstelllen z.B. mqtt_state und die dann abfragen, aber die muss dauerhaft abgespeichert werden. Bis eben die Batterie oder Stromversorgung weg ist. Muss den DeepSleep überstehen.

Hier der Code:

/*
 AndyW Dash Button V1
 23.02.2018
 by Andy Wolff
*/

//**********************************************************************
// INCLUDE
//**********************************************************************
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>

//**********************************************************************
// DEFINE
//**********************************************************************
#define LED 2               // GPIO2 - Onboard LED
#define SETUP_BUTTON 12     // Button for Webupdate

//**********************************************************************
// PARAMETER
//**********************************************************************
// Wifi
const char* host = "dashbutton-sz-light";
const char* ssid = "Headquarter";
const char* password = "XXXXXX";
// MQTT
const char* mqtt_server = "10.80.1.24";
const char* mqtt_clientId = "dashbutton-sz-light";
const char* outTopicMsg = "dashbutton-sz/light/state";
const char* outTopicVCC = "dashbutton-sz/light/vcc";
const char* outTopicCon = "dashbutton-sz/light/connect";
// Hardware
boolean mSetupButton = LOW;         // flag Setup Button
int ledState = HIGH;                // ledState used to set the LED
unsigned long previousMillis = 0;   // will store last time LED was updated
const long interval = 500;          // interval at which to blink (milliseconds)
long sendtime = 0;                  // sendtime
char msg[50];                       // message for mqtt publish
int state = 0;                      // for Statemachine

//**********************************************************************
// SETUP
//**********************************************************************
ADC_MODE (ADC_VCC);                 // VCC Read

ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

WiFiClient espClient;
PubSubClient client(espClient);

void setup(){ 
  pinMode(SETUP_BUTTON, INPUT_PULLUP);    // Webupdate Button
  pinMode(LED, OUTPUT);                   // Onboard LED on ESP-08S as Output                             
  sendtime = millis();                    
  Serial.begin(115200);  

// Setup Wifi
  setup_wifi();

// Setup MQTT
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  
// Setup httpUpdater
  MDNS.begin(host);
  httpUpdater.setup(&httpServer);
  httpServer.begin();
  MDNS.addService("http", "tcp", 80);
} 

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

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

//**********************************************************************
// LOOP
//**********************************************************************
void loop(){ 
  
  // HTTPServer Handle Client
  httpServer.handleClient();

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

  // LED blink when ESP is in Upload Mode
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if ((ledState == LOW) && (mSetupButton = HIGH)){
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    // set the LED with the ledState of the variable:
    digitalWrite(LED, ledState);
  } 

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

// StateMachine for send the telegram to MQTT
  switch (state) {
    case 0:    // SETUP
      if (digitalRead(SETUP_BUTTON) == LOW) {
        mSetupButton = HIGH;
        Serial.println("Webupdate started ...");
        Serial.printf("Open http://%s.local/update in your browser\n", host);
      } else {
        state = 1;
        Serial.println("No Webupdate...");
      }

      if (mSetupButton == HIGH){
        state = 0;
        Serial.println("Starting Webupdate...");
      }
      break;
    case 1:    // Give out the message "ON"
        client.publish(outTopicMsg, "1");
        Serial.println("Send: ON");
        state = 2;
      break;
    case 2:    // Give out the message "OFF"
        client.publish(outTopicMsg, "0");
        Serial.println("Send: OFF");
        state = 3;
      break;
    case 3:    // Give out the message of the State from VCC
        dtostrf(vcc, sizeof(vcc), 2, msg);
        client.publish(outTopicVCC, msg);
        Serial.print("VCC: ");
        Serial.print(msg);
        Serial.println("V");
        state = 4;
      break;
    case 4:    // Give out the Sendtime on Serial and go to Deepsleep  
        sendtime = millis() - sendtime;
        Serial.print("Sendtime: ");
        Serial.print(sendtime);
        Serial.println("ms");
        Serial.print("Good Night ...");
        ESP.deepSleep(0, WAKE_RFCAL);
      break;
  }
  delay(200);  // delay in between reads for stability 
}

Dein "switch/case" kann so auch nicht funktionieren. case beruft sich auf state, aber state wird erst in case gesetzt.

Das habe ich mir schon gedacht, das hatte mich schon sehr verwirrt.
Da frage ich mich wieso, dass so viele nutzen und keiner sich irgendwie dazu äußert.

Hat jemand noch eine Idee?

Ich versuche mich heute abend mal an den RTC Memory vom ESP und bastel was eigenes zusammen.

Etwas fortschritt. RTC war nicht der richtige weg. Machte kein Sinn.
Ich habe nun folgendes zusammengebaut:

//**********************************************************************
// INCLUDE
//**********************************************************************
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>

//**********************************************************************
// DEFINE
//**********************************************************************
#define LED 2               // GPIO2 - Onboard LED

//**********************************************************************
// PARAMETER
//**********************************************************************
// Wifi
const char* host = "dashbutton-sz-light";
const char* ssid = "Headquarter";
const char* password = "XXXXXXXXX";
// MQTT
const char* mqtt_server = "10.80.1.24";
const char* mqtt_clientId = "dashbutton-sz-light";
const char* outTopicMsg = "dashbutton-sz/light/state";
const char* outTopicVCC = "dashbutton-sz/light/vcc";
const char* outTopicCon = "dashbutton-sz/light/connect";
// Hardware
int ledState = HIGH;                // ledState used to set the LED
unsigned long previousMillis = 0;   // will store last time LED was updated
const long interval = 500;          // interval at which to blink (milliseconds)
long sendtime = 0;                  // sendtime
char msg[50];                       // message for mqtt publish
//int mqtt_state = 3;

//**********************************************************************
// SETUP
//**********************************************************************
ADC_MODE (ADC_VCC);                 // VCC Read

WiFiClient espClient;
PubSubClient client(espClient);

void setup(){ 
  pinMode(LED, OUTPUT);                   // Onboard LED on ESP-08S as Output                             
  sendtime = millis();                    
  Serial.begin(115200);  

// Setup Wifi
  setup_wifi();

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

}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

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

void callback(char* topic, byte* payload, unsigned int length) {
   String s = String((char*)payload);
   int mqtt_state = s.toInt();
   Serial.print("Actual State is: ");
   Serial.println(mqtt_state);
   // Read the VCC from Battery
   float vcc = ESP.getVcc() / 1000.0;
   vcc = vcc - 0.12;     // correction value from VCC
   dtostrf(vcc, sizeof(vcc), 2, msg);
   Serial.print("VCC: ");
   Serial.print(msg);
   Serial.println("V");
   Serial.print("Publishing VCC State to the MQTT Broker now.");
   client.publish(outTopicVCC, msg);
   //Set State and publish
   Serial.print("Setting State and publishing it to the MQTT Broker now. ");
   if (mqtt_state ==  0) {
      Serial.print("State is OFF. Turning ON. ");
      mqtt_state = 1;
      Serial.print("State is now: ");
      Serial.println(mqtt_state);
      sendtime = millis() - sendtime;
      Serial.print("Sendtime: ");
      Serial.print(sendtime);
      Serial.println("ms");
      Serial.print("Finished. Going to sleep now.");
      //ESP.deepSleep(0, WAKE_RFCAL);
   } else if (mqtt_state == 1) {
      Serial.print("State is ON. Turning OFF. ");
      mqtt_state = 0;
      Serial.print("State is now:");
      Serial.println(mqtt_state);
      sendtime = millis() - sendtime;
      Serial.print("Sendtime: ");
      Serial.print(sendtime);
      Serial.println("ms");
      Serial.print("Finished. Going to sleep now.");
      //ESP.deepSleep(0, WAKE_RFCAL);
   } else {
      Serial.print("ERROR: No vaild Value found. ");
      Serial.print("Finished with ERRORS. Going to sleep now.");
      //ESP.deepSleep(0, WAKE_RFCAL);
   }
}

//**********************************************************************
// LOOP
//**********************************************************************
void loop(){ 

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

  delay(500);
}

Zwei Probleme:

  1. Die Callback Funktion wird nur ausgelöst. Wenn eine MQTT Nachricht in das Topic eingeht.
    Wie kann ich die Funktion im loop aufrufen, dass er einfach das Topic ausliest. Es hat ja irgendein Wert, was mein Broker gespeichert hat.

  2. Der Wert in mqtt_state wird am anfang korrekt gespeichert. Dieser hat z.B. den Wert 0. Den schicke aktuell Manuell raus. Wenn ich nun die 1 an das Topic sende, dann kommt eine 13 raus. Wenn ich dann wieder eine 0 sende kommt eine 3. Wenn ich aber 00 oder 01 sende, dann passt es... Hier mal die Serial Console:

https://pastebin.com/H7JVGxjp

Da ihm die Antworten hier anscheinend nicht gefallen haben, versucht er es mal mit Crossposting.

Gruß Tommy

Na danke...
Zwei Foren = Verschiedene Leute = Verschiedene Anworten und Lösungen.
Und die Antwort im anderen Forum war ja klar und deutlich und habe neue Fragen bzw. um neue Hilfe gebeten.
Verstehe gerade ein Problem nicht.

Und DerkleinePunk hat schnell geantwortet und ich weiß nicht ob er in dem anderen Forum geantwortet. Ich bin auf jede Hilfe angewiesen und freue mich. Aber sowas muss nicht sein.

Hi

Ich weiß, wo Dein Problem ist ...

Zumindest könntest Du den potentiellen Helfern reinen Wein einschenken, daß Sie eventuell gar nicht mehr beachtet werden, da Du ja bereits seit einer Woche schon woanders Hilfe bekommen hast (Das wäre was für 'Nebenan') oder, daß Du ein weiteres Forum gefunden hast, wo Du Deine Frage gestellt hast (Das wäre hier).
In BEIDEN Threads gehören Links zum jeweils Anderen - so kann sich die Helfer-Schar, Der Das nicht zu blöd ist, anschauen, was bereits versucht wurde.

Und ganz ganz toll ist's auch in zwölf Jahren, wenn irgend ein Neuer über Dein Thread stolpert und eben auch den Anderen findet, wo's vll die Lösung gibt.

Stichwort: Diese gehört dann ebenfalls in BEIDEN erwähnt oder zumindest, daß 'Nebenan' wohl die Lösung erarbeitet wurde - mit Link.

Und wenn Du meinst, daß Das nicht nötig ist, hast Du echt ein Problem!

MfG

FirstS0ul:
Na danke...
Zwei Foren = Verschiedene Leute = Verschiedene Anworten und Lösungen.

E la stessa incazzatura.

Und Du ärgerst damit alle.

Grüße Uwe