Just to be clear… I was only using the topics from the MQTT Switch component page as an example. I’m aware that topics can be setup in any way. My question is related to how you add the topics within the arduino sketch since the pubsubclient library doesn’t let you add topics as definitions IIRC.
So if my topic tree were (for example) identical to that on the MQTT switch component page home/bedroom/switch1 and home/bedroom/switch1/set I’m trying to figure out how the arduino sketch would be changed to reflect that.
This schematic from this tutorial http://lawrencejeff.blogspot.com/2015/02/esp8266-and-openhab.html is the closest I could yet find to what I’m trying to do-
However, I would much rather use a method based on the sketch posted by @thaijames earlier in the thread. The problem is the wiring in the OpenHAB tutorial presumes only two GPIO ports will be available which is why GPIO0 must be set to high on boot. My controller is the same as the one pictured (ESP8266 v01) but I’m wondering if the sketch is intended for a more advanced version like the Node MCU or Adafruit Huzzah? Otherwise I can’t make sense of the references to GPIO4 and a built-in LED?
@thaijames- Will your sketch work with a generic ESP8266 v01?
Okay… I think I’m getting closer… It looks like the most challenging part of learning ESP8266 at present is in finding the most up-to-date documentation as it appears most of the earlier tutorials were written before the ESP boards were officially supported by the Arduino IDE. Many of which recommend overly complicated methods which have now been deprecated. I also had to sift through a lot of conflicting information about power sources for which my UartSBee/FTDI adapter functioned perfectly in 3.3v mode.
As of the present I have it wired akin to the following diagram-
This way the button can also double as a reset by pulling GPIO0 to ground-
Next I’ll try modifying the ESPwificlient sketch to accept GPIO0 as the input before sketching out my wiring for the physical button. Ideally, I’d like to use some Neopixel leds in place of the standard single color version but this may be farther down the road…
I’m probably getting ahead of myself here but I just thought of a much more interesting physical button setup… It would be similar enough to my current physical MQTT trigger button, only it would also incorporate a rotary pot and a neopixel ring. The form would be like a combination of a pushbutton LED and a rotary thermostat. A rotating ring around the plastic center globe would be connected to a potentiometer which would in turn change colors on a Neopixel ring. When the users selects a desired color, the pushbutton would send the color value to HASS using MQTT, which in turn triggers the corresponding color on the home lighting component.
While it might be possible to accomplish all of this with a single ESP8266, I’m probably going to use either an Arduino Yun or an Arduino+NRF24 transceiver for the time being.
In any case, I need to finish my first project before I can do anything else but I’m interested to hear what others think of this concept.
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/setOptional
payload: ‘on’
action:
service: scene.turn_on
entity_id: scene.baby_change - platform: mqtt
automation:
-
alias: ‘Baby Wake’
trigger:
- platform: mqtt
topic: home/bedroom/buttonswitch/setOptional
payload: ‘off’
action:
service: scene.turn_off
entity_id: scene.sleep[/code] - platform: mqtt
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?