How does OH know the state of a switch?

Thanks I will have a play with this later when I get home.

That’s the problem. It’s that Alexa has no idea what the current light on/off state is. If you ask for “turn on”, it blindly sends ON. The mirroring is the oher way round - the Sonoff relay takes up Alexas commanded state.

As we already noted, Sonoff relay ON might mean light-on or it might mean light-off. Just passing along Alexa’s ON won’t do it.
You need that extra logic to work out current state and see if it needs changing, and then if it does changing how to change it.

So far none of the Switches “knows” the correct State, all you do is switching to the opposite. That s true for the Sonoff as well as for the hard-wired Switch. Alexa will only be able to switch the Sonoff. However the present implementation requires an explicit state to switch too. (all least that is what I understand without having one).

Why don’t you to give Alexa just a “switch” command.

See my two-item solution. virtual_switch ‘knows’ whether the light is on or off correctly, due to binding with @crumpy10 's current monitor. The rule translates requested ON and OFF into relay position A or B as required, to send to the hardware.
You tell Alexa (or the UI, or a motion-detect rule triggers) virtual_switch ON, the light turns on or stays on.

Hi Rossko & Opus,
I havent had much spare time to play but yahoo it looks like I (with your help!) got it working…
Heres my items-:

//First Sonoff TH16
//Switch SonoffTH "sonoff TH" <poweroutlet_au> (gLight) [ "Switchable" ] { mqtt=">[broker:cmnd/sonoffTH/POWER:command:*:default],<[broker:stat/sonoffTH/POWER:state:default]" }
 // Number SonoffTemp "Sonoff Temperature [%.1f °C]" <temperature> {mqtt="<[broker:tele/sonoffTH/SENSOR:state:JSONPATH($.AM2301.Temperature)]"}
 // Number SonoffHumidity "Sonoff Humidity [%d %%]" <humidity> {mqtt="<[broker:tele/sonoffTH/SENSOR:state:JSONPATH($.AM2301.Humidity)]"}
  
 //First 4 Channel Pro Sonoff for 2 way lighting
//Switch Sonoff4ch_1Channel1 "Kitchen Lights" <light> (gLight) [ "Switchable" ] { mqtt=">[broker:cmnd/sonoff4chan_1/POWER1:command:*:default],<[broker:stat/sonoff4chan_1/POWER1:state:default]" }
Switch Sonoff4ch_1Channel1 "Kitchen Lights" <light> (gLight) [ "Switchable" ] { mqtt=">[broker:cmnd/sonoff4chan_1/POWER1:command:*:default],<[broker:arduino/channel1:state:default]", autoupdate="false" }
Switch Sonoff4ch_1Channel2 "Family Lights" <light> (gLight) [ "Switchable" ] { 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:cmnd/sonoff4chan_1/POWER3:command:*:default],<[broker:stat/sonoff4chan_1/POWER3:state:default]" }
Switch Sonoff4ch_1Channel4 "Office Lights" <light> (gLight) [ "Switchable" ] { mqtt=">[broker:cmnd/sonoff4chan_1/POWER4:command:*:default],<[broker:stat/sonoff4chan_1/POWER4:state:default]" }

//Switch sonoffpow_1 "sonoffpow_1" <whitegood> (BA) [ "Switchable" ] { mqtt=">[broker:cmnd/sonoffpow_1/POWER:command:*:default],<[broker:stat/sonoffpow_1/POWER:state:default]" }

//Number BA_Washingmachine_Power "Washing Machine Power [%.1f W]" (BA,gPower)
 //   { mqtt="<[broker:tele/sonoffpow_1/SENSOR:state:JSONPATH($.ENERGY.Power)]" }

Switch Virtual_light "KitchenL" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel1:state:default]", autoupdate="false"}
Switch Sonoff_relay "2-way switch" { mqtt=">[broker:cmnd/sonoff4chan_1/POWER1:command:*:default],<[broker:stat/sonoff4chan_1/POWER1:state:default]" } 

and rule

rule "control lights toggling"
when
   Item Sonoff4ch_1Channel1 received command
then
   if (receivedCommand != Virtual_light.state) { 
          // only if new request does not mach actual current state
          // then we need to toggle the relay state
      if (Sonoff_relay.state == OFF) {
         Sonoff_relay.sendCommand(ON)
      } else {
         Sonoff_relay.sendCommand(OFF)
      }
   }  // else already in requested state
end

and sitemap

sitemap home label="The Crumps"
{
    Frame label="Weather"
    Frame label="Outside Lighting"
    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=Virtual_light label="Kitchen Lights" icon="Light"
    }
}

I had to change some of the code around a bit to make it work but a quick try and it all seems to be working! So a big thank you for all the hints. When I get the whole 4 channels up and running with sensors and code etc I will try and post a full explanation of how I did it, components, code and wiring etc

Cheers

Crumpy

“An exercise for the reader”
Seeing as you have multiple similar Items, this is an ideal case for deploying ‘Associated Items’ naming techniques with the vers 2.3 on Group rule triggers.
This allows all related Items to share one set of rules.

Use a scheme to name Items like myLight, myLight_sonoff, hisLight, hisLight_sonoff.
Group these items, e.g. gLights , gSonoffs
This will allow rules to work out the name of an associated Item from the name of the one it’s working with.
Rules can then retrieve the Item called XX from a given group.

Rules can triggered from Group member events e.g. member of gLights received command
Rule can get triggering Item name (that ‘member’), manipulate the string to add “_sonoff”, and search another Group by name string to get the Item that pairs with the light it started with.
And then go on to do its thing of course.

It’s a little more effort to implement to begin with, but is expandable to 4, 8, 400 Items easily, requiring only sticking to a naming convention.

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.

Well, just when you thought everything was working fine and no bugs, enter the Wife and kids…

So, if like normal human beings when a light is off, you ask Alexa to turn the light on, she does it. Or if its on you would ask to turn it off. If I do that my items and rules work fine but if like the wife and kids your are trying to confuse the hell out of anything AI in the home or prove that it does not work then you ask for the lights to be off when they are already off or on when they are already on.

Thats the bug that I cant work out why its happening. If you ask for OFF when the lights already OFF she turns them ON. If you ask for ON when they are already ON she turns them OFF.

You may ask why worry, teach them to ask for the right action. Yep that would work fine, but I am also using PIR’s on some circuits and they turn the lights on when they should not because of this rule…

Heres part of my Items

Switch Sonoff4ch_1Channel1 "Kitchen Lights" <light> (gLight) [ "Switchable" ] { mqtt=">[broker:cmnd/sonoff4chan_1/POWER1:command:*:default]", autoupdate="false" }
Switch Virtual_light1 <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]" } 

and here is the rule thats driving me crazy…

rule "Sonoff4ch_1Channel1 Toggle"
when
   Item Sonoff4ch_1Channel1 received command
then
   if (receivedCommand == Virtual_light1.state) {
      logInfo("Kitchen lights","Command same as state no action required")
      return;
   }
   if (receivedCommand != Virtual_light1.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

I added the first 4 lines after the ‘then’ to try and make sure that the rule stopped if the incoming request was the same as the current light state. Hence remove the ability for stupid requests but also stop the PIR’s turning the lights on…

Any ideas anyone?

To me your problem sounds confusing as in my mind it translates to a scenarios where both if statements are evaluated as true at seemingly the same time:
if (receivedCommand == Virtual_light1.state)
and
if (receivedCommand != Virtual_light1.state)
You write that you need to use a return statement to exit your rule in your first if clause. Unless I am missing something obvious, the two if clauses are mutually exclusive and it is inexplicable why both would execute at the same time. Well I am sure there is an explanation, but to me it is not yet obvious; for example, strange things can happen if your states change very quickly or if your rule gets triggered so quickly again that the first instance is still running, etc. Also check that each rule in your whole system has a unique name.

What exactly is the receivedCommand, Sonoff_relay8.state, Sonoff4ch_2Channel8.state and the Virtual_light1.state at the beginning of the rule and how do they change at the end? maybe things become clearer if you pepper your rule with a lot of logInfo statements that print out the states, rule starting and the commands received etc. But maybe you did that already and there was nothing to report.

On the other hand, feel free to ignore if I am missing something obvious…

Yes, it certainly is confusing the hell out of me. Yes I now see what you mean, I am not a programmer so this is not second nature to me, I am learning by examples and experimenting.

Yes I was trying to but it does not exit the rule, it carries on with the rule…?

It does, but worth checking.

This the command issued via Alexa to turn on or off the lights.

This is the physical state of a relay in a Sonoff 4 channel pro unit.

This is an item to be able to change the state of the relay.

This is a virtual light that stores the physical state of the light. ie if the light is physically on or off.
I have to do it this way because I have two and three way lighting circuits.

Why would I ignore any help. :grinning:

Sorry, I know what you want to represent by the items but I wanted suggest you log all their states at the beginning and the end of the rule and post what you find
Just to give an example:

rule "Sonoff4ch_1Channel1 Toggle" 
when
 Item Sonoff4ch_1Channel1 received command 
then
logInfo ("Kitchen lights", "Rule Sonoff4ch_1Channel1 Toggle started")
logInfo ("Kitchen lights", "Sonoff4ch_1Channel1 state at start of rule is: " + Sonoff4ch_1Channel1.state.toString)
logInfo ("Kitchen lights", "Virtual_light1 state at start of rule is: " + Virtual_light1.state.toString) 

and adding all other states. You can then take out the return and post the same block of logInfo at the end of your rule (adjusting the text of course), run it and look in your logfile to see what actually is happening
Note: the above is just typed in and not tested, some typos may exist.

I am sorry I dont know how to do that?

@crumpy10, apologies, I was already editing my post as I felt I had been to abstract. Post above now contains more detailed examples; hope that helps

Hi, Ah I see what you mean. OK I started with my original rule below and added the loginfo

rule "Sonoff4ch_1Channel1 Toggle"
when
   Item Sonoff4ch_1Channel1 received command
then

logInfo("Kitchen lights","Rule Sonoff4ch_1Channel1 Toggle started")
logInfo("Kitchen lights","Sonoff4ch_1Channel1 state at start of rule is: " + Sonoff4ch_1Channel1.state.toString)
logInfo("Kitchen lights","Virtual_light1 state at start of rule is: " + Virtual_light1.state.toString) 

   if (receivedCommand != Virtual_light1.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

logInfo("Kitchen lights","Rule Sonoff4ch_1Channel1 Toggle finished")
logInfo("Kitchen lights","Sonoff4ch_1Channel1 state at end of rule is: " + Sonoff4ch_1Channel1.state.toString)
logInfo("Kitchen lights","Virtual_light1 state at end of rule is: " + Virtual_light1.state.toString) 
end

Asked Alexa to turn the lights OFF (they were ON) and I get this in the log

2018-12-09 22:08:42.863 [ome.event.ItemCommandEvent] - Item 'Sonoff4ch_1Channel1' received command OFF

==> /var/log/openhab2/openhab.log <==

2018-12-09 22:08:44.589 [INFO ] [marthome.model.script.Kitchen lights] - Rule Sonoff4ch_1Channel1 Toggle started

2018-12-09 22:08:44.595 [INFO ] [marthome.model.script.Kitchen lights] - Sonoff4ch_1Channel1 state at start of rule is: NULL

2018-12-09 22:08:44.602 [INFO ] [marthome.model.script.Kitchen lights] - Virtual_light1 state at start of rule is: ON

2018-12-09 22:08:44.611 [INFO ] [marthome.model.script.Kitchen lights] - Rule Sonoff4ch_1Channel1 Toggle finished

==> /var/log/openhab2/events.log <==

2018-12-09 22:08:44.612 [ome.event.ItemCommandEvent] - Item 'Sonoff_relay1' received command ON

==> /var/log/openhab2/openhab.log <==

2018-12-09 22:08:44.620 [INFO ] [marthome.model.script.Kitchen lights] - Sonoff4ch_1Channel1 state at end of rule is: NULL

==> /var/log/openhab2/events.log <==

2018-12-09 22:08:44.625 [vent.ItemStateChangedEvent] - Sonoff_relay1 changed from OFF to ON

==> /var/log/openhab2/openhab.log <==

2018-12-09 22:08:44.628 [INFO ] [marthome.model.script.Kitchen lights] - Virtual_light1 state at end of rule is: ON

==> /var/log/openhab2/events.log <==

2018-12-09 22:08:45.573 [vent.ItemStateChangedEvent] - Virtual_light1 changed from ON to OFF

If I ask her to turn the lights OFF when they are already OFF then I get this in the log-: and she turns them ON

2018-12-09 22:13:20.929 [ome.event.ItemCommandEvent] - Item 'Sonoff4ch_1Channel1' received command OFF

==> /var/log/openhab2/openhab.log <==

2018-12-09 22:13:20.946 [INFO ] [marthome.model.script.Kitchen lights] - Rule Sonoff4ch_1Channel1 Toggle started

2018-12-09 22:13:20.956 [INFO ] [marthome.model.script.Kitchen lights] - Sonoff4ch_1Channel1 state at start of rule is: NULL

2018-12-09 22:13:20.964 [INFO ] [marthome.model.script.Kitchen lights] - Virtual_light1 state at start of rule is: OFF

2018-12-09 22:13:20.972 [INFO ] [marthome.model.script.Kitchen lights] - Rule Sonoff4ch_1Channel1 Toggle finished

2018-12-09 22:13:20.979 [INFO ] [marthome.model.script.Kitchen lights] - Sonoff4ch_1Channel1 state at end of rule is: NULL

2018-12-09 22:13:20.987 [INFO ] [marthome.model.script.Kitchen lights] - Virtual_light1 state at end of rule is: OFF

==> /var/log/openhab2/events.log <==

2018-12-09 22:13:21.035 [vent.ItemStateChangedEvent] - Sonoff_relay1 changed from ON to OFF

2018-12-09 22:13:23.078 [vent.ItemStateChangedEvent] - Virtual_light1 changed from OFF to ON

Its been a long day and I have work tomorrow so hopefully when I get a chance to look at it then it may be obvious what I have done wrong…

One thing that jumps out is this

Which could mean that something is wrong in your item definition as you defined your item with an incoming mqtt message that apparently is NULL

Also, as Alexa still does stuff when your rule has ended(at least the timestamps look that way) maybe try to get it down to the minimal configuration, and for example delete all the Switchable tags from your Virtual_light definitions, just to avoid confusion. Otherwise, double-check that you have not another rule that may get triggered and change the state of your lights. (if you want to be sure, just add to all your rules the logInfo rule started statement that you would see when anything else gets triggered)

1 Like

Yes I have just had a look at those logs after some sleep and that jumps out at me as well. Still dont unerstand why its half working but will have a look later when I am at home.

and I really dont know why the relay and the virtual light changes after the rule is finished.

Thanks for the advice so far.

Are you having Alexa command Sonoff4ch_1Channel1 ON/OFF ?
Don’t do that - it is linked/bound to a two-way switch where we’ve no idea if ON means light on or off.

I think it’s all got a bit muddled, with too many Items.
For a single channel,
Have one Item (lets call it myLight-N) that is linked only to the current monitor.
This item will “know” the real on/off state of the light.
This is the item to put on sitemap; this is the item to link to Alexa.

Have another Item (lets cal it myRelay-N) that is linked to the relay contact.
As that’s a two-way switch ON could be on or off, we don’t know.
Don’t link this to Alexa, don’t put on sitemap except as testing aid.

To make it all work, we need a rule that listens out for commands sent to myLight-N.
If the current myLight-N state does match the commanded state, then toggle myRelay-N


Looking at your existing collection, maybe the cleanest way out is
Bin all virtual_light items, redundant.
Modify Sonoff-XX-Channel Items to remove the outbound MQTT which is causing problems, leaving the current-sense inbound.
Leave the Sonoff_relay items alone
Leave the rules alone

1 Like

Thank you for the pointers @lipp_markus your way of logging makes a lot of sense to me and got me half way home. I will remember that one.

@rossko57 Thank you so much for making that understandable. The way you explained it filled in many gaps. I have amended my items and the rule had to be changed slightly to get rid of the virtual light. I am glad the code can be more streamlined, and understandable.

I have a question that is associated with these items. On one of the channels (which is a hallway light) I have a PIR as you may remember from another thread. It turns the light off after a set time if the kids leave it on.

Now the rule I have for this no longer works because the Sonoff4ch_1Channel5’ cannot be resolved to an item.
This is because Sonoff4ch_1Channel5 is not listening to the command from the rule.
Can I have two incoming parts in the items file for the same item?

eg

Switch Sonoff4ch_2Channel5 "Hall Lights" <light> (gLight) [ "Switchable" ] { mqtt="<[broker:arduino/channel5:state:default]", autoupdate="false",<[broker:cmnd/sonoff4chan_2/POWER1:command:*:default] }

or do I have to have two separate lines with the same item in, just different inbound MQTT?

Hope that makes sense.

I’m not sure what you’re trying to achieve there, but in general you can bind an Item to more than one channel. Inbound or outbound. It’s that ‘bus’ concept again.

You can’t have two Item definitions with the same name.

Obviously any current state reflects the last thing done to it - whether that’s an update from a binding or from a rule.


Away from generalisms, isn’t that arduino channel a PIR sensor? Why not bind it to an Item representing a PIR sensor, in a conventional way. There’s little logic in linking a PIR sensor to an item representing a light.

What I am trying to do is turn off the same light as Alexa can control either on or off. I have a presence sensor on a D1mini and PIR that sends MQTT ON/OFF, a rule sees the MQTT ON and sets a timer, after the timer expires I want the light to turn OFF. So the PIR isnt linked to the item(I dont think…)

I thought it would be just a case of commanding that item to turn OFF, then that would invoke the Toggle rule but I was wrong…

The Arduino channel is solely current sensors that send back the actual state of the physical light to the MQTT bus.

Items

//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 Sonoff4ch_2Channel5 "Hall Lights" <light> (gLight) [ "Switchable" ] { mqtt=">[broker:cmnd/sonoff4chan_1/POWER1:command:*: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]" }
*/

D1Mini items

//D1 Mini boards used with PIR's for presence detection

Switch D1mini_pir1 <pir> (gPresent) { mqtt="<[broker:stat/d1mini/pir1/POWER:state:default]" }

Motion detector rule

var Timer occupancyTimer = null
val int timeoutMinutes = 1 // choose an appropriate value

rule "D1mini_pir1 received ON"
when
    Item D1mini_pir1 received update ON
then
    logInfo("PIR1","RECEIVED UPDATE ON")
    if(occupancyTimer === null) {
        logInfo("PIR1","Creating Timer")
        occupancyTimer = createTimer(now.plusMinutes(timeoutMinutes ), [ |
            Sonoff4ch_2Channel5.sendCommand(OFF)
            occupancyTimer = null
            logInfo("PIR1","Timer Expired")
        ])
    }
    else {
        occupancyTimer.reschedule(now.plusMinutes(timeoutMinutes ))
        logInfo("PIR1","Timer Rescheduled")
    }
end

Light toggle Rule

rule "Sonoff4ch_2Channel5 Toggle"
when
   Item Sonoff4ch_2Channel5 received command
then
   if (receivedCommand != Sonoff4ch_1Channel5.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

I think most of this you have helped me with over a few months. The way I thought this would work is when the timer expires it sends the Sonoff4ch_2Channel5.sendCommand(OFF) and the toggle rule picks up that Sonoff4ch_2Channel5 has been asked to do something, the toggle rule then decides if the relay needs to be turned On or OFF…

Does that make sense?