-
-
Save lukedemi/344964aed524f54e9a709061ad1139a6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <WiFi.h> | |
#include <HTTPClient.h> | |
#include <PubSubClient.h> | |
// Unique WiFi credentials | |
const char* wifiSSID = "R7000"; | |
const char* wifiPassword = "<fake>"; | |
// MQTT server details | |
const char* mqttServer = "192.168.1.48"; | |
const int mqttPort = 1883; | |
// Location variable | |
const char* location = "test2"; | |
// Node ID for the device | |
char nodeID[50]; | |
// MQTT topics | |
char commandTopic[150]; | |
char stateTopic[150]; | |
char configTopic[150]; | |
// GPIO pin for controlling the Thermacell device | |
const int controlPin = 2; // GPIO2 | |
const int statusPin = 3; // GPIO3 | |
// Variables for status updates | |
long lastStatusUpdate = 0; | |
const long statusUpdateInterval = 10000; // 10 seconds | |
// Variables for discovery message retries | |
long lastDiscoveryAttempt = 0; | |
const long discoveryAttemptInterval = 30000; // 30 seconds | |
int discoveryAttempts = 0; | |
const int maxDiscoveryAttempts = 5; | |
WiFiClient espClient; | |
PubSubClient client(espClient); | |
// Declare uniqueID as a global variable | |
String uniqueID; | |
void setup() { | |
Serial.begin(115200); // Start the Serial communication to send messages to the computer | |
pinMode(controlPin, OUTPUT); // Set the control pin as an output | |
digitalWrite(controlPin, LOW); // Ensure the control pin is in a known state (off) | |
// Initialize the WiFi in station mode | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(wifiSSID, wifiPassword); | |
// Wait for WiFi to connect | |
Serial.print("Connecting to WiFi"); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(1000); | |
Serial.print("."); | |
} | |
Serial.println(" connected"); | |
// Get the MAC address and use it as unique ID | |
String macAddress = getMacAddress(); | |
uniqueID = String(location) + "_" + macAddress; | |
// Initialize MQTT topics | |
snprintf(nodeID, sizeof(nodeID), "%s_thermacell", location); | |
snprintf(commandTopic, sizeof(commandTopic), "homeassistant/switch/%s/%s/set", nodeID, uniqueID.c_str()); | |
snprintf(stateTopic, sizeof(stateTopic), "homeassistant/switch/%s/%s/state", nodeID, uniqueID.c_str()); | |
snprintf(configTopic, sizeof(configTopic), "homeassistant/switch/%s/%s/config", nodeID, uniqueID.c_str()); | |
connectToMQTT(); // Connect to the MQTT server | |
client.setCallback(callback); // Set the callback function for incoming MQTT messages | |
} | |
void loop() { | |
if (!client.connected()) { | |
reconnectMQTT(); // Reconnect to MQTT if the connection is lost | |
} | |
client.loop(); // Keep the MQTT connection alive | |
// Check if it's time to send a status update | |
long now = millis(); | |
if (now - lastStatusUpdate >= statusUpdateInterval) { | |
sendStatusUpdate(); | |
lastStatusUpdate = now; | |
} | |
// Retry sending the discovery message multiple times | |
if (discoveryAttempts < maxDiscoveryAttempts) { | |
if (now - lastDiscoveryAttempt >= discoveryAttemptInterval) { | |
publishDiscoveryMessage(); // Publish the discovery message for Home Assistant | |
lastDiscoveryAttempt = now; | |
discoveryAttempts++; | |
} | |
} | |
} | |
void connectToMQTT() { | |
client.setServer(mqttServer, mqttPort); | |
client.setBufferSize(512); | |
Serial.print("Connecting to MQTT"); | |
while (!client.connected()) { | |
if (client.connect("ESP32Client-1")) { // Use a different client ID | |
Serial.println(" connected"); | |
client.subscribe(commandTopic); // Subscribe to the control topic | |
} else { | |
Serial.print("."); | |
delay(2000); | |
} | |
} | |
} | |
void reconnectMQTT() { | |
Serial.print("Reconnecting to MQTT"); | |
while (!client.connected()) { | |
if (client.connect("ESP32Client-1")) { // Use a different client ID | |
Serial.println(" connected"); | |
client.subscribe(commandTopic); // Subscribe to the control topic | |
} else { | |
Serial.print("."); | |
delay(2000); | |
} | |
} | |
} | |
void callback(char* topic, byte* payload, unsigned int length) { | |
String message; | |
for (unsigned int i = 0; i < length; i++) { | |
message += (char)payload[i]; | |
} | |
Serial.print("Message arrived ["); | |
Serial.print(topic); | |
Serial.print("]: "); | |
Serial.println(message); | |
if (String(topic) == commandTopic) { | |
if (message == "ON") { | |
digitalWrite(controlPin, HIGH); // Set the GPIO to high to turn on the device | |
delay(500); | |
digitalWrite(controlPin, LOW); // Set the GPIO to low to turn off the device | |
client.publish(stateTopic, "ON", true); // Publish to MQTT | |
} else if (message == "OFF") { | |
digitalWrite(controlPin, HIGH); // Set the GPIO to high to turn on the device | |
delay(4000); | |
digitalWrite(controlPin, LOW); // Set the GPIO to low to turn off the device | |
client.publish(stateTopic, "OFF", true); // Publish to MQTT | |
} | |
} | |
} | |
void publishDiscoveryMessage() { | |
char discoveryMsg[512]; | |
// Create the discovery message with full topic paths | |
int msgLength = snprintf(discoveryMsg, sizeof(discoveryMsg), | |
"{\"name\": \"Thermacell %s\"," | |
"\"cmd_t\": \"%s\"," | |
"\"stat_t\": \"%s\"," | |
"\"pl_on\": \"ON\"," | |
"\"pl_off\": \"OFF\"," | |
"\"uniq_id\": \"%s\"}", | |
location, commandTopic, stateTopic, uniqueID.c_str()); | |
Serial.print("Discovery message length: "); | |
Serial.println(msgLength); | |
if (msgLength >= sizeof(discoveryMsg) || msgLength < 0) { | |
Serial.println("Error: Discovery message too long or formatting error."); | |
return; // Exit if the message is too long or there was an error | |
} | |
Serial.print("Publishing discovery message: "); | |
Serial.println(discoveryMsg); | |
if (client.connected()) { | |
if (client.publish(configTopic, discoveryMsg, true)) { | |
Serial.println("Discovery message published successfully"); | |
} else { | |
Serial.println("Failed to publish discovery message"); | |
} | |
} else { | |
Serial.println("MQTT client not connected"); | |
} | |
} | |
void sendStatusUpdate() { | |
int padValue = analogRead(statusPin); // Read the analog value from the pad | |
Serial.print("Pad Value: "); // Print the pad value | |
Serial.println(padValue); | |
if (padValue < 2000) { // Replace 2000 with an appropriate threshold value | |
Serial.println("Device might be ON"); | |
client.publish(stateTopic, "ON", true); | |
} else { | |
Serial.println("Device might be OFF"); | |
client.publish(stateTopic, "OFF", true); | |
} | |
} | |
String getMacAddress() { | |
byte mac[6]; | |
WiFi.macAddress(mac); | |
char macStr[18]; | |
snprintf(macStr, sizeof(macStr), "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | |
return String(macStr); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment