diff --git a/multi-esp.ino b/multi-esp.ino index 99813a6..3dd2649 100644 --- a/multi-esp.ino +++ b/multi-esp.ino @@ -2,20 +2,57 @@ #include #include #include +#include +#include #include "secrets.h" #define MQTT_VERSION MQTT_VERSION_3_1_1 +// General MQTT settings +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]"; + + +// RFSOCKET subsystem mqtt topic components +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"; + + +// BH1750 subsystem mqtt topic components +// TODO: implement support for multiple sensors. +// (BH1750 can talk on two different i²c addr) +const char* MQTT_BH1750_SUBSYSTEM = "lightsensor/"; +const char* MQTT_BH1750_LOCATION = "livingroom_window"; +const char* MQTT_BH1750_STATE_TOPIC = "/status"; + +unsigned long last_bh1750_publish = millis(); + + + +WiFiClient wifiClient; +PubSubClient client(wifiClient); + RCSwitch mySwitch = RCSwitch(); +BH1750 lightMeter; + typedef struct { - char* channel; - char* id; - char name[255]; - bool powered; - uint8_t type; // 0=DIP, 1=Learned - int on_code; - int off_code; + char* channel; // First DIP set + char* id; // Second DIP set + char name[255]; // human readable name (included in mqtt topic) + bool powered; // last known power state of socket + uint8_t type; // 0=DIP, 1=Learned + int on_code; // ON code for self learning sockets (according to trained remote) + int off_code; // Same as above but for OFF } PowerSocket; // see struct for description of fields @@ -32,43 +69,47 @@ PowerSocket sockets[] = { 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]"; + +// function called to measure and publish the state of the BH1750 +void publishBH1750State() { + uint16_t lux = lightMeter.readLightLevel(); + char lux_string[10]; + itoa(lux, lux_string, 10); + char topic[ + strlen(MQTT_BH1750_SUBSYSTEM) + + strlen(MQTT_BH1750_LOCATION) + + strlen(MQTT_BH1750_STATE_TOPIC) + ]; + strcpy(topic, MQTT_BH1750_SUBSYSTEM); + strcat(topic, MQTT_BH1750_LOCATION); + strcat(topic, MQTT_BH1750_STATE_TOPIC); + + client.publish(topic, lux_string, true); +} -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) { +// function called to publish the state of the rfsockets (on/off) +void publishSocketState(int socketIdx) { char *socket_name = sockets[socketIdx].name; - char topic[strlen(MQTT_RFSOCKET_SUBSYSTEM) + strlen(MQTT_RFSOCKET_STATE_TOPIC) + strlen(socket_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); - } + 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) { +// function called to turn on/off the rfsockets +void setSocketState(byte socketIdx) { if (sockets[socketIdx].powered) { setSocket(socketIdx, true); Serial.println("INFO: Turn light on..."); @@ -78,6 +119,7 @@ void setLightState(byte socketIdx) { } } +// handler for mqtt messages arriving on that subsystems topic void subsystem_rfsockets(char *topic_ptr, String payload) { const char* delimiter = "/"; topic_ptr = strtok(NULL, delimiter); @@ -92,14 +134,14 @@ void subsystem_rfsockets(char *topic_ptr, String payload) { if (payload.equals(String(LIGHT_ON))) { if (sockets[socketIdx].powered != true) { sockets[socketIdx].powered = true; - setLightState(socketIdx); - publishLightState(socketIdx); + setSocketState(socketIdx); + publishSocketState(socketIdx); } } else if (payload.equals(String(LIGHT_OFF))) { if (sockets[socketIdx].powered != false) { sockets[socketIdx].powered = false; - setLightState(socketIdx); - publishLightState(socketIdx); + setSocketState(socketIdx); + publishSocketState(socketIdx); } } else { Serial.print("Unknown payload received: "); @@ -145,15 +187,16 @@ void callback(char* p_topic, byte* p_payload, unsigned int p_length) { } } +// handles initial connection and reconnect in case of failures 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"); + // 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); + publishSocketState(i); } for (int i = 0; i < numofsockets; i++) { char *socket_name = sockets[i].name; @@ -167,14 +210,14 @@ void reconnect() { 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); - } - } + } 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) { @@ -261,14 +304,24 @@ void setup() { Serial.print("IP address: "); Serial.println(WiFi.localIP()); + // setup bh1750 sensor + Wire.begin(); + lightMeter.begin(); + // init the MQTT connection client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT); client.setCallback(callback); } void loop() { - if (!client.connected()) { - reconnect(); - } - client.loop(); + if (!client.connected()) { + reconnect(); + } + client.loop(); + + if(abs(millis() - last_bh1750_publish) >= 5000){ + Serial.println("Publishing BH1750 state"); + publishBH1750State(); + last_bh1750_publish = millis(); + } }