I already use Domoticz for weather/temp data logging, alarm and heating management (see http://www.domoticz.com/forum/viewtopic ... 38&t=17032 ). I've deployed a new feature about lighting management. Among the lighting, there is two areas at my house with multiples lamps and multiple pushbuttons switches connected to two electromechanical lighting relays (GM43 series, a rather old LATCHING relay model) located at main panelboard.
For those two areas, I wanted to add Domoticz as "an additional pushbutton" able to know if lights are on (or off) and to switch on/off these two lighting areas. But I didn't want to change the pushbuttons or worst (meaning changing the wiring from the main panelboard !!) the way they are connected (pushbuttons to Neutral and Live only at the GM43 contacts).
The way I've done it :
- no change to the coil command with the pushbuttons,
- disconnect the lamps and the Live from the two GM43 relays contacts and use the contacts as a sensor/switch GPIO signal,
- use a WiFi Relay ESP8266 board with two relays to switch on/off the lamps of these two lighting areas.
Here is the Arduino sketch for the ESP8266. It uses MQTT to communicate with Domoticz.
Code: Select all
// @Antori91 http://www.domoticz.com/forum/memberlist.php?mode=viewprofile&u=13749
// ***** Lighting management
// Interfaces two GM43 devices with ElectroDragon IoT WiFi SPST/SPDT Relay board
// Lighting connected to relay *NO* output on SPDT (don't switch ON/OFF lamps during boot time)
// V0.3 First release - January 2018
// - CHANGE : Improve stability with use of an noise filter to read GPIO (digitalReadF instead of digitalRead)
// - CHANGE : Switch OFF relays at boot time to avoid desynchronization between internal state and lighting in case of unattended ESP8266 reset
// V0.1 - January 2018
// Initial Beta release
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// WiFi parameters
byte WiFi_AP = 1; // The WiFi Access Point we are connected to : 1 = main one or 2 = alternate one
const char *ssid = "YOUR MAIN WIFI SSID"; //$$
const char *password = "YOUR MAIN WIFI PASSWORD"; //$$
const char *ssid2 = "YOUR ALTERNATE WIFI SSID"; //$$
const char *password2 = "YOUR ALTERNATE WIFI PASSWORD"; //$$
// MQTT parameters
byte willQoS = 0;
char willMessage[MQTT_MAX_PACKET_SIZE+1];
boolean willRetain = false;
const char* mqtt_server = "192.168.1.45"; //$$ CERTIFICATION=192.168.1.103 $$ PROD=192.168.1.45
const char* topic_Domoticz_IN = "domoticz/in"; //$$
const char* topic_Domoticz_OUT = "domoticz/out"; //$$
char msgToPublish[MQTT_MAX_PACKET_SIZE+1];
WiFiClient espClient;
PubSubClient client(espClient);
// EDragon/ESP8266 board parameters
#define FILTER 3 // N same readings every 100 ms must be read to validate GPIO reading !
#define Relay1 12 // Digital Pin 12
#define Relay2 13 // Digital Pin 13
#define GPIO4 4 // GPIO-5 on SPDT connector
#define GPIO5 5 // GPIO-4 on SPDT connector
// Lighting parameters
String LIGHTING[2] = { "ENTREE", "MEZZANINE" }; //$$
String LIGHT_SWITCH_IDX[2] = { "50", "51" }; //$$ Corresponding DomoticZ switchs
String LIGHT_ACTIVE[2] = { "Off", "Off" }; // Lighting state (On or Off)
boolean LIGHT_CHANGED[2] = { true, true }; // Flag to know if we must update DomoticZ because people have changed Lighting state using home pushbuttons. Initialize to *true* to reset DomoticZ switchs at boot.
int cstate_GM43[2]; // GM43 current device status
int pstate_GM43[2]; // GM43 previous device status
const char* LIGHT_MQTT_ID = "LIGHTING";
void setup() { // ****************
Serial.begin(115200);
Serial.println("iot_EDRAGON_GM43_Lighting Booting - Firmware Version : 0.30");
pinMode(Relay1,OUTPUT);
pinMode(Relay2,OUTPUT);
digitalWrite(Relay1, LOW); // Lighting switch OFF
digitalWrite(Relay2, LOW);
pinMode(GPIO4,INPUT);
pinMode(GPIO5,INPUT);
pstate_GM43[0] = digitalReadF(GPIO4); cstate_GM43[0] = pstate_GM43[0];
pstate_GM43[1] = digitalReadF(GPIO5); cstate_GM43[1] = pstate_GM43[1];
// connect to WiFi Access Point
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection to the main WiFi Failed!");
PushbuttonsPressed();
delay(2000);
if( WiFi_AP == 1 ) {
WiFi_AP=2;
Serial.println("Trying to connect to the alternate WiFi...");
WiFi.begin(ssid2, password2);
} else {
WiFi_AP=1;
Serial.println("Trying to connect to the main WiFi...");
WiFi.begin(ssid, password);
}
} // while (WiFi.waitForConnectResult() != WL_CONNECTED) {
// if ( MDNS.begin ( "esp8266" ) ) Serial.println ( "MDNS responder started" );
// Port defaults to 8266
// ArduinoOTA.setPort(8266);
// Set OTA Hostname
ArduinoOTA.setHostname(LIGHT_MQTT_ID);
// Set OTA authentication password
ArduinoOTA.setPassword((const char *)"YOUR FOTA PASSWORD");
ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
// MQTT
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
// say we are now ready and give configuration items
Serial.println( "Ready" );
Serial.print ( "Connected to " ); if( WiFi_AP == 1 ) Serial.println( ssid ); else Serial.println( ssid2 );
Serial.print ( "IP address: " ); Serial.println( WiFi.localIP() );
Serial.print ( "Lighting " ); Serial.print(LIGHTING[0]); Serial.print(" set to : "); Serial.print(LIGHT_ACTIVE[0]); Serial.print(" - its GM43-GPIO4 is : "); Serial.println(cstate_GM43[0]);
Serial.print ( "Lighting " ); Serial.print(LIGHTING[1]); Serial.print(" set to : "); Serial.print(LIGHT_ACTIVE[1]); Serial.print(" - its GM43-GPIO5 is : "); Serial.println(cstate_GM43[1]);
} // void setup( ****************
void callback(char* topic, byte* payload, unsigned int length) { // ****************
DynamicJsonBuffer jsonBuffer( MQTT_MAX_PACKET_SIZE );
String messageReceived="";
// Affiche le topic entrant - display incoming Topic
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
// decode payload message
for (int i = 0; i < length; i++) {
messageReceived+=((char)payload[i]);
}
// display incoming message
Serial.print(messageReceived);
// if domoticz message
if ( strcmp(topic, topic_Domoticz_OUT) == 0 ) {
JsonObject& root = jsonBuffer.parseObject(messageReceived);
if (!root.success()) {
Serial.println("parsing Domoticz/out JSON Received Message failed");
return;
}
const char* idxChar = root["idx"];
String idx = String( idxChar);
if ( idx == LIGHT_SWITCH_IDX[0] ) {
const char* cmde = root["nvalue"];
if( strcmp(cmde, "0") == 0 ) { // 0 means we have to switch OFF the lamps
if( LIGHT_ACTIVE[0] == "On" ) { digitalWrite(Relay1, LOW); LIGHT_ACTIVE[0] = "Off"; }
} else if( LIGHT_ACTIVE[0] == "Off" ) { digitalWrite(Relay1, HIGH); LIGHT_ACTIVE[0] = "On"; }
Serial.print("Lighting "); Serial.print(LIGHTING[0]); Serial.print(" is now : "); Serial.println(LIGHT_ACTIVE[0]);
} // if ( idx == LIGHT_SWITCH_IDX[0] ) {
if ( idx == LIGHT_SWITCH_IDX[1] ) {
const char* cmde = root["nvalue"];
if( strcmp(cmde, "0") == 0 ) {
if( LIGHT_ACTIVE[1] == "On" ) { digitalWrite(Relay2, LOW); LIGHT_ACTIVE[1] = "Off"; }
} else if( LIGHT_ACTIVE[1] == "Off" ) { digitalWrite(Relay2, HIGH); LIGHT_ACTIVE[1] = "On"; }
Serial.print("Lighting "); Serial.print(LIGHTING[1]); Serial.print(" is now : "); Serial.println(LIGHT_ACTIVE[1]);
} // if ( idx == LIGHT_SWITCH_IDX[0] ) {
} // if domoticz message
delay(15);
} // void callback(char* to ****************
void reconnect() { // ****************
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
String string;
// Attempt to connect
string = "{\"command\" : \"addlogmessage\", \"message\" : \"Lighting went Offline - IP : " + WiFi.localIP().toString() + "\"}";
string.toCharArray( willMessage, MQTT_MAX_PACKET_SIZE);
// if ( client.connect(buf) ) {
if ( client.connect( LIGHT_MQTT_ID, topic_Domoticz_IN, willQoS, willRetain, willMessage ) ) {
Serial.println("connected");
// suscribe to MQTT topics
Serial.print("Subscribe to domoticz/out topic. Status=");
if ( client.subscribe(topic_Domoticz_OUT, 0) ) Serial.println("OK"); else Serial.println("KO");
// Wait ten seconds to try to be sure DomoticZ available after a DomoticZ server reboot (i.e. means avoid MQTT available but not yet DomoticZ)
delay(10000);
// Say now "Me the lighting, I'm here"
string = "{\"command\" : \"addlogmessage\", \"message\" : \"iot_EDRAGON_GM43_Lighting Online - Firmware Version : 0.30 - IP : " + WiFi.localIP().toString() + "\"}";
string.toCharArray( msgToPublish, MQTT_MAX_PACKET_SIZE);
Serial.print(msgToPublish);
Serial.print("Published to domoticz/in. Status=");
if ( client.publish(topic_Domoticz_IN, msgToPublish) ) Serial.println("OK"); else Serial.println("KO");
} else {
Serial.print("MQTT connection failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 2 seconds");
PushbuttonsPressed();
// Wait 2 seconds before retrying
delay(2000);
} // if (client.connect
} // while (!client.connected()) {
} // void reconnect() { ****************
byte digitalReadF(int GPIO) {
int i;
byte Reading = digitalRead(GPIO);
byte NextReading;
for( i=1; i <= FILTER ; i++ ) {
delay( 100 );
NextReading = digitalRead(GPIO);
if( NextReading != Reading ) { i = 1; Reading = NextReading; }
}
return( Reading );
} // byte digitalReadF(GPIO) {
void PushbuttonsPressed() { // ****************
cstate_GM43[0] = digitalReadF(GPIO4);
if( cstate_GM43[0] != pstate_GM43[0] ) {
pstate_GM43[0] = cstate_GM43[0];
LIGHT_CHANGED[0]=true;
if( LIGHT_ACTIVE[0] == "Off") {
digitalWrite(Relay1, HIGH); LIGHT_ACTIVE[0] = "On";
} else {
digitalWrite(Relay1, LOW); LIGHT_ACTIVE[0] = "Off";
} // if( LIGHT_ACTIVE[0] == "Off") {
} // if( cstate_GM43[0] != pstate_GM43[0] ) {
cstate_GM43[1] = digitalReadF(GPIO5);
if( cstate_GM43[1] != pstate_GM43[1] ) {
pstate_GM43[1] = cstate_GM43[1];
LIGHT_CHANGED[1]=true;
if( LIGHT_ACTIVE[1] == "Off") {
digitalWrite(Relay2, HIGH); LIGHT_ACTIVE[1] = "On";
} else {
digitalWrite(Relay2, LOW); LIGHT_ACTIVE[1] = "Off";
} // if( LIGHT_ACTIVE[0] == "Off") {
} // if( cstate_GM43[0] != pstate_GM43[0] ) {
} // void PushbuttonsPressed() ****************
void loop() { // ****************
if (!client.connected()) { // MQTT connection
reconnect();
}
ArduinoOTA.handle();
String string;
// Check if people have pressed a home pushbutton to change Lighting state
PushbuttonsPressed();
// if indeed a pushbutton was pressed, then update the corresponding DomoticZ switch
if( LIGHT_CHANGED[0] ) {
string = "{\"command\" : \"switchlight\", \"idx\" : " + LIGHT_SWITCH_IDX[0] + ", \"switchcmd\": \"" + LIGHT_ACTIVE[0] + "\"}";
string.toCharArray( msgToPublish, MQTT_MAX_PACKET_SIZE);
Serial.print(msgToPublish);
Serial.print(" Published to domoticz/in. Status=");
if ( client.publish(topic_Domoticz_IN, msgToPublish) ) { LIGHT_CHANGED[0] = false; Serial.println("OK"); } else Serial.println("KO");
}
if( LIGHT_CHANGED[1] ) {
string = "{\"command\" : \"switchlight\", \"idx\" : " + LIGHT_SWITCH_IDX[1] + ", \"switchcmd\": \"" + LIGHT_ACTIVE[1] + "\"}";
string.toCharArray( msgToPublish, MQTT_MAX_PACKET_SIZE);
Serial.print(msgToPublish);
Serial.print(" Published to domoticz/in. Status=");
if ( client.publish(topic_Domoticz_IN, msgToPublish) ) { LIGHT_CHANGED[1] = false; Serial.println("OK"); } else Serial.println("KO");
}
client.loop();
delay(100);
} // void loop() ****************
/* THE END */