sqozz
0356892526
This enables the nodemcu to listen for multiple topics. First comes the subsystem which is then followed by parameters for that specific subsystem. For 433MHz sockets this subsystem is called "rfsockets". It operates on "rfsockets/<socket_name>/(status|switch)" wher it accepts and reports with either "ON" or "OFF" as payloads. The subsystem therefore complies with the Home Assistant mqtt component.
272 lines
7.4 KiB
C++
272 lines
7.4 KiB
C++
#include <ESP8266WiFi.h>
|
|
#include <WiFiClient.h>
|
|
#include <PubSubClient.h>
|
|
#include <RCSwitch.h>
|
|
#include "secrets.h"
|
|
|
|
#define MQTT_VERSION MQTT_VERSION_3_1_1
|
|
|
|
RCSwitch mySwitch = RCSwitch();
|
|
|
|
typedef struct {
|
|
char* channel;
|
|
char* id;
|
|
char name[255];
|
|
bool powered;
|
|
uint8_t type; // 0=DIP, 1=Learned
|
|
int on_code;
|
|
int off_code;
|
|
} PowerSocket;
|
|
|
|
// see struct for description of fields
|
|
PowerSocket sockets[] = {
|
|
(PowerSocket) {"00000", "10000", "A", false, 0, -1, -1},
|
|
(PowerSocket) {"00000", "01000", "B", false, 0, -1, -1},
|
|
(PowerSocket) {"00000", "00100", "C", false, 0, -1, -1},
|
|
(PowerSocket) {"00000", "00010", "D", false, 0, -1, -1},
|
|
(PowerSocket) {"", "", "E", false, 1, 530800, 713872},
|
|
(PowerSocket) {"", "", "F", false, 1, 172340, 409380},
|
|
(PowerSocket) {"", "", "G", false, 1, 842428, 409388},
|
|
(PowerSocket) {"", "", "H", false, 1, 713874, 530802}
|
|
};
|
|
|
|
int numofsockets = sizeof(sockets)/sizeof(sockets[0]);
|
|
|
|
// MQTT: ID, server IP, port, username and password
|
|
const PROGMEM char* MQTT_CLIENT_ID = "multi-esp";
|
|
const PROGMEM char* MQTT_SERVER_IP = "10.42.0.3";
|
|
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;
|
|
// TODO: check if needed?
|
|
//const PROGMEM char* MQTT_USER = "[Redacted]";
|
|
//const PROGMEM char* MQTT_PASSWORD = "[Redacted]";
|
|
|
|
|
|
|
|
//// MQTT: topics
|
|
//const char* MQTT_LIGHT_STATE_TOPIC = "balcony/hanging_lamp/status";
|
|
//const char* MQTT_LIGHT_COMMAND_TOPIC = "balcony/hanging_lamp/switch";
|
|
|
|
const char* MQTT_RFSOCKET_SUBSYSTEM = "rfsockets/";
|
|
const char* MQTT_RFSOCKET_STATE_TOPIC = "/status";
|
|
const char* MQTT_RFSOCKET_COMMAND_TOPIC = "/switch";
|
|
|
|
// payloads by default (on/off)
|
|
const char* LIGHT_ON = "ON";
|
|
const char* LIGHT_OFF = "OFF";
|
|
|
|
WiFiClient wifiClient;
|
|
PubSubClient client(wifiClient);
|
|
|
|
// function called to publish the state of the light (on/off)
|
|
void publishLightState(int socketIdx) {
|
|
char *socket_name = sockets[socketIdx].name;
|
|
char topic[strlen(MQTT_RFSOCKET_SUBSYSTEM) + strlen(MQTT_RFSOCKET_STATE_TOPIC) + strlen(socket_name)];
|
|
strcpy(topic, MQTT_RFSOCKET_SUBSYSTEM);
|
|
strcat(topic, socket_name);
|
|
strcat(topic, MQTT_RFSOCKET_STATE_TOPIC);
|
|
|
|
if (sockets[socketIdx].powered) {
|
|
client.publish(topic, LIGHT_ON, true);
|
|
} else {
|
|
client.publish(topic, LIGHT_OFF, true);
|
|
}
|
|
}
|
|
|
|
// function called to turn on/off the light
|
|
void setLightState(byte socketIdx) {
|
|
if (sockets[socketIdx].powered) {
|
|
setSocket(socketIdx, true);
|
|
Serial.println("INFO: Turn light on...");
|
|
} else {
|
|
setSocket(socketIdx, false);
|
|
Serial.println("INFO: Turn light off...");
|
|
}
|
|
}
|
|
|
|
// function called when a MQTT message arrived
|
|
void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
|
|
// concat the payload into a string
|
|
String payload;
|
|
for (uint8_t i = 0; i < p_length; i++) {
|
|
payload.concat((char)p_payload[i]);
|
|
}
|
|
|
|
// handle message topic
|
|
Serial.print("Got a message on topic: ");
|
|
Serial.println(p_topic);
|
|
|
|
char *topic_ptr;
|
|
const char* delimiter = "/";
|
|
topic_ptr = strtok(p_topic, delimiter);
|
|
if (topic_ptr != NULL) {
|
|
char *subsystem = topic_ptr;
|
|
Serial.print("Found subsystem: ");
|
|
Serial.println(subsystem);
|
|
topic_ptr = strtok(NULL, delimiter);
|
|
if (topic_ptr != NULL) {
|
|
char *name = topic_ptr;
|
|
Serial.print("Found socket name: ");
|
|
Serial.println(name);
|
|
int socketIdx = findSocketIndex(name);
|
|
Serial.print("Found socket index ");
|
|
Serial.println(socketIdx);
|
|
// We only listen on the command channel so no further splitting needed
|
|
if (payload.equals(String(LIGHT_ON))) {
|
|
if (sockets[socketIdx].powered != true) {
|
|
sockets[socketIdx].powered = true;
|
|
setLightState(socketIdx);
|
|
publishLightState(socketIdx);
|
|
}
|
|
} else if (payload.equals(String(LIGHT_OFF))) {
|
|
if (sockets[socketIdx].powered != false) {
|
|
sockets[socketIdx].powered = false;
|
|
setLightState(socketIdx);
|
|
publishLightState(socketIdx);
|
|
}
|
|
} else {
|
|
Serial.print("Unknown payload received: ");
|
|
Serial.println(payload);
|
|
Serial.println("Ignoring it…\n");
|
|
}
|
|
} else {
|
|
Serial.print("Got topic without delimiter (");
|
|
Serial.print(delimiter);
|
|
Serial.print("), topic was:");
|
|
Serial.println(p_topic);
|
|
}
|
|
} else {
|
|
Serial.print("Got topic without delimiter (");
|
|
Serial.print(delimiter);
|
|
Serial.print("), topic was:");
|
|
Serial.println(p_topic);
|
|
}
|
|
}
|
|
|
|
void reconnect() {
|
|
// Loop until we're reconnected
|
|
while (!client.connected()) {
|
|
Serial.println("INFO: Attempting MQTT connection...");
|
|
// Attempt to connect
|
|
if (client.connect(MQTT_CLIENT_ID)) {
|
|
Serial.println("INFO: connected");
|
|
for (int i = 0; i < numofsockets; i++) {
|
|
publishLightState(i);
|
|
}
|
|
for (int i = 0; i < numofsockets; i++) {
|
|
char *socket_name = sockets[i].name;
|
|
char topic[strlen(MQTT_RFSOCKET_SUBSYSTEM) + strlen(MQTT_RFSOCKET_COMMAND_TOPIC) + strlen(socket_name)];
|
|
strcpy(topic, MQTT_RFSOCKET_SUBSYSTEM);
|
|
strcat(topic, socket_name);
|
|
strcat(topic, MQTT_RFSOCKET_COMMAND_TOPIC);
|
|
|
|
Serial.print("INFO: subscribing to topic \"");
|
|
Serial.print(topic);
|
|
Serial.println("\"");
|
|
client.subscribe(topic);
|
|
}
|
|
} else {
|
|
Serial.print("ERROR: failed, rc=");
|
|
Serial.print(client.state());
|
|
Serial.println("DEBUG: try again in 5 seconds");
|
|
// Wait 5 seconds before retrying
|
|
delay(5000);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool setSocket(int socketIdx, bool newStatus) {
|
|
PowerSocket socket;
|
|
bool success = false;
|
|
|
|
if (socketIdx >= 0) {
|
|
success = true;
|
|
socket = sockets[socketIdx];
|
|
socket.powered = newStatus;
|
|
sockets[socketIdx] = socket; // write back to status array
|
|
if (newStatus == true) {
|
|
for (char i = 0; i <= 1; i++) {
|
|
if (socket.type == 0) {
|
|
Serial.println("id socket");
|
|
mySwitch.setProtocol(1);
|
|
mySwitch.switchOn(socket.channel, socket.id);
|
|
} else if (socket.type == 1) {
|
|
Serial.println("learning socket");
|
|
mySwitch.setProtocol(5);
|
|
mySwitch.send(socket.on_code, 24);
|
|
}
|
|
delay(250);
|
|
}
|
|
} else {
|
|
for (char i = 0; i <= 1; i++) {
|
|
if (socket.type == 0) {
|
|
Serial.println("id socket");
|
|
mySwitch.setProtocol(1);
|
|
mySwitch.switchOff(socket.channel, socket.id);
|
|
} else if (socket.type == 1) {
|
|
Serial.println("learning socket");
|
|
char* off_code = socket.id;
|
|
mySwitch.setProtocol(5);
|
|
mySwitch.send(socket.off_code, 24);
|
|
}
|
|
delay(250);
|
|
}
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
int findSocketIndex(char *name) {
|
|
for (int socketIdx = 0; socketIdx < numofsockets; socketIdx++) {
|
|
PowerSocket canidateSocket = sockets[socketIdx];
|
|
if (strcmp(canidateSocket.name, name) == 0) {
|
|
Serial.print(canidateSocket.name);
|
|
Serial.print(" equals ");
|
|
Serial.println(name);
|
|
return socketIdx;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void setup() {
|
|
// setup serial
|
|
Serial.begin(115200);
|
|
Serial.println("Serial interface initialized");
|
|
|
|
WiFi.mode(WIFI_STA);
|
|
Serial.print("Connecting to wifi ");
|
|
Serial.println(WIFI_SSID);
|
|
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
|
|
|
Serial.println("Enable transmission while waiting on wifi");
|
|
mySwitch.enableTransmit(2);
|
|
delay(1000);
|
|
Serial.print("Transmission enabled, waiting for wifi now.");
|
|
|
|
// Wait for connection
|
|
while (WiFi.status() != WL_CONNECTED) {
|
|
delay(500);
|
|
Serial.print(".");
|
|
}
|
|
|
|
// serial output of connection details
|
|
Serial.println("");
|
|
Serial.print("Wifi connected to ");
|
|
Serial.println(WIFI_SSID);
|
|
Serial.print("IP address: ");
|
|
Serial.println(WiFi.localIP());
|
|
|
|
// init the MQTT connection
|
|
client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
|
|
client.setCallback(callback);
|
|
}
|
|
|
|
void loop() {
|
|
if (!client.connected()) {
|
|
reconnect();
|
|
}
|
|
client.loop();
|
|
}
|