Skip to content

Instantly share code, notes, and snippets.

@lukedemi
Created September 17, 2024 14:04
Show Gist options
  • Save lukedemi/344964aed524f54e9a709061ad1139a6 to your computer and use it in GitHub Desktop.
Save lukedemi/344964aed524f54e9a709061ad1139a6 to your computer and use it in GitHub Desktop.
#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