Add BH1750 subsystem

Currently the subsystem only supports one single sensor. It publishes
its state to lightsensor/livingroom_window/status every 5 seconds.
This commit is contained in:
sqozz 2018-07-13 19:31:57 +02:00
parent 0e0a10ae7b
commit 0e01a7de9b
1 changed files with 110 additions and 57 deletions

View File

@ -2,20 +2,57 @@
#include <WiFiClient.h> #include <WiFiClient.h>
#include <PubSubClient.h> #include <PubSubClient.h>
#include <RCSwitch.h> #include <RCSwitch.h>
#include <BH1750.h>
#include <Wire.h>
#include "secrets.h" #include "secrets.h"
#define MQTT_VERSION MQTT_VERSION_3_1_1 #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(); RCSwitch mySwitch = RCSwitch();
BH1750 lightMeter;
typedef struct { typedef struct {
char* channel; char* channel; // First DIP set
char* id; char* id; // Second DIP set
char name[255]; char name[255]; // human readable name (included in mqtt topic)
bool powered; bool powered; // last known power state of socket
uint8_t type; // 0=DIP, 1=Learned uint8_t type; // 0=DIP, 1=Learned
int on_code; int on_code; // ON code for self learning sockets (according to trained remote)
int off_code; int off_code; // Same as above but for OFF
} PowerSocket; } PowerSocket;
// see struct for description of fields // see struct for description of fields
@ -32,43 +69,47 @@ PowerSocket sockets[] = {
int numofsockets = sizeof(sockets)/sizeof(sockets[0]); int numofsockets = sizeof(sockets)/sizeof(sockets[0]);
// MQTT: ID, server IP, port, username and password
const PROGMEM char* MQTT_CLIENT_ID = "multi-esp"; // function called to measure and publish the state of the BH1750
const PROGMEM char* MQTT_SERVER_IP = "10.42.0.3"; void publishBH1750State() {
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883; uint16_t lux = lightMeter.readLightLevel();
// TODO: check if needed? char lux_string[10];
//const PROGMEM char* MQTT_USER = "[Redacted]"; itoa(lux, lux_string, 10);
//const PROGMEM char* MQTT_PASSWORD = "[Redacted]"; 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) // function called to publish the state of the rfsockets (on/off)
const char* LIGHT_ON = "ON"; void publishSocketState(int socketIdx) {
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 *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); strcpy(topic, MQTT_RFSOCKET_SUBSYSTEM);
strcat(topic, socket_name); strcat(topic, socket_name);
strcat(topic, MQTT_RFSOCKET_STATE_TOPIC); strcat(topic, MQTT_RFSOCKET_STATE_TOPIC);
if (sockets[socketIdx].powered) { if (sockets[socketIdx].powered) {
client.publish(topic, LIGHT_ON, true); client.publish(topic, LIGHT_ON, true);
} else { } else {
client.publish(topic, LIGHT_OFF, true); client.publish(topic, LIGHT_OFF, true);
} }
} }
// function called to turn on/off the light // function called to turn on/off the rfsockets
void setLightState(byte socketIdx) { void setSocketState(byte socketIdx) {
if (sockets[socketIdx].powered) { if (sockets[socketIdx].powered) {
setSocket(socketIdx, true); setSocket(socketIdx, true);
Serial.println("INFO: Turn light on..."); 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) { void subsystem_rfsockets(char *topic_ptr, String payload) {
const char* delimiter = "/"; const char* delimiter = "/";
topic_ptr = strtok(NULL, 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 (payload.equals(String(LIGHT_ON))) {
if (sockets[socketIdx].powered != true) { if (sockets[socketIdx].powered != true) {
sockets[socketIdx].powered = true; sockets[socketIdx].powered = true;
setLightState(socketIdx); setSocketState(socketIdx);
publishLightState(socketIdx); publishSocketState(socketIdx);
} }
} else if (payload.equals(String(LIGHT_OFF))) { } else if (payload.equals(String(LIGHT_OFF))) {
if (sockets[socketIdx].powered != false) { if (sockets[socketIdx].powered != false) {
sockets[socketIdx].powered = false; sockets[socketIdx].powered = false;
setLightState(socketIdx); setSocketState(socketIdx);
publishLightState(socketIdx); publishSocketState(socketIdx);
} }
} else { } else {
Serial.print("Unknown payload received: "); 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() { void reconnect() {
// Loop until we're reconnected // Loop until we're reconnected
while (!client.connected()) { while (!client.connected()) {
Serial.println("INFO: Attempting MQTT connection..."); Serial.println("INFO: Attempting MQTT connection...");
// Attempt to connect // Attempt to connect
if (client.connect(MQTT_CLIENT_ID)) { if (client.connect(MQTT_CLIENT_ID)) {
Serial.println("INFO: connected"); Serial.println("INFO: connected");
for (int i = 0; i < numofsockets; i++) { for (int i = 0; i < numofsockets; i++) {
publishLightState(i); publishSocketState(i);
} }
for (int i = 0; i < numofsockets; i++) { for (int i = 0; i < numofsockets; i++) {
char *socket_name = sockets[i].name; char *socket_name = sockets[i].name;
@ -167,14 +210,14 @@ void reconnect() {
Serial.println("\""); Serial.println("\"");
client.subscribe(topic); client.subscribe(topic);
} }
} else { } else {
Serial.print("ERROR: failed, rc="); Serial.print("ERROR: failed, rc=");
Serial.print(client.state()); Serial.print(client.state());
Serial.println("DEBUG: try again in 5 seconds"); Serial.println("DEBUG: try again in 5 seconds");
// Wait 5 seconds before retrying // Wait 5 seconds before retrying
delay(5000); delay(5000);
} }
} }
} }
bool setSocket(int socketIdx, bool newStatus) { bool setSocket(int socketIdx, bool newStatus) {
@ -261,14 +304,24 @@ void setup() {
Serial.print("IP address: "); Serial.print("IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
// setup bh1750 sensor
Wire.begin();
lightMeter.begin();
// init the MQTT connection // init the MQTT connection
client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT); client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
client.setCallback(callback); client.setCallback(callback);
} }
void loop() { void loop() {
if (!client.connected()) { if (!client.connected()) {
reconnect(); reconnect();
} }
client.loop(); client.loop();
if(abs(millis() - last_bh1750_publish) >= 5000){
Serial.println("Publishing BH1750 state");
publishBH1750State();
last_bh1750_publish = millis();
}
} }