I'm trying to trigger an action using the output of the callback function in my code. Basically, I will have a door sensor on "reedTopic" which needs to report "OFF" before allowing the payload for "topic" to be sent. The "topic" payload is a toggle for a garage door opener so the data from the "topic" will always remain the same.
The goal is for when the esp8266-01 that is plugged into my car connects to the wireless network, it will detect the status of the "reedTopic" and if it is not equal to "OFF" it will not trigger the "topic" payload.
I want to setup this automation completely in code and not have to rely on an additional software such as Node-Red or HomeAssistant to do the job.
I'm also pretty sure that I do not fully understand the callback function and how it is supposed to be used, especially in this case. I'm still bit of an Arduino newbie so this is really my first project. I'm also pretty sure that there is some garbage code in there as most of the code was spliced together from examples in the Arduino IDE for the pubsubclient handler.
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
const char* ssid = "******";
const char* password = "******";
const char* host = "CarPresence";
const char* update_path = "/";
const char* update_username = "*****";
const char* update_password = "*****";
char* topic = "cmnd/GarageDoor/POWER";
const char* willTopic = "cmnd/GarageDoor/POWER";
char* reedTopic = "cmnd/GarageDoor/POWER2";
char* server = "192.168.1.138";
byte willQoS = 1;
const char* willMessage = "1";
boolean willRetain = false;
boolean retained = true;
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
WiFiClient wifiClient;
PubSubClient client(server, 1883, wifiClient);
void callback(char* reedTopic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(reedTopic);
Serial.print("] ");
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]);
}
if (strcmp((char* )reedTopic, "OFF") == 0) {
client.connect("CarPresence", willTopic, willQoS, willRetain, willMessage);
client.publish(topic, "The Garage door is CLOSED... Opening...");
client.publish(topic, "1");
while (WiFi.status() == WL_CONNECTED) {
delay(5000);
client.println(reedTopic);
client.publish(topic, "Ah ah ah ah staying alive staying alive...");
}
}
if (strcmp((char* )reedTopic, "ON") == 0) {
client.publish(topic, "The Garage door is OPEN... Aborting...");
while (WiFi.status() == WL_CONNECTED) {
delay(5000);
client.println(reedTopic);
client.publish(topic, "Dying... I'm dying...");
}
}
Serial.println();
}
String macToStr(const uint8_t* mac)
{
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
if (i < 5)
result += ':';
}
return result;
}
void setup() {
Serial.begin(115200);
delay(10);
client.setCallback(callback);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
client.connect("CarPresence");
client.subscribe(topic);
client.subscribe(reedTopic, retained);
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
httpUpdater.setup(&httpServer, update_path, update_username, update_password);
httpServer.begin();
Serial.printf("HTTPUpdateServer ready! Open http://%s%s in your browser and login with username '%s' and password '%s'\n", host, update_path, update_username, update_password);
// Generate client name based on MAC address and last 8 bits of microsecond counter
String clientName = "CarPresence";
Serial.print("Connecting to ");
Serial.print(server);
Serial.print(" as ");
Serial.println(clientName);
if (client.connect((char*) clientName.c_str())) {
Serial.println("Connected to MQTT broker");
Serial.print("Topics are: ");
Serial.println(topic);
Serial.println(reedTopic);
if (client.publish(topic, "Hello from ESP8266")) {
Serial.println("Publish ok");
}
else {
Serial.println("Publish failed");
}
}
else {
Serial.println("MQTT connect failed");
Serial.println("Will reset and try again...");
abort();
}
}
void loop() {
httpServer.handleClient();
client.setCallback(callback);
while (WiFi.status() != WL_CONNECTED) {
delay(5000);
Serial.print(".");
}
}
For the most part the code works. The biggest problem is the IF statement surrounding the reedTopic feedback. The code blows straight past it and executes the topic payload without a second glance.
I managed to get some help from the author of the PubSubClient on GitHub. I later found the rest of what I needed on the Arduino Forums. Here is my completed code below.
// Setup your sonoff //
// Flash your sonoff switch with tasmota //
// Associate the tasmotized sonoff with your WiFi network //
// Load the webpage for the sonoff and setup your mqtt topics //
// Go into module setup and set GPIO14 to Switch2 //
// Go into the console and type "SwitchMode2 1" (without quotes) //
// Lastly, in the console type "PulseTime 1" (without quotes) //
// Setup credentials in the code //
// Replace asterisks next to ssid & password with WiFi credentials //
// Replace asterisks next to update_username & update_password with creds //
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
const char* ssid = "******";
const char* password = "******";
const char* host = "CarPresence";
const char* update_path = "/";
const char* update_username = "******";
const char* update_password = "******";
char* topic = "cmnd/GarageDoor/POWER";
const char* willTopic = "cmnd/GarageDoor/POWER";
char* reedTopic = "cmnd/GarageDoor/POWER2";
char* server = "192.168.1.138";
byte willQoS = 1;
const char* willMessage = "1";
boolean willRetain = false;
boolean retained = true;
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
WiFiClient wifiClient;
PubSubClient client(wifiClient);
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("CarPresence")) {
Serial.println("connected");
// set callback and subscribe to topics
client.setCallback(callback);
client.subscribe("cmnd/GarageDoor/POWER");
client.subscribe("cmnd/GarageDoor/POWER2");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void callback(char* reedTopic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(reedTopic);
Serial.print("] ");
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]);
}
Serial.println();
payload[length] = '\0';
String message = (char*)payload;
if(message == "ON"){
client.publish(topic, "Garage Door is CLOSED");
client.publish(topic, "1");
delay(10000);
while(message != "ON"){
break;
}
}
if(message == "OFF"){
client.publish(topic, "Garage Door is OPEN");
delay(10000);
while(message != "OFF"){
break;
}
}
}
String macToStr(const uint8_t* mac)
{
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
if (i < 5)
result += ':';
}
return result;
}
void setup() {
Serial.begin(115200);
delay(10);
Serial.println();
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());
httpUpdater.setup(&httpServer, update_path, update_username, update_password);
httpServer.begin();
Serial.println("HTTPUpdateServer ready!");
// Generate client name based on MAC address and last 8 bits of microsecond counter
String clientName = "CarPresence";
client.setServer(server, 1883);
client.setCallback(callback);
client.connect("CarPresence", willTopic, willQoS, willRetain, willMessage);
client.subscribe(topic);
client.subscribe(reedTopic, retained);
Serial.print("Connecting to ");
Serial.print(server);
Serial.print(" as ");
Serial.println(clientName);
if (client.connect((char*) clientName.c_str())) {
Serial.println("Connected to MQTT broker");
Serial.print("Topics are: ");
Serial.println(topic);
Serial.println(reedTopic);
if (client.publish(topic, "Hello from ESP8266")) {
Serial.println("Publish ok");
}
else {
Serial.println("Publish failed");
}
}
else {
Serial.println("MQTT connect failed");
Serial.println("Will reset and try again...");
reconnect();
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
httpServer.handleClient();
client.publish(topic, "Keeping Alive");
delay(2000);
while (WiFi.status() != WL_CONNECTED) {
delay(5000);
Serial.print(".");
}
}
The code will also be posted in a gist on GitHub. https://gist.github.com/hyukishi