Just an update on this project… I have made a current monitor PCB that has 8 channels using SCT-013-005 current transformers.
So basicaly my setup comprises 2 Sonoff 4 channel pro devices flashed with Tasmota and an Arduino Mega dealing with the current sensing on 8 channels. I have the 4 channel pro units because they are wired the same as two way and three way lighting circuits as below-:
The reason for the current sensing is to tell Openhab the physical state of the light in the room, so with my Alexa integration the system always knows this physical state.
My Arduino sketch, credit where due to the guys over at Openenergymonitor for the Emonlib library-:
/*
Prototype sensor to feedback state of lighting circuits to Openhab2 via MQTT
*/
/*-----( Declare Constants )-----*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include "EmonLib.h" // Include Emon Library
const char* mqttServer = "192.168.1.119";
const int mqttPort = 1883;
const char* mqttUser = "********";
const char* mqttPassword = "********";
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 250);
EthernetClient ethClient;
PubSubClient client(ethClient);
EnergyMonitor emon1, emon2, emon3, emon4, emon5, emon6, emon7, emon8; // Create eight instances
/*-----( Declare Variables )-----*/
bool sonoff4ch1_On = false;
bool sonoff4ch2_On = false;
bool sonoff4ch3_On = false;
bool sonoff4ch4_On = false;
bool sonoff4ch5_On = false;
bool sonoff4ch6_On = false;
bool sonoff4ch7_On = false;
bool sonoff4ch8_On = false;
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("arduinoClient")) {
Serial.println("Connected to MQTT Server");
// Once connected, publish an announcement...
client.publish("outTopic", "Reconnected to MQTT Server");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup()
{
Serial.begin(115200);
Ethernet.begin(mac, ip);
// Allow the hardware to sort itself out
delay(5000);
client.setServer(mqttServer, mqttPort);
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ArduinoClient", mqttUser, mqttPassword )) {
Serial.println("connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
emon1.current(A0, 5); // Current: input pin, Default calibration for 5v1A version is 5.
emon2.current(A1, 5); // Current: input pin, calibration.
emon3.current(A2, 5); // Current: input pin, calibration.
emon4.current(A3, 5); // Current: input pin, calibration.
emon5.current(A4, 5); // Current: input pin, calibration.
// emon6.current(A5, 5); // Current: input pin, calibration.
// emon7.current(A6, 5); // Current: input pin, calibration.
// emon8.current(A7, 5); // Current: input pin, calibration.
}
}
void loop()
{
if (!client.connected()) {
reconnect();
}
// Channel 1
double Irms = emon1.calcIrms(1480); //extract Irms into Variable
Serial.println(Irms);
if ((Irms >= 0.08) && !sonoff4ch1_On) { //Each current setting will be different for different lighting circuits
// these may have to be adjusted to suit
Serial.println("Sonoff4ch1 light is ON");
client.publish("arduino/channel1", "ON");
sonoff4ch1_On = true; //Remember what state the light is
}
else if ((Irms <= 0.079) && sonoff4ch1_On) //Each current setting will be different for different lighting
//circuits these may have to be adjusted to suit.
{
Serial.println("Sonoff4ch1 light is OFF");
client.publish("arduino/channel1", "OFF");
sonoff4ch1_On = false; //Remember what state the light is
}
// Channel 2
double Irms2 = emon2.calcIrms(1480); //extract Irms2 into Variable
Serial.println(Irms2);
if ((Irms2 >= 0.08) && !sonoff4ch2_On) {
Serial.println("Sonoff4ch2 light is ON");
client.publish("arduino/channel2", "ON");
sonoff4ch2_On = true; //Remember what state the light is
}
else if ((Irms2 <= 0.079) && sonoff4ch2_On)
{
Serial.println("Sonoff4ch2 light is OFF");
client.publish("arduino/channel2", "OFF");
sonoff4ch2_On = false; //Remember what state the light is
}
// Channel 3
double Irms3 = emon3.calcIrms(1480); //extract Irms3 into Variable
Serial.println(Irms3);
if ((Irms3 >= 0.08) && !sonoff4ch3_On) {
Serial.println("Sonoff4ch3 light is ON");
client.publish("arduino/channel3", "ON");
sonoff4ch3_On = true; //Remember what state the light is
}
else if ((Irms3 <= 0.079) && sonoff4ch3_On)
{
Serial.println("Sonoff4ch3 light is OFF");
client.publish("arduino/channel3", "OFF");
sonoff4ch3_On = false; //Remember what state the light is
}
// Channel 4
double Irms4 = emon4.calcIrms(1480); //extract Irms4 into Variable
Serial.println(Irms4);
if ((Irms4 >= 0.08) && !sonoff4ch4_On) {
Serial.println("Sonoff4ch4 light is ON");
client.publish("arduino/channel4", "ON");
sonoff4ch4_On = true; //Remember what state the light is
}
else if ((Irms4 <= 0.079) && sonoff4ch4_On)
{
Serial.println("Sonoff4ch4 light is OFF");
client.publish("arduino/channel4", "OFF");
sonoff4ch4_On = false; //Remember what state the light is
}
// Channel 5
double Irms5 = emon5.calcIrms(1480); //extract Irms into Variable
Serial.println(Irms5);
if ((Irms5 >= 0.08) && !sonoff4ch5_On) {
Serial.println("Sonoff4ch5 light is ON");
client.publish("arduino/channel5", "ON");
sonoff4ch5_On = true; //Remember what state the light is
}
else if ((Irms5 <= 0.079) && sonoff4ch5_On)
{
Serial.println("Sonoff4ch5 light is OFF");
client.publish("arduino/channel5", "OFF");
sonoff4ch5_On = false; //Remember what state the light is
}
/*
// Channel 6
double Irms6 = emon6.calcIrms(1480); //extract Irms into Variable
Serial.println(Irms6);
if ((Irms6 >= 0.05) && !sonoff4ch6_On) {
Serial.println("Sonoff4ch6 light is ON");
client.publish("arduino/channel6", "ON");
sonoff4ch6_On = true; //Remember what state the light is
}
else if ((Irms6 <= 0.049) && sonoff4ch6_On)
{
Serial.println("Sonoff4ch6 light is OFF");
client.publish("arduino/channel6", "OFF");
sonoff4ch6_On = false; //Remember what state the light is
}
// Channel 7
double Irms7 = emon7.calcIrms(1480); //extract Irms into Variable
Serial.println(Irms7);
if ((Irms7 >= 0.05) && !sonoff4ch7_On) {
Serial.println("Sonoff4ch7 light is ON");
client.publish("arduino/channel7", "ON");
sonoff4ch7_On = true; //Remember what state the light is
}
else if ((Irms7 <= 0.049) && sonoff4ch7_On)
{
Serial.println("Sonoff4ch7 light is OFF");
client.publish("arduino/channel7", "OFF");
sonoff4ch7_On = false; //Remember what state the light is
}
// Channel 8
double Irms8 = emon8.calcIrms(1480); //extract Irms into Variable
Serial.println(Irms8);
if ((Irms8 >= 0.05) && !sonoff4ch8_On) {
Serial.println("Sonoff4ch8 light is ON");
client.publish("arduino/channel8", "ON");
sonoff4ch8_On = true; //Remember what state the light is
}
else if ((Irms8 <= 0.049) && sonoff4ch8_On)
{
Serial.println("Sonoff4ch8 light is OFF");
client.publish("arduino/channel8", "OFF");
sonoff4ch8_On = false; //Remember what state the light is
}*/
client.loop();
}
My Items file-:
//First 4 Channel Pro Sonoff for 2 way lighting
Switch Sonoff4ch_1Channel1 "Kitchen Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel1:state:default]", autoupdate="false" }
Switch Sonoff_relay1 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_1/POWER1:command:*:default],<[broker:stat/sonoff4chan_1/POWER1:state:default]" }
Switch Sonoff4ch_1Channel2 "Family Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel2:state:default]", autoupdate="false" }
Switch Sonoff_relay2 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_1/POWER2:command:*:default],<[broker:stat/sonoff4chan_1/POWER2:state:default]" }
Switch Sonoff4ch_1Channel3 "Dining Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel3:state:default]", autoupdate="false" }
Switch Sonoff_relay3 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_1/POWER3:command:*:default],<[broker:stat/sonoff4chan_1/POWER3:state:default]" }
Switch Sonoff4ch_1Channel4 "Office Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel4:state:default]", autoupdate="false" }
Switch Sonoff_relay4 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_1/POWER4:command:*:default],<[broker:stat/sonoff4chan_1/POWER4:state:default]" }
//Second 4 Channel Pro Sonoff for 2 way lighting
Switch Sonoff4ch_2Channel5 "Hall Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel5:state:default]", autoupdate="false" }
Switch Sonoff_relay5 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_2/POWER1:command:*:default],<[broker:stat/sonoff4chan_2/POWER1:state:default]" }
Switch Sonoff4ch_2Channel6 "Lounge Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel6:state:default]", autoupdate="false" }
Switch Sonoff_relay6 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_2/POWER2:command:*:default],<[broker:stat/sonoff4chan_2/POWER2:state:default]" }
Switch Sonoff4ch_2Channel7 "Bed1 Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel7:state:default]", autoupdate="false" }
Switch Sonoff_relay7 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_2/POWER3:command:*:default],<[broker:stat/sonoff4chan_2/POWER3:state:default]" }
Switch Sonoff4ch_2Channel8 "Bed2 Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel8:state:default]", autoupdate="false" }
Switch Sonoff_relay8 "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_2/POWER4:command:*:default],<[broker:stat/sonoff4chan_2/POWER4:state:default]" }
My Rules file -: Thanks to those above in this thread that helped out with the coding (I am better with hardware!)
rule "Sonoff4ch_1Channel1 Toggle"
when
Item Sonoff4ch_1Channel1 received command
then
if (receivedCommand != Sonoff4ch_1Channel1.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay1.state == OFF) {
Sonoff_relay1.sendCommand(ON)
} else {
Sonoff_relay1.sendCommand(OFF)
}
} // else already in requested state
end
rule "Sonoff4ch_1Channel2 Toggle"
when
Item Sonoff4ch_1Channel2 received command
then
if (receivedCommand != Sonoff4ch_1Channel2.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay2.state == OFF) {
Sonoff_relay2.sendCommand(ON)
} else {
Sonoff_relay2.sendCommand(OFF)
}
} // else already in requested state
end
rule "Sonoff4ch_1Channel3 Toggle"
when
Item Sonoff4ch_1Channel3 received command
then
if (receivedCommand != Sonoff4ch_1Channel3.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay3.state == OFF) {
Sonoff_relay3.sendCommand(ON)
} else {
Sonoff_relay3.sendCommand(OFF)
}
} // else already in
end
rule "Sonoff4ch_1Channel4 Toggle"
when
Item Sonoff4ch_1Channel4 received command
then
if (receivedCommand != Sonoff4ch_1Channel4.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay4.state == OFF) {
Sonoff_relay4.sendCommand(ON)
} else {
Sonoff_relay4.sendCommand(OFF)
}
} // else already in
end
rule "Sonoff4ch_2Channel5 Toggle"
when
Item Sonoff4ch_2Channel5 received command
then
logInfo("Sonoff4ch_2Channel5","Toggle rule triggered")
if (receivedCommand != Sonoff4ch_2Channel5.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay5.state == OFF) {
Sonoff_relay5.sendCommand(ON)
} else {
Sonoff_relay5.sendCommand(OFF)
}
} // else already in
end
rule "Sonoff4ch_2Channel6 Toggle"
when
Item Sonoff4ch_2Channel6 received command
then
if (receivedCommand != Sonoff4ch_2Channel6.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay6.state == OFF) {
Sonoff_relay6.sendCommand(ON)
} else {
Sonoff_relay6.sendCommand(OFF)
}
} // else already in
end
rule "Sonoff4ch_2Channel7 Toggle"
when
Item Sonoff4ch_2Channel7 received command
then
if (receivedCommand != Sonoff4ch_2Channel7.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay7.state == OFF) {
Sonoff_relay7.sendCommand(ON)
} else {
Sonoff_relay7.sendCommand(OFF)
}
} // else already in
end
rule "Sonoff4ch_2Channel8 Toggle"
when
Item Sonoff4ch_2Channel8 received command
then
if (receivedCommand != Sonoff4ch_2Channel8.state) {
// only if new request does not match actual current state
// then we need to toggle the relay state
if (Sonoff_relay8.state == OFF) {
Sonoff_relay8.sendCommand(ON)
} else {
Sonoff_relay8.sendCommand(OFF)
}
} // else already in
end
and my sitemap that shows physical state of the light not the relay-:
sitemap home label="The Crumps"
{
Frame label="Outside Lighting"
Frame label="Garage Control" {
Text item=GarageDoorSensor icon="garagedoor-closed"
Switch item=GarageDoor icon="garagedoor-open" mappings=[ON="OPEN/CLOSE"]
}
Frame label="Main Lighting"
{
Switch item=Sonoff4ch_1Channel1 label="Kitchen Lights" icon="light"
Switch item=Sonoff4ch_1Channel2 label="Family Lights" icon="light"
Switch item=Sonoff4ch_1Channel3 label="Dining Lights" icon="light"
Switch item=Sonoff4ch_1Channel4 label="Office Lights" icon="light"
Switch item=Sonoff4ch_2Channel5 label="Hall Lights" icon="light"
Text item=D1mini_pir1 icon="motion"
//Switch item=Sonoff4ch_2Channel6 label="Lounge Lights" icon="light"
//Switch item=Sonoff4ch_2Channel7 label="Bed1 Lights" icon="light"
//Switch item=Sonoff4ch_2Channel8 label="Bed2 Lights" icon="light"
}
}
Anyone thats interested here is the schematic for my PCB to go on an Arduino Mega (it has enough analogue inputs). I am also thinking of selling the PCB shield for a nominal sum in the future if anyone is interested.
Hope this helps others as it took me (with a lot of help!) a long time to figure through.
Rossko, thanks for the Associated items info. I didnt understand it when you posted that, and I still cant get my head around it but hopefully as I learn more I will… I understand its maybe not pretty but it works well so far…
Next task I am currently working on is to build in a motion sensor with a D1 Mini and PIR(with a custom adapter sheild), so prepare for questions @rlkoshak on your motion sensor timer script… I am trying to integrate it into the hallway.