Lighting management with feedback using ESP8266 and electromechanical lighting relays

In this subforum you can show projects you have made, or you are busy with. Please create your own topic.
Post Reply
User avatar
Antori91
Posts: 114
Joined: Sunday 12 February 2017 18:12
Target OS: NAS (Synology & others)
Domoticz version: 4.97&3.5
Location: France
Contact:

Lighting management with feedback using ESP8266 and electromechanical lighting relays

Post by Antori91 » Wednesday 24 January 2018 9:17

Hello,

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 */
iotGM43_BancTests.JPG
iotGM43_BancTests.JPG (161.41 KiB) Viewed 1824 times
iotGM43_Installé.JPG
iotGM43_Installé.JPG (137.91 KiB) Viewed 1824 times
MySwitchesPanel.JPG
MySwitchesPanel.JPG (281.58 KiB) Viewed 1824 times
Last edited by Antori91 on Monday 18 June 2018 14:27, edited 2 times in total.
Domoticz High Availability Cluster: Synology Dz V3.5877 (Main) - Raspberry Dz V4.97 (Backup) - Scripts Node.js
Alarm server: Raspberry - motionEye - iot_ALARM-SVR Node.js
Sensors/Actuators: ESP8266-Arduino
https://github.com/Antori91/Home_Automation

User avatar
Antori91
Posts: 114
Joined: Sunday 12 February 2017 18:12
Target OS: NAS (Synology & others)
Domoticz version: 4.97&3.5
Location: France
Contact:

Re: Lighting management with feedback using ESP8266 and electromechanical lighting relays

Post by Antori91 » Monday 18 June 2018 14:25

Hello,
The latest code version is here : https://github.com/Antori91/Home_Automa ... 6_GM43.ino
Domoticz High Availability Cluster: Synology Dz V3.5877 (Main) - Raspberry Dz V4.97 (Backup) - Scripts Node.js
Alarm server: Raspberry - motionEye - iot_ALARM-SVR Node.js
Sensors/Actuators: ESP8266-Arduino
https://github.com/Antori91/Home_Automation

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest