Wemos ESP8266 to control light with manual button, not updating web interface

Hello everyone,

I think I have a basic problem and I miss some basic knowledge to solve it.

Situation:
Wemos D1 mini with ESP8266 connected to home assistant through MQTT wired with:

  • DHT11 temperature and humidity sensor
  • relay for light control
  • Momentary button
    I can operate the relay nicely through the hass interface and see the temp en humidity.
    When I push the button it also turns on
    but… when I push the button i also want the button on the interface to change.
    What am I missing in my client.publish()?

Home Assistant config:

sensor:
 - platform: mqtt
   state_topic: 'home/midden/keuken/temp'
   name: 'keuken temperatuur'
   unit_of_measurement: '°C'

 - platform: mqtt
   state_topic: 'home/midden/keuken/humi'
   name: 'keuken vochtigheid'
   unit_of_measurement: '%'

switch:
 - platform: mqtt
   name: "keuken spots"
   state_topic: "home/midden/keuken/spots"
   command_topic: "home/midden/keuken/spots/set"
   payload_off: 0
   payload_on: 1
   qos: 1

Wemos Arduino Code:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

#define DHTPIN D7   
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);

#define LED D3
#define buttonPin D2
int buttonState = 0;
int lightstate = 0;

// Update these with values suitable for your network.
const char* ssid = "Awesomeness";
const char* password = "Fakenews";
const char* mqtt_server = "192.168.178.172";
#define CLIENT_ID "keuken"


WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid); //We don't want the ESP to act as an AP
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password); 

  while (WiFi.status() != WL_CONNECTED) 
  {
    
    digitalWrite(LED_BUILTIN, HIGH);
    delay(125);
    digitalWrite(LED_BUILTIN, LOW);
    delay(125);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(125);
    digitalWrite(LED_BUILTIN, LOW);
    delay(125);
    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();

  // Switch on the relay if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(LED, HIGH);
    client.publish("home/midden/keuken/spots", "1", true);
    int lightstate = 1;
    Serial.print("lightstate = ");
    Serial.println(lightstate);
  } else {
    digitalWrite(LED, LOW);
    client.publish("home/midden/keuken/spots", "0", true);
    int lightstate = 0;
    Serial.print("lightstate = ");
    Serial.println(lightstate);
  }

}

void reconnect() {
  // Loop until we're reconnected
  digitalWrite(LED_BUILTIN, LOW);
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(CLIENT_ID)) {
      Serial.println("connected");
      client.subscribe("home/midden/keuken/spots/set");
      digitalWrite(LED_BUILTIN, HIGH);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(1000);
      digitalWrite(LED_BUILTIN, HIGH);
      delay(1000);
      digitalWrite(LED_BUILTIN, LOW);
      delay(1000);
      digitalWrite(LED_BUILTIN, HIGH);
      delay(1000);
      digitalWrite(LED_BUILTIN, LOW);
      delay(1000);
    }
  }
}
 
void setup(){
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(LED, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  digitalWrite(LED, LOW);
  Serial.begin(9600);
  setup_wifi(); 
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  dht.begin();
}

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

  // DHT11 temperature and humidity
  long now = millis();                  // only check every x ms
  if (now - lastMsg > 2000) {
    lastMsg = now;
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    
    if (isnan(h) || isnan(t)) {
       Serial.println("Impossible de lire la sonde DHT!");
       return;
    }
    Serial.print("Humidity: ");
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: ");
    Serial.print(t);
    Serial.println(" *C ");
    
    client.publish("home/midden/keuken/temp", String(t).c_str(), false);
    client.publish("home/midden/keuken/humi", String(h).c_str(), false);
  }

    // read button press
    buttonState = digitalRead(buttonPin);    
    if (buttonState == LOW) {
      if (lightstate == 0){
        digitalWrite(LED, HIGH); 
        client.publish("home/midden/keuken/spots", "1", true);
        int lightstate = 1;
        Serial.print("lightstate = ");
        Serial.println(lightstate);
      } else {
        digitalWrite(LED, LOW);
        client.publish("home/midden/keuken/spots", "0", true);
        int lightstate = 0;
        Serial.print("lightstate = ");
        Serial.println(lightstate);
      }
    }

}

I use "'s round my payloads…

- platform: mqtt
  name: bathroom_light
  state_topic:   "stat/bathroomPIR"
  command_topic: "cmnd/bathroomPIR"
  qos: 1
  payload_on: "on"
  payload_off: "off"
  retain: true 
  optimistic: false

Thanks @keithh666 that is a devils good answer :wink:
That fixed it. I furthermore found some other errors which are just stupid arduino code error.
For reference find below the working arduino for Wemos D1 mini with:

  • relay shield
  • DHT11 sensor for temperature and humidity
  • button that was connected to Momentary button of original kitchen spot system.

Wife acceptance factor = 100% (she doesn’t know, it doesn’t effect her original workflow).

edit: Disaster! The WiFi failed on me and the wife was bullying me that it was a crappy system.
So i changed the code a bit to check for button press during wifi and MQTT connecting.
I also restructured the whole connecting part to fit in the loop.
This enables to reconnect without reset if the Wifi fails during operation.

Arduino code:

//Wemos D1 mini with:
//- relay shield
//- DHT11 sensor for temperature and humidity
//- button that was connected to Momentary button of original kitchen spot system.
//
//Home assistant configiguration:
//
//sensor:
// - platform: mqtt
//   state_topic: 'home/midden/keuken/temp'
//   name: 'keuken temperatuur'
//   unit_of_measurement: '°C'
//
// - platform: mqtt
//   state_topic: 'home/midden/keuken/humi'
//   name: 'keuken vochtigheid'
//   unit_of_measurement: '%'
//
//switch:
// - platform: mqtt
//   name: "keuken spots"
//   state_topic: "home/midden/keuken/spots"
//   command_topic: "home/midden/keuken/spots/set"
//   payload_off: "0"
//   payload_on: "1"
//   qos: 1

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

#define DHTPIN D7            // what pin we're connected to
#define DHTTYPE DHT11        // DHT 11 (you might want to graph the mean of this data -> https://home-assistant.io/components/sensor.statistics/) 
//#define DHTTYPE DHT22        // DHT 22 (uncomment your sensor) (recommend using DHT 22 as Home Assistant graph looks a lot nicer)
DHT dht(DHTPIN, DHTTYPE);
int checkinterval = 10000;   // ms interval between checkups (reality is longer as rest of code takes more time), smaller then 6 seconds makes it unstable.
long lastMsg = 0;            // counter for non-interupt measurement

#define LED D1               // Relay connected to D1 of the wemos
#define buttonPin D2
int buttonState = 0;
int lightstate;

// Update these with values suitable for your network.
const char* ssid = Awesomeness";
const char* password = "supersexy";
const char* mqtt_server = "123.456.789.123";
int mqttport = 1883;
#define CLIENT_ID "keuken"

WiFiClient espClient;
PubSubClient client(espClient);
 
void setup(){
  Serial.begin(9600);
  Serial.println("setup begin");
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(LED, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);  // do not forget to add 10k resistor between GND - btn - input pin
  digitalWrite(LED, LOW);            // Start with lights off
  lightstate = 0;
  dht.begin();
  Serial.println("setup end");
}

void loop(){
  Serial.println("Loop begin");

  // Connect to Wifi if not connected
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("wifi connect in loop - start");
    setup_wifi();
    client.setServer(mqtt_server, mqttport);
    client.setCallback(callback);
    Serial.println("wifi connect in loop - end");
  } else {
    Serial.println("wifi connect in loop - already connected");
  }

  // reconnect when MQTT is not connected
  if (!client.connected()) {
    Serial.println("MQTT reconnect - start");
    reconnect();

    //publish state here (in case wifi is not connected then lightstate might changed before connecting MQTT)
    if (lightstate == 1){
      client.publish("home/midden/keuken/spots", "1", true);
    } else {
      client.publish("home/midden/keuken/spots", "0", true);
    }
    
    Serial.println("MQTT reconnect - end");
  } else {
    Serial.println("MQTT reconnect - already connected");
  }
  client.loop();

  // DHT11 temperature and humidity
  long now = millis();                  // only check every x ms  checkinterval
  if (now - lastMsg > checkinterval) {
    lastMsg = now;
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    
    if (isnan(h) || isnan(t)) {
       Serial.println("Impossible de lire la sonde DHT!");
       return;
    }
    Serial.print("                      Humidity: ");  // a little longer string to make it stand out in the serial monitor
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: ");
    Serial.print(t);
    Serial.println(" *C ");

    if (client.connected()) {
      client.publish("home/midden/keuken/temp", String(t).c_str(), false);
      client.publish("home/midden/keuken/humi", String(h).c_str(), false);      
    }
  }

    // read button press
        buttonState = digitalRead(buttonPin); 
        if (buttonState == 0) {
          if (lightstate == 0){
            lightstate = 1;
            digitalWrite(LED, HIGH);
            if (client.connected()) {client.publish("home/midden/keuken/spots", "1", true);}
          } else {
            lightstate = 0;
            digitalWrite(LED, LOW);
            if (client.connected()) {client.publish("home/midden/keuken/spots", "0", true);}
          }
          delay(150); // delay after button press to prevent double click
        }
        Serial.print("lightstate = ");
        Serial.print(lightstate);
        Serial.print(" - buttonState = ");
        Serial.println(buttonState);   

  Serial.println("Loop ended");
}

void checkbtnpress(){
  buttonState = digitalRead(buttonPin);
  if (buttonState == 0) {
          if (lightstate == 0){
            lightstate = 1;
            digitalWrite(LED, HIGH);
          } else {
            lightstate = 0;
            digitalWrite(LED, LOW);
          }
          delay(150);
        } 
   delay(10);    
}

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

  while (WiFi.status() != WL_CONNECTED) {
    // wait 50 * 10 ms = 500 ms to give ESP some time to connect (need to give delay else you get soft WDT reset)
      for (int i=0; i <= 50; i++){
      checkbtnpress(); // this takes ~10ms
        if (i == 50) { 
          Serial.println(".");
        } else {
          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();

  // Switch on the relay if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(LED, HIGH);
    client.publish("home/midden/keuken/spots", "1", true);
    lightstate = 1;
    Serial.print("lightstate = ");
    Serial.println(lightstate);
  } else {
    digitalWrite(LED, LOW);
    client.publish("home/midden/keuken/spots", "0", true);
    lightstate = 0;
    Serial.print("lightstate = ");
    Serial.println(lightstate);
  }
}

void reconnect() {
  // Loop until we're reconnected
  digitalWrite(LED_BUILTIN, LOW);
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(CLIENT_ID)) {
      Serial.println("connected");
      client.subscribe("home/midden/keuken/spots/set");    //subscribe light to MQTT server, you can set your name here
      digitalWrite(LED_BUILTIN, HIGH);      
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");

      // Wait (500 * 10ms = 5000ms) 5 seconds before retrying, but read button press meanwhile
      for (int i=0; i <= 500; i++){
      checkbtnpress(); // this takes ~10ms
        if (i == 500) { 
          Serial.println(".");
        } else {
          Serial.print(".");
        }     
      }     
    }
  }
}
1 Like