either message from MQTT server turn on the light or push button

Hi,
I am trying to create a home automation system with my own server. ESP8266 perfectly subscribe and received the message from MQTT. My problem is either manual push-button works or online command.
If I use this code only push-button turns light on/off.
My code is:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "MY SSID";
const char* password = "MY Password";
const char* mqtt_server = "MY MQTT server IP Address";
char* deviceId = "node019";
char* stateTopic = "sakil";
char* commandTopic = "sakil/set";
char buf[4];
int updateInterval = 2000;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg0[20];
const int buttonPin1 = 16;
const int ledPin1 = 4;
int buttonState1 = 0;
int lastButtonState1 = 0;
int ledState1 = 0;
void setup_wifi() {
delay(10);
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("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if ((char)payload[0] == '1') {
    digitalWrite(4, HIGH);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(4, LOW);  // Turn the LED off by making the voltage HIGH
  }
  
  
//Serial.print(topic);
//Serial.print(” ");
//String recieveTopic = (char*)topic;
//Serial.print("Payload: ");
//Serial.write(payload, length);
//Serial.println();
//char p[length + 1];
//memcpy(p, payload, length);
//p[length] = NULL;
//String message;
//if (recieveTopic == (char*)commandTopic) {
 // Serial.print("ok..");
//if (message==("1")) {
//digitalWrite(4, HIGH);
//} else {
//digitalWrite(4, LOW);
//}
//} else {
//Serial.print("Topic unknown");
//}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection…");
if (client.connect(deviceId)) {
Serial.println("connected");
client.publish(stateTopic, "ready");
client.subscribe(commandTopic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
pinMode(buttonPin1, INPUT);
pinMode(ledPin1, OUTPUT);
pinMode(4, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
buttonState1 = digitalRead(buttonPin1);
if (buttonState1 != lastButtonState1) {
if (buttonState1 == HIGH) {
if (ledState1 == HIGH) {
ledState1 = LOW;
} else {
ledState1 = HIGH;
}
}
lastButtonState1 = buttonState1;
}
digitalWrite(ledPin1, ledState1);
delay(20);
long now = millis();
if (now - lastMsg > updateInterval) {
lastMsg = now;
snprintf(msg0, 75, "%ld", ledState1);
client.publish(stateTopic, msg0);
}
}

if I remove this code after client.loop();

buttonState1 = digitalRead(buttonPin1);
if (buttonState1 != lastButtonState1) {
if (buttonState1 == HIGH) {
if (ledState1 == HIGH) {
ledState1 = LOW;
} else {
ledState1 = HIGH;
}
}
lastButtonState1 = buttonState1;
}
digitalWrite(ledPin1, ledState1);
delay(20);

Then an online message from MQTT server turns on/off the light.

Unable to figure it out what is going wrong. I am looking for your kind suggestions. Thanks in advance for your time and help.

Put some more serial prints in so you can see what is happening in the button code.

I notice that you haven't used input_pullup for the button. Consider it if you don't have an external pulldown resistor wired up. Remember that input_pullup means that a LOW signal will indicate a button press.

Curious, have you tried this:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "MY SSID";
const char* password = "MY Password";
const char* mqtt_server = "MY MQTT server IP Address";
char* deviceId = "node019";
char* stateTopic = "sakil";
char* commandTopic = "sakil/set";
char buf[4];
int updateInterval = 2000;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg0[20];
const int buttonPin1 = 16;
const int ledPin1 = 4;
int buttonState1 = 0;
int lastButtonState1 = 0;
int ledState1 = 0;
void setup_wifi() {
delay(10);
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("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if ((char)payload[0] == '1') {
    digitalWrite(4, HIGH);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(4, LOW);  // Turn the LED off by making the voltage HIGH
  }
 
 
//Serial.print(topic);
//Serial.print(" ");
//String recieveTopic = (char*)topic;
//Serial.print("Payload: ");
//Serial.write(payload, length);
//Serial.println();
//char p[length + 1];
//memcpy(p, payload, length);
//p[length] = NULL;
//String message;
//if (recieveTopic == (char*)commandTopic) {
 // Serial.print("ok..");
//if (message==("1")) {
//digitalWrite(4, HIGH);
//} else {
//digitalWrite(4, LOW);
//}
//} else {
//Serial.print("Topic unknown");
//}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection…");
if (client.connect(deviceId)) {
Serial.println("connected");
client.publish(stateTopic, "ready");
client.subscribe(commandTopic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
pinMode(buttonPin1, INPUT);
pinMode(ledPin1, OUTPUT);
pinMode(4, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
Serial.println( "got to 1");
buttonState1 = digitalRead(buttonPin1);
Serial.println( "got to 2");
if (buttonState1 != lastButtonState1) {
if (buttonState1 == HIGH) {
if (ledState1 == HIGH) {
ledState1 = LOW;
Serial.println( "got to 3");
} else {
ledState1 = HIGH;
}
}
lastButtonState1 = buttonState1;
}
digitalWrite(ledPin1, ledState1);
delay(20); <<<< why use delay???????????????????
Serial.println( "got to 4");
long now = millis();
if (now - lastMsg > updateInterval) {
lastMsg = now;
snprintf(msg0, 75, "%ld", ledState1);
client.publish(stateTopic, msg0);
}
Serial.println( "got to 5");
client.loop();
Serial.println( "got to 6");
}

?

Idahowalker:
Curious, have you tried this:

#include <ESP8266WiFi.h>

#include <PubSubClient.h>
const char* ssid = "MY SSID";
const char* password = "MY Password";
const char* mqtt_server = "MY MQTT server IP Address";
char* deviceId = "node019";
char* stateTopic = "sakil";
char* commandTopic = "sakil/set";
char buf[4];
int updateInterval = 2000;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg0[20];
const int buttonPin1 = 16;
const int ledPin1 = 4;
int buttonState1 = 0;
int lastButtonState1 = 0;
int ledState1 = 0;
void setup_wifi() {
delay(10);
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("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

if ((char)payload[0] == '1') {
    digitalWrite(4, HIGH);  // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(4, LOW);  // Turn the LED off by making the voltage HIGH
  }

//Serial.print(topic);
//Serial.print(" ");
//String recieveTopic = (char*)topic;
//Serial.print("Payload: ");
//Serial.write(payload, length);
//Serial.println();
//char p[length + 1];
//memcpy(p, payload, length);
//p[length] = NULL;
//String message;
//if (recieveTopic == (char*)commandTopic) {
// Serial.print("ok..");
//if (message==("1")) {
//digitalWrite(4, HIGH);
//} else {
//digitalWrite(4, LOW);
//}
//} else {
//Serial.print("Topic unknown");
//}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection…");
if (client.connect(deviceId)) {
Serial.println("connected");
client.publish(stateTopic, "ready");
client.subscribe(commandTopic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
pinMode(buttonPin1, INPUT);
pinMode(ledPin1, OUTPUT);
pinMode(4, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
Serial.println( "got to 1");
buttonState1 = digitalRead(buttonPin1);
Serial.println( "got to 2");
if (buttonState1 != lastButtonState1) {
if (buttonState1 == HIGH) {
if (ledState1 == HIGH) {
ledState1 = LOW;
Serial.println( "got to 3");
} else {
ledState1 = HIGH;
}
}
lastButtonState1 = buttonState1;
}
digitalWrite(ledPin1, ledState1);
delay(20); <<<< why use delay???????????????????
Serial.println( "got to 4");
long now = millis();
if (now - lastMsg > updateInterval) {
lastMsg = now;
snprintf(msg0, 75, "%ld", ledState1);
client.publish(stateTopic, msg0);
}
Serial.println( "got to 5");
client.loop();
Serial.println( "got to 6");
}


?

Thank you,
I tried your code. It is continuously print:

19:41:57.427 -> got to 5
19:41:57.427 -> got to 6
19:41:57.427 -> got to 1
19:41:57.427 -> got to 2
19:41:57.427 -> got to 4
19:41:57.427 -> got to 5
19:41:57.427 -> got to 6
19:41:57.427 -> got to 1
19:41:57.427 -> got to 2
19:41:57.427 -> got to 4
19:41:57.427 -> got to 5
19:41:57.427 -> got to 6
19:41:57.427 -> got to 1
19:41:57.427 -> got to 2
19:41:57.427 -> got to 4

wildbill:
Put some more serial prints in so you can see what is happening in the button code.

I notice that you haven't used input_pullup for the button. Consider it if you don't have an external pulldown resistor wired up. Remember that input_pullup means that a LOW signal will indicate a button press.

Thank you for your reply. I used an external pulldown resistor. when I push the button it turns on/off. when I send message to topic "sakil/set" it prints

Message arrived [sakil/set] 1

but unable to turn on/off the light.

D'oh! it's obvious, but I missed it: that digitalWrite after the button code isn't controlled by the button change so it runs every time loop runs. So likely, the MQTT stuff is working, but you don't see it because the digitalWrite overrides it almost immediately.

wildbill:
D'oh! it's obvious, but I missed it: that digitalWrite after the button code isn't controlled by the button change so it runs every time loop runs. So likely, the MQTT stuff is working, but you don't see it because the digitalWrite overrides it almost immediately.

Yes, you are right. If the button state is 0 the light is off. when I send 1 immediately it overrides by 0, that is why MQTT message is not working. But how can I overcome this issue?

Move the digitalWrite up one line.

wildbill:
Move the digitalWrite up one line.

Thank you very much. It's working. I think its time to close this topic as solved.

sakilimtiaz:
Thank you,
I tried your code. It is continuously print:

Which means 3 does not run and the code does not stop running?

Idahowalker:
Which means 3 does not run and the code does not stop running?

Thank you for your reply. Actually the solution is: the digitalWrite(ledPin1, ledState1); line need to inside if {} Condition

sakilimtiaz:
Thank you very much. It's working. I think its time to close this topic as solved.

Hi,
The previous problem was solved. But one new problem arrived. Push-button works fine only if the device connected to the internet. It is not working, if the device unable to connect to the server. The main problem is the loop function stuck on reconnect(); that is why push-button code is not working. How can it works with both connected and disconnected?

Thank you

Get rid of the while loop in reconnect. I assume that you pulled that code from an MQTT example and there's a tacit assumption there that there's no point doing anything if you can't connect to the server.

Just let the reconnect function have one attempt, it's going to be called again and again from loop anyway until a connection is established, but this way the rest of loop (i.e. the button code) will run too.

wildbill:
Get rid of the while loop in reconnect. I assume that you pulled that code from an MQTT example and there's a tacit assumption there that there's no point doing anything if you can't connect to the server.

Just let the reconnect function have one attempt, it's going to be called again and again from loop anyway until a connection is established, but this way the rest of loop (i.e. the button code) will run too.

Thank you for your reply,
I created a function named button(){ button code....}.

and placed the function inside

void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
button();
Serial.print(".");

}

it works fine while the device is trying to connect with wifi. Hope if I add them inside reconnect(); it will work fine. I will let you know the result

wildbill:
Get rid of the while loop in reconnect. I assume that you pulled that code from an MQTT example and there's a tacit assumption there that there's no point doing anything if you can't connect to the server.

Just let the reconnect function have one attempt, it's going to be called again and again from loop anyway until a connection is established, but this way the rest of loop (i.e. the button code) will run too.

Yes, I am using PubSubClient example. If I use reconnect() function one time. I mean use if instead of while. It needs long-press to turn on the light. But it won't work again to turn the light off. Needs another switch to turn other light on then it is able to turn off 1st light. Not works the same switch twice in a row.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "sakil";
const char* password = "sakil123";
const char* mqtt_server = "147.139.32.13";
char* deviceId = "node019";
char* stateTopic = "sakil";
char* commandTopic = "sakil/set";
char buf[4];
int updateInterval = 2000;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg0[20];
char msg1[20];
const int buttonPin = 5;
const int buttonPin1 = 16;
const int ledPin = 4;
const int ledPin1 = 2;
int buttonState = 0;
int buttonState1 = 0;
int lastButtonState = 0;
int lastButtonState1 = 0;
int ledState = 0;
int ledState1 = 0;
boolean toogleState = false;
boolean currentState = true;
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(50);
button();
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("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if ((char)payload[0] == '1') {
    digitalWrite(2, HIGH);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else if((char)payload[0] == '0'){
    digitalWrite(2, LOW);  // Turn the LED off by making the voltage HIGH
  }
  else if((char)payload[0] == '2'){
    digitalWrite(4, HIGH);  // Turn the LED off by making the voltage HIGH
  }
  else if((char)payload[0] == '3'){
    digitalWrite(4, LOW);  // Turn the LED off by making the voltage HIGH
  }

}
void reconnect() {
 //button();
if (!client.connected()) {
//  button();
Serial.print("Attempting MQTT connection…");
if (client.connect(deviceId)) {
Serial.println("connected");
client.publish(stateTopic, "ready");
client.subscribe(commandTopic);
//button();
} else {
  // button();
 //Serial.print("failed, rc=");
//Serial.print(client.state());
//Serial.println(" try again in 5 seconds");
//delay(500);
//button();
}
}
}

void button(){
  buttonState = digitalRead(buttonPin);
buttonState1 = digitalRead(buttonPin1);
if (buttonState1 != lastButtonState1) {
if (buttonState1 == HIGH) {
if (ledState1 == HIGH) {
ledState1 = LOW;
} else {
ledState1 = HIGH;
}
}
lastButtonState1 = buttonState1;
digitalWrite(ledPin1, ledState1);
}

if (buttonState != lastButtonState) {
if (buttonState == HIGH) {
if (ledState == HIGH) {
ledState = LOW;
} else {
ledState = HIGH;
}
}
lastButtonState = buttonState;
digitalWrite(ledPin, ledState);
}
  
  }

void setup() {
pinMode(buttonPin, INPUT);
pinMode(buttonPin1, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(ledPin1, OUTPUT);
pinMode(4, OUTPUT);
pinMode(2, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
 if (!client.connected()) {
reconnect();
//button();
}
client.loop();

button();
//delay(20);
long now = millis();
if (now - lastMsg > updateInterval) {
lastMsg = now;
snprintf(msg0, 75, "%ld", ledState1);
client.publish(stateTopic, msg0);
snprintf(msg1, 75, "%ld", ledState);
client.publish(stateTopic, msg1);
}
}

It looks like you pasted the same code into the button function twice.

wildbill:
Get rid of the while loop in reconnect. I assume that you pulled that code from an MQTT example and there's a tacit assumption there that there's no point doing anything if you can't connect to the server.

Just let the reconnect function have one attempt, it's going to be called again and again from loop anyway until a connection is established, but this way the rest of loop (i.e. the button code) will run too.

Thank you,

Finally, I managed to resolve the issue by letting the reconnect function have one attempt in every 30 sec.

wildbill:
It looks like you pasted the same code into the button function twice.

I need to control two light. That is why buttonState and buttoState1 code in button();