MQTT Button using ESP8266

I found at least one example of someone using a rotary encoder to control automations via MQTT though its only a small part of a massive wall controller for OpenHAB- github.com/hazymat/fleetwood/bl … July15.ino
Looking over the code, it isnt hard to see that why OpenHAB isnt exactly known for its efficiency… Glad I made the choice to go with Home-Assistant!
Anyway, I’d never heard of an encoder library for Arduino before, so that might be a good place to start. After all, as far as MQTT and HASS is concerned, the Neopixel ring doesn’t have to exist as long as it knows to read the encoder after the button is pressed.

Back to the original project for the time being… Using the wiring I posted earlier, I was indeed able to successfully load a version of the Arduino sketch posted earlier with just a few modifications to match my network preferences and MQTT topics.

[code]#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Wifi Connection
const char* ssid = “ssid”;
const char* password = “pass”;

// MQTT Server address
const char* mqtt_server = “192.168.1.1”;

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup() {

// prepare GPIO4

pinMode(0, OUTPUT);
digitalWrite(0, 1);

Serial.begin(9600);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}

void setup_wifi() {

delay(2);
// We start by connecting to a WiFi network
Serial.println();
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();

// Switch on the LED if an 1 was received as first character
int val;
if ((char)payload[0] == ‘1’) {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
val = 1;
digitalWrite(0, val);
// but actually the LED is on; this is because
// it is acive low on the ESP-01)
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
val = 0;
digitalWrite(0, val);
}

}

void reconnect() {
// Loop until we’re reconnected
while (!client.connected()) {
Serial.print(“Attempting MQTT connection…”);
// Attempt to connect
if (client.connect(“ESP8266Client”)) {
Serial.println(“connected”);
// Once connected, publish an announcement…
client.publish(“home/bedroom/buttonswitch/set”, “connected”);
// … and resubscribe
client.subscribe(“home/bedroom/buttonswitch”);
} 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() {

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

long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, 75, “connected”, value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish(“home/bedroom/buttonswitch”, msg);
}
}[/code]

Then on the HASS side I added the switch to my config.yaml

switch: platform: mqtt name: "Bedroom Switch" state_topic: "home/bedroom/buttonswitch" command_topic: "home/bedroom/buttonswitch/set" qos: 0 payload_on: "ON" payload_off: "OFF" optimistic: false state_format:

I then created two new scenes of which one is the default “lights out” mode while we’re all sleeping and the other wherein the MQTT button will turn the lights on.

[code]- name: ‘Baby Change’
entities:
light.bedlamp:
state: on
brightness: 100
rgb_color: [255, 0, 0]
light.bedroom:
state: on
brightness: 100
rgb_color: [255, 0, 0]
light.bathroom:
state: on
brightness: 50
rgb_color: [20, 50, 200]

  • name: ‘Sleep’
    entities:
    light.bedlamp:
    state: off
    brightness: 0
    light.bedroom:
    state: off
    brightness: 0
    light.bathroom:
    state: on
    brightness: 50
    rgb_color: [20, 50, 200][/code]

Lastly, I created the following automation for the MQTT trigger itself-

[code]automation:

  • alias: ‘Baby Wake’

    trigger:

    • platform: mqtt
      topic: home/bedroom/buttonswitch/set

      Optional

      payload: ‘on’

    action:
    service: scene.turn_on
    entity_id: scene.baby_change

automation:

  • alias: ‘Baby Wake’

    trigger:

    • platform: mqtt
      topic: home/bedroom/buttonswitch/set

      Optional

      payload: ‘off’

    action:
    service: scene.turn_off
    entity_id: scene.sleep[/code]

While I was able to see the messages while connected to the Arduino Serial Monitor, the actions did not seem to be recognized by Home Assistant. So I’m definitely missing something. Is there any additional configuartion that needs to be done through the MQTT Broker (Mosquitto in my case?). Do I need to publish each topic and subtopic directly to Mosquitto or will it automatically publish from the config.yaml?

My current (scrubbed) config.yaml can be found at my pastebin if anybody would like to take a look- pastebin.com/hjeJm3xa

I guess I’ll continue to update my progress for future reference even if it seems like I’m in an echo chamber…

I was able to confirm through the CLI on the Mosquitto broker that the sketch is indeed working. It is continually sending out to the state topic home/bedroom/buttonswitch and home/bedroom/buttonswitch/set when the button is pressed… I can’t quite figure out from the MQTT-Switch component docs whether it is supposed to be this way or not… If not, then I need to rewrite the Arduino sketch to only publish when the button is pressed. If using an Arduino, I would do so with the following sketch-

[code]#include <SPI.h>
#include <PubSubClient.h>
#include <Ethernet.h>
#include <util.h>
#include <ctype.h>

#define CLIENTID “ArduinoSensor”
#define TOPICNAME “switch/signal”
#define POLLINTERVAL 120000

#define PORT 80
//Connect to MQTT server
byte server1 [] = {192, 168, 1, 4};
byte mac[] = {0x5e, 0xa4, 0x18, 0xf0, 0x8a, 0xf6};

IPAddress arduinoIP(192, 168, 1, 67);
IPAddress dnsIP(203, 145, 184, 32);
IPAddress gatewayIP(192, 168, 1, 1);
IPAddress subnetIP(255, 255, 255, 0);
EthernetServer server(PORT);

EthernetClient ethClient;
PubSubClient arduinoClient(server1, 8081, callback, ethClient);
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
}
int inPin1 = 2;
int inPin2 = 0;// the number of the input pin
int outPin = 7; // the number of the output pi

int state = HIGH; // the current state of the output pin
int reading; // the current reading from the input pin
int previous = LOW; // the previous reading from the input pin

// the follow variables are long’s because the time, measured in milliseconds
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers

int state2 = HIGH; // the current state of the output pin
int reading2; // the current reading from the input pin
int previous2 = LOW; // the previous reading from the input pin

// the follow variables are long’s because the time, measured in milliseconds
// will quickly become a bigger number than can be stored in an int.
long time2 = 0; // the last time the output pin was toggled
long debounce2 = 200; // the debounce time, increase if the output flickers
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, arduinoIP, dnsIP, gatewayIP, subnetIP);
pinMode(inPin1, INPUT);
pinMode(inPin2, INPUT);
pinMode(outPin, OUTPUT);
beginConnection() ;
}

void beginConnection() {
Serial.begin(9600);
//Ethernet.begin(mac) ;
int connRC = arduinoClient.connect(CLIENTID) ;
if (!connRC) {
Serial.println(connRC) ;
Serial.println(“Could not connect to MQTT Server”);
Serial.println(“Please reset the arduino to try again”);
delay(100);
exit(-1);
}
else {
Serial.println(“Connected to MQTT Server…”);

}}

void loop()
{

reading = digitalRead(inPin1);

// if the input just went from LOW and HIGH and we’ve waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (state == HIGH){
state = LOW;
arduinoClient.publish(TOPICNAME, “Button A is Pressed”) ;
Serial.println(“Button A is Pressed and message published”);}
else
{
state = HIGH;
arduinoClient.publish(TOPICNAME, “Button A is Pressed”) ;
Serial.println(“Button A is Pressed and message published”);
}
time = millis();
}
digitalWrite(outPin, state);

previous = reading;

reading2 = digitalRead(inPin2);

// if the input just went from LOW and HIGH and we’ve waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading2 == HIGH && previous2 == LOW && millis() - time2 > debounce2) {
if (state2 == HIGH){
state2 = LOW;
arduinoClient.publish(TOPICNAME, “Button B is Pressed”) ;
Serial.println(“Button B is Pressed and message published”);}
else
{
state2 = HIGH;
arduinoClient.publish(TOPICNAME, “Button B is Pressed”) ;
Serial.println(“Button B is Pressed and message published”);
}
time2 = millis();
}
digitalWrite(outPin, state2);

previous2 = reading2;

}[/code]

Unfortunately, the PUBSUBCLIENT library works somewhat differently with an ESP8266 so its not quite as simple as changing some of the parameters…

If on the other hand, the MQTT comms are working as they should, then the problem is in the scene configuration as I would’ve expected to see start/stop_scene available under services… But it is not…

humblehacker, sorry for not getting back to you earlier.

I will try to send you pics of the wiring tommorrow when I get back home.
In regards to a button I have implemented something similar however using an RIFD reader.
In this example it reads the Token and if the token is allowed it either turns on or off the alarm system.
However you could adapt it to act as a button only.

Please note that I use an ESP8266 (ESP-12) much easier to use and program.
Here is the example:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>
#include "MFRC522.h"

/* wiring the MFRC522 to ESP8266 (ESP-12)
RST     = GPIO4
SDA(SS) = GPIO2 
MOSI    = GPIO13
MISO    = GPIO12
SCK     = GPIO14
GND     = GND
3.3V    = 3.3V
*/

#define RST_PIN  4 // RST-PIN GPIO4 
#define SS_PIN  2  // SDA-PIN GPIO2 

MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance

// Wifi Connection details
const char* ssid = "SSID";
const char* password = "PASSWORD";

// MQTT Server address
const char* mqtt_server = "SERVER_IP";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int state;



void setup() {
  Serial.begin(9600);

  SPI.begin();           // Init SPI bus
  mfrc522.PCD_Init();    // Init MFRC522
    
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}


// Connect to Wifi
void setup_wifi() {

  pinMode(5, OUTPUT); // Red LED
  pinMode(5, HIGH); 
  pinMode(0, OUTPUT); // Greem :LED
  pinMode(0, HIGH);

  delay(2);
  // We start by connecting to a WiFi network
  Serial.println();
  
  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());
}


// Check for incoming messages
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]);
  }


  // Alarm is on
  if ((char)payload[1] == 'n') {
    Serial.println();
    Serial.print("Alarm is on");
    Serial.println();
    state=1;
    on_red_led();    
  } 
  
  // Alarm is off
  if ((char)payload[1] == 'f') {
    Serial.println();
    Serial.print("Alarm is off");
    Serial.println();
    state=0;
    on_green_led();    
  } 
  
  // Alarm is arming
  if ((char)payload[2] == 'm') {
    Serial.println();
    Serial.print("Alarm is arming");
    Serial.println();
    state=2;
    flash_red_led();    
  }   

  // Alarm is disarming
  if ((char)payload[2] == 's') {
    Serial.println();
    Serial.print("Alarm is disarming");
    Serial.println();
    state=2;
    flash_green_led();    
  } 

  // Error
  if ((char)payload[3] == 'o') {
    Serial.println();
    Serial.print("Error wrong token");
    Serial.println();
    state=3;
    blink_red_led();    
  }

}


// Reconnect to wifi if connection lost
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("/rfid/state", "connected");
      // ... and resubscribe
      client.subscribe("/alarm/state");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


// Main functions
void loop() {

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

  client.loop();
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    delay(50);
    return;
  }
  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    delay(50);
    return;
  }

  // if still arming or disarming then return
  if (state == 2) { 
  return; 
  }

  // if error delay
  if (state == 3) { 
  delay(2000); 
  }
  
  // Show some details of the PICC (that is: the tag/card)
  Serial.print(F("Card UID:"));
  dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  Serial.println();

  // Send data to MQTT
  String rfidUid = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    rfidUid += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
    rfidUid += String(mfrc522.uid.uidByte[i], HEX);
  }
  const char* id = rfidUid.c_str();

  // Blink led once
  if (state == 1) { 
  beep_red_led(); 
  }
  if (state != 1) { 
  beep_green_led();  
  }
  
  client.publish("/rfid/user", id);
  //delay(2000);
}


// LED Loop
void blink_red_led(){
  Serial.println("Blinking Red");
  digitalWrite(0, LOW);
  // Flash 6 times:
  for(int i = 0; i < 5; i++)
  {
  digitalWrite(5, HIGH);
  delay(200);
}}

void flash_green_led(){
  Serial.println("Flashing Green LED");
  digitalWrite(5, LOW);
  // Flash 15 times:
  for(int i = 0; i < 14; i++)
  {
  digitalWrite(0, HIGH);
  delay(1000);
  digitalWrite(0, LOW);
  delay(500);
}}


void beep_red_led(){
  Serial.println("Beep Red LED");
  digitalWrite(5, LOW);
  delay(500);
  digitalWrite(5, HIGH);
}

void beep_green_led(){
  Serial.println("Beep Red LED");
  digitalWrite(0, LOW);
  delay(500);
  digitalWrite(0, HIGH);
}

void flash_red_led(){
  Serial.println("Flashing Red LED");
  digitalWrite(0, LOW);
  // Flash 20 times:
  for(int i = 0; i < 19; i++)
  {
  digitalWrite(5, HIGH);
  delay(1000);
  digitalWrite(5, LOW);
  delay(500);
}}


void on_green_led(){
  Serial.println("Turning on green led");
  digitalWrite(5, LOW);
  digitalWrite(0, HIGH);
}

void on_red_led(){
  Serial.println("Turning on red led");
  digitalWrite(0, LOW);
  digitalWrite(5, HIGH);
}


// Helper routine to dump a byte array as hex values to Serial
void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

Thank you @thaijames!!! I think I’ve got the wiring down and I was able to load the first example sketch you provided earlier but I’m a little confused about the how they use state and command topics in the MQTT Switch component. As I have it at present, the switch is continuously publishing “home/bedroom/buttonswitch connected” about once every second. Assuming I have the button set correctly etc… it will publish “home/bedroom/buttonswitch/set” on button press though sometimes it can be finicky. Anyway, I don’t know if this is how its supposed to work or not but it doesn’t seem like the best setup to me as theres nowhere to add an “on” or “off” payload to trigger a scene…

Thanks to user @fabaff on the Gitter chat I think I’m getting a little closer.

His original sketch-

[code]/*
Basic ESP8266 MQTT example NodeMCU ESP8266-12E development board
*/

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

int inputPins[] = { 1, 3, 12, 13, 14, 15 };
int pinInputCount = 6;

int outputPins[] = { 0, 2, 4, 5 };
int pinOutputCount = 4;

// Update these with values suitable for your network.
const char* ssid = “…”;
const char* password = “”;
const char* mqtt_server = “…”;

char* deviceId = “unit007”;
char* stateTopic = “home/unit007”;
char* commandTopic = “home/unit007/set”;
int sensorPin = A0;
char buf[4];
int updateInterval = 2000;

char* stateTopicA0 = “home/unit007/a0”;
char* stateTopic0 = “home/unit007/0”;
char* stateTopic1 = “home/unit007/1”;
char* stateTopic2 = “home/unit007/2”;
char* stateTopic3 = “home/unit007/3”;
char* stateTopic4 = “home/unit007/4”;
char* stateTopic5 = “home/unit007/5”;
char* stateTopic12 = “home/unit007/12”;
char* stateTopic13 = “home/unit007/13”;
char* stateTopic14 = “home/unit007/14”;
char* stateTopic15 = “home/unit007/15”;
char* stateTopic16 = “home/unit007/16”;

char* commandTopic0 = “home/unit007/0/set”;
char* commandTopic2 = “home/unit007/2/set”;
char* commandTopic4 = “home/unit007/4/set”;
char* commandTopic5 = “home/unit007/5/set”;

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msga0[20];
char msg0[20];
char msg1[20];
char msg2[20];
char msg3[20];
char msg4[20];
char msg5[20];
char msg12[20];
char msg13[20];
char msg14[20];
char msg15[20];
char msg16[20];
int sensorValue = 0;

const int buttonPin1 = 12;
const int buttonPin2 = 13;

const int ledPin1 = 2;
const int ledPin2 = 5;

int buttonState1 = 0;
int buttonState2 = 0;

int lastButtonState1 = 0;
int lastButtonState2 = 0;

int ledState1 = 0;
int ledState2 = 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(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*)commandTopic0) {
if (message.equals(“1”)) {
digitalWrite(0, HIGH);
} else {
digitalWrite(0, LOW);
}
} else if (recieveTopic == (char*)commandTopic2) {
if (message.equals(“1”)) {
digitalWrite(2, HIGH);
} else {
digitalWrite(2, LOW);
}
} else if (recieveTopic == (char*)commandTopic4) {
if (message.equals(“1”)) {
digitalWrite(4, HIGH);
} else {
digitalWrite(4, LOW);
}
} else if (recieveTopic == (char*)commandTopic5) {
if (message.equals(“1”)) {
digitalWrite(5, HIGH);
} else {
digitalWrite(5, 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(commandTopic0);
client.subscribe(commandTopic2);
client.subscribe(commandTopic4);
client.subscribe(commandTopic5);
} else {
Serial.print(“failed, rc=”);
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}

void setup() {
// Input pins
for (int thisPin = 0; thisPin < pinInputCount; thisPin++) {
pinMode(inputPins[thisPin], INPUT);
}
// Output pins
for (int thisPin = 0; thisPin < pinOutputCount; thisPin++) {
pinMode(outputPins[thisPin], 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);

buttonState2 = digitalRead(buttonPin2);
if (buttonState2 != lastButtonState2) {
if (buttonState2 == HIGH) {
if(ledState2 == HIGH) {
ledState2 = LOW;
} else {
ledState2 = HIGH;
}
}
lastButtonState2 = buttonState2;
}
digitalWrite(ledPin2, ledState2);
delay(20);
//////////////////////////////////////////////////////////////
long now = millis();
if (now - lastMsg > updateInterval) {
lastMsg = now;

snprintf (msga0, 75, "%ld", analogRead(sensorPin));
client.publish(stateTopicA0, msga0);

// Input pins
snprintf(msg0, 75, "%ld", digitalRead(0));
client.publish(stateTopic0, msg0);

snprintf(msg1, 75, "%ld", digitalRead(1));
client.publish(stateTopic1, msg1);

snprintf(msg2, 75, "%ld", digitalRead(2));
client.publish(stateTopic2, msg2);

snprintf(msg3, 75, "%ld", digitalRead(3));
client.publish(stateTopic0, msg3);

snprintf(msg4, 75, "%ld", digitalRead(4));
client.publish(stateTopic4, msg4);

snprintf(msg5, 75, "%ld", digitalRead(5));
client.publish(stateTopic5, msg5);

snprintf(msg12, 75, "%ld", digitalRead(12));
client.publish(stateTopic12, msg12);

snprintf(msg13, 75, "%ld", digitalRead(13));
client.publish(stateTopic13, msg13);

snprintf(msg14, 75, "%ld", digitalRead(14));
client.publish(stateTopic14, msg14);

snprintf(msg15, 75, "%ld", digitalRead(15));
client.publish(stateTopic15, msg15);

snprintf(msg16, 75, "%ld", digitalRead(16));
client.publish(stateTopic16, msg16);    

}
}[/code]

His code was written for the NodeMCU board however which has many more open ports, so I had to modify for the ESP v01 with only two open pins. My current version is as follows-

[code]/*
Basic ESP8266 MQTT example NodeMCU ESP8266-12E development board
*/

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

int inputPins[] = { 0 };
int pinInputCount = 1;

int outputPins[] = { 2 };
int pinOutputCount = 4;

// Update these with values suitable for your network.
const char* ssid = “ssid”;
const char* password = “password”;
const char* mqtt_server = “192.168.1.1”;

char* deviceId = “Button”;
char* stateTopic = “home/bedroom/buttonswitch”;
char* commandTopic = “home/bedroom/buttonswitch/set”;
int sensorPin = A0;
char buf[4];
int updateInterval = 2000;

char* stateTopicA0 = “home/bedroom/buttonswitch/a0”;
char* stateTopic0 = “home/bedroom/buttonswitch/0”;
char* stateTopic1 = “home/bedroom/buttonswitch/1”;

char* commandTopic0 = “home/bedroom/buttonswitch/0/set”;
char* commandTopic2 = “home/bedroom/buttonswitch/2/set”;
char* commandTopic4 = “home/bedroom/buttonswitch/4/set”;
char* commandTopic5 = “home/bedroom/buttonswitch/5/set”;

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msga0[20];
char msg0[20];
char msg1[20];
char msg2[20];
char msg3[20];
char msg4[20];
char msg5[20];
char msg12[20];
char msg13[20];
char msg14[20];
char msg15[20];
char msg16[20];
int sensorValue = 0;

const int buttonPin1 = 0;

const int ledPin1 = 2;

int buttonState1 = 0;
int buttonState2 = 0;

int lastButtonState1 = 0;
int lastButtonState2 = 0;

int ledState1 = 0;
int ledState2 = 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(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*)commandTopic0) {
if (message.equals(“1”)) {
digitalWrite(0, HIGH);
} else {
digitalWrite(0, LOW);
}
} else if (recieveTopic == (char*)commandTopic2) {
if (message.equals(“1”)) {
digitalWrite(2, HIGH);
} else {
digitalWrite(2, LOW);
}
} else if (recieveTopic == (char*)commandTopic4) {
if (message.equals(“1”)) {
digitalWrite(4, HIGH);
} else {
digitalWrite(4, LOW);
}
} else if (recieveTopic == (char*)commandTopic5) {
if (message.equals(“1”)) {
digitalWrite(5, HIGH);
} else {
digitalWrite(5, 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(commandTopic0);
client.subscribe(commandTopic2);
client.subscribe(commandTopic4);
client.subscribe(commandTopic5);
} else {
Serial.print(“failed, rc=”);
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}

void setup() {
// Input pins
for (int thisPin = 0; thisPin < pinInputCount; thisPin++) {
pinMode(inputPins[thisPin], INPUT);
}
// Output pins
for (int thisPin = 0; thisPin < pinOutputCount; thisPin++) {
pinMode(outputPins[thisPin], 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 (msga0, 75, "%ld", analogRead(sensorPin));
client.publish(stateTopicA0, msga0);

// Input pins
snprintf(msg0, 75, "%ld", digitalRead(0));
client.publish(stateTopic0, msg0);

snprintf(msg1, 75, "%ld", digitalRead(1));
client.publish(stateTopic1, msg1);

snprintf(msg3, 75, "%ld", digitalRead(3));
client.publish(stateTopic0, msg3);

 }

}[/code]

Now, in the Mosquitto CLI, at least instead of publishing a “connection” message every other second, I get a string of digits like so-

[quote]1
0
0
47
1
0
0
46[/quote]

When I push the button I get-

[quote]1
0
0
47
ready
1
0
0
46[/quote]

This is the updated and stripped version of the sketch I posted before. Button connected to buttonPin1 and a LED on ledPin1. After one press the ESP8266 send every 2 s its state (1) to the broker and switch the LED on. The next press will switch the LED off and change the state to 0.

This

[code]binary_sensor:

  • platform: mqtt
    name: Physical button
    state_topic: “home/node019”
    payload_on: “1”
    payload_off: “0”[/code]

and the sketch

[code]#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = “SSID”;
const char* password = “PASSWORD”;
const char* mqtt_server = “BROKER”;

char* deviceId = “node019”;
char* stateTopic = “home/node019”;
char* commandTopic = “home/unit019/set”;
char buf[4];
int updateInterval = 2000;

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg0[20];

const int buttonPin1 = 12;
const int ledPin1 = 2;

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(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) {
if (message.equals(“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);

}
}[/code]

I didn’t remove the command topic but toggle an additional LED (nodemcu has more pins than an ESP-01).

humblehacker,

Sorry if I am still confused about what you are trying to do . I am assuming that you want to trigger different scenes or actions remotely using wifi. However I note that you only have one button, but you are trying to publish a number of different values as MQTT topics. Don’t you need one button for each value or topic?

So that when a button is pressed it only publishes that one value or to that one topic?

I would think that you would only want one value published in MQTT at a time so that home assistant can react to it. Otherwise if a number of values are being published rapidly then only the last value will be used.

1
0
0
47
ready
1
0
0
46

Am I understanding you correctly?

Later today I will write a new topic on the process of setting up an RFID reader to interface with an alarm system.
That might give you more insight on how I made it work.

[quote=“fabaff”]This is the updated and stripped version of the sketch I posted before. Button connected to buttonPin1 and a LED on ledPin1. After one press the ESP8266 send every 2 s its state (1) to the broker and switch the LED on. The next press will switch the LED off and change the state to 0.

I didn’t remove the command topic but toggle an additional LED (nodemcu has more pins than an ESP-01).[/quote]

Strange… The code compiled and uploaded just fine but the Mosquitto CLI still just keeps showing-

Even stranger is the fact that the LED will turn off when I push the button but then it comes back on again after about 5 seconds…?

After changing the wifi and topics this is the sketch I uploaded-

[code]#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = “myssid”;
const char* password = “mypassword”;
const char* mqtt_server = “192.168.1.1”;

char* deviceId = “buttonswitch”;
char* stateTopic = “home/bedroom/buttonswitch”;
char* commandTopic = “home/bedroom/buttonswitch/set”;
char buf[4];
int updateInterval = 2000;

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg0[20];

const int buttonPin1 = 0;
const int ledPin1 = 2;

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(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(p);

if (recieveTopic == (char*)commandTopic) {
if (message.equals(“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);

}
}[/code]

[quote=“thaijames”]humblehacker,

Sorry if I am still confused about what you are trying to do . I am assuming that you want to trigger different scenes or actions remotely using wifi. However I note that you only have one button, but you are trying to publish a number of different values as MQTT topics. Don’t you need one button for each value or topic?

So that when a button is pressed it only publishes that one value or to that one topic?

I would think that you would only want one value published in MQTT at a time so that home assistant can react to it. Otherwise if a number of values are being published rapidly then only the last value will be used.

1
0
0
47
ready
1
0
0
46

Am I understanding you correctly?

Later today I will write a new topic on the process of setting up an RFID reader to interface with an alarm system.
That might give you more insight on how I made it work.[/quote]

Yes you are correct @thaijames. I am only trying to control a single scene. I was attempting to modify @fabaffs original sketch which he had created for multiple scenes, but apparently I didnt strip out as much as I thought. Luckily @fabaff posted his own stripped-down version which is what I’m working off of at present.

[quote=“fabaff”]
I didn’t remove the command topic but toggle an additional LED (nodemcu has more pins than an ESP-01).[/quote]

Can you elaborate more about this? I’m guessing this is why I’m getting a “ready” instead of a 0 value when I push the button. Why would I need an extra pin and LED?

It shouldnt be this compilicated to build a light switch… I’m really starting to question whether its worth going through all this trouble for something that doesnt require opening up a web page… All the automations are great but theres no way I’"ll be able to convince the rest of the family that they need to open a web browser to turn the lights on at night etc…

[quote=“humblehacker”][quote=“fabaff”]
I didn’t remove the command topic but toggle an additional LED (nodemcu has more pins than an ESP-01).[/quote]

Can you elaborate more about this? I’m guessing this is why I’m getting a “ready” instead of a 0 value when I push the button. Why would I need an extra pin and LED?[/quote]

There are several reason for me to do this (visual feedback, remote commanding of the button, etc.)…so, why not simply remove it if you don’t want it?

You get the “ready” message only when the connection to the broker was made. If you get that message could mean that your board was rebooted. Issues with the circuit probably

I think I might’ve phrased my question wrong as I didnt mean to question why you did it that way. Rather I meant to ask if you could explain a little more about how the process works. For some reason I’m having a hard time grasping the concepts behind state and command topics in general. In the past, when I’ve used MQTT, it would be in a somewhat simplistic configuration where pushing a button would simply publish a topic like “home/bedroom/switch/toggle”, The controller would then be set up to listen for these actions by subscribing to the same topic “home/bedroom/switch/toggle” and then either turn a scene on or off.
I’m sure there is a good reason for seperate topics for state and command, I just don’t understand it. In any case my line of questioning isnt meant to suggest I have a better approach. I just want to understand how to make it work.

The MQTT sensor and the Binary sensor are working exactly in that manner. They are just consuming messages. So if you want to use a button you only need to send its state. In sketch it’s done that way. If the button gets pressed then a message is sent on the state topic.

The command topic is for receiving command of a remote device (view from your controller/HA). If the command topic is the same as the state topic then you could end up in a loop. The receiver would consume its own state message which will be interpreted as command and then send a new state message.

Oh ok. Its starting to make a little more sense now. In that case I wonder if this would make sense-
[ul]
1 Add the ESP+Button as an MQTT sensor
2 Create a scene with most lights off for when we’re sleeping
3 Create a “Nightlight” scene for when we need to quickly turn the lights on
4 Create an event that listens for the sensor topic and triggers the nightlight scene
5 Add a condition that triggers the sleep scene if the nightlight is already triggered[/ul]

Or is there a simpler way to toggle between two scenes?

How many programmers does it take to build a lightswitch? :smiley:
If anybody else has succeeded in building a simple wireless toggle switch then by all means please do share your method… Otherwise, I’m going to declare that this seemingly simple function is proving to be anything but! Nevertheless,it is the type of thing where one has to question the value of having so many amazing automations at our calling when its impossible to physically turn anything on or off without a phone or computer…
Anyway, I thought I had it all figured out with adding the toggle button as a sensor rather than a switch but as soon as I restarted HASS with my new config my lights started going all Skynet on me flickering on and off and refusing all commands… I tried a couple different configs but in the end I’m afraid it all comes down to a phenomenon called “bounce” wherein too much interference on an analog pushbutton causes the client to constantly send out events… This Arduino article explains a little bit more- learn.acrobotic.com/tutorials/po … ush-button
The more I think about it, the more it occurs to me that the simple act of toggling an LED on which most of us began our programming journey is very much dependent on simple analog communications e.g power come on=light comes on/power goes off=light goes off and so on… The same process doesn’t carry over all that well to triggering big LEDs over a wireless network apparently…
So I’m back at square one and will gladly entertain any “its not really that complicated” comments if they lead to an actual working solution…

Here’s one way of doing it I guess, but its pretty specific to functioning as a standalone wifi connecting wall switch. It may be possible to dissect the code and extract the pieces that relate to the switching function itself…

Take a look at my post:
https://automic.us/forum/viewtopic.php?f=4&t=43

While it demonstrates turning on and off an alarm using an RFID reader, you can modify it so that by presenting a token you turn on and off what ever you want.

Instead of the RFID reader a key switch, push button or some other mechanism can be used. When I have some free time I will try to come up with some kind of solution.

I know this is an old topic. I hope its still relevant. I want to achieve something very similar ( I think!) to this. I have an esp8266 nodeMCU. Plenty of pins and goodies. I basically want a relay, led, and push button. I want the button to trigger the relay and LED (locally, NOT over Mqtt) then report the relays state to the MQTT broker. I also want it receive on/off from the broker. Im using the default MQTT broker with HASS. I can do the simple MQTT on/off but I have gotten lost in the button!
Any help is much appreciated!