Easy way to handle multiple “if X on then Y on” rules

Hello everyone,

This is probably very low level for most of you here but it’s breaking my head a bit so I’m asking for help :slight_smile:
I have a few situations where I have a disconnected switch, that when pressed turns on a remote relay.
Two concrete examples are:
A two gang switch on the wall:
Gang 1 turns on - Shelly plug turns on
Gang 2 turns on - a group of zigbee lights turn on.

Likewise when gangs turn off, their respective paired item also turns off.

The logic isn’t the problem for me, the problem is that I’m looking at my rules growing with basic logic that ideally should be done in one place, instead of multiple rules.

As it is right now I’m using OpenHABs “if this then that but only if” rule engine so I have:
A rule for when the gang is on, turns on the plug.
Another for the the gang 2 is on, turns on the lights.
A third and forth for when the gangs are off.
And just now I noticed that, obviously, when someone changes the state of the item that the gangs control, the gang itself does not reflect the state because I haven’t got a rule for that.

At this point I have to admit that I’m certain that I’m being dumb and that there must be a simpler way to achieve the same logic.

Help anyone?

You are doing it how I do it.

Keep it simple.

And just now I noticed that, obviously, when someone changes the state of the item that the gangs control, the gang itself does not reflect the state because I haven’t got a rule for that.

Can you explain what you want this to do

Oh right, I skimmed that part - the Shelly plug also has a button on it.
The rule says “if the gang is turned ON, turn the Shelly plug ON.”
But if someone presses the Shelly plug button to turn it off, the gang does not turn off (because I don’t have a rule for that).

So in the end I would need 4 rules for each switch - relay combo:
If x on then y on
If x off then y off
And the other way around:
If y on then x on
If y off then x off

Because certain relays also have buttons on them and you’d want to have the state synced both ways.

I thought that maybe a group could sync the state between all items but I think that it’s only if the group itself gets the command. Maybe if the rule sent the command to the group instead… ooh… could that be it?

If I understand your use case correctly, I have a similar setup in my house where I synchronise “Virtual” switches to the actual device.

Create the item then one with the same name with a suffix of “_virt”. Add both of them to the trigger items for the JS rule below and they will stay in sync. Add as many devices as you to the same rule. You could also probably add the devices to a group and use that as the trigger, but I didnt bother.


if(event.itemName != undefined) 
{
//Stops script from running if triggered via OpenHAB console - Event would be undefined, and fail
    
  triggeringItem = items[event.itemName].name
  if(triggeringItem.indexOf("_virt") === (triggeringItem.length()-5))
    {
      otherItem = triggeringItem.substring(0,triggeringItem.length()-5)
    }
    else
      {
      otherItem = triggeringItem + "_virt"  
      }

  if (items[otherItem].state != items.getItem(triggeringItem).state) {
    console.log("Sync Virtual Switches Rule Running - Triggered by",triggeringItem,"- Changing item state for",otherItem,"to",items[triggeringItem].state);
    items[otherItem].sendCommand(items[triggeringItem].state);
  }
}

Have you considered using Groups with an aggregation function?

For example a Group:Switch:OR(ON,OFF) (if one ON then ON else OFF) would be ON if one of the switches are ON and OFF only if all the switches are OFF. You can then have one rule to command the light or whatever based on changes in the state of the Group Item and you don’t really have to worry about the states of the individual switches themselves.

As always Rich has great ideas.

Groups are grate if you want to have a bunch of items the same act individually or as a group.

It depends on what the shelly is controlling lets say it is a fan connected.

The user wants to turn the fan off but not the lights what do you want that button to do?

I use google voice for celling fans and lights. You can setup items so if you say turn off everything in the room everything defined will turn off.

If say you have a lamp plugged into the shelly then it would also not make sense if the user can’t just turn the lamp off without turning everything off.

As with any project you need to clearly define the scope of what you want to do and have a functional description of how you want it to work before starting coding.

If you have 10000 rules or 1 script file it doesn’t change the functionality. With 1 script file if you want to make a change and you create a bug it may take a lot longer to find than of you just change one rule. There is no right and wrong way to program only working and broken programs.

1 Like

Nothing as complicated as that :slight_smile: turn on switch on the wall, turn on the switch on a Shelly plug. But the opposite can also be true. The Shelly plug as a button, and if someone presses it, I’d like for the switch to keep synced to the plug. This is the fight that I’m having :slight_smile:

@rlkoshak has indeed shared a great suggestion as per usual :smiley: , i need some time to do some tests, maybe if I have a group with both the switch and the plug…

I’m not 100% sure if I got your setup right but in case of simple switches I would never implement items to represent their state. Instead just link the event channels to the items that you want to control. Why would you want to monitor this separately if you can make sure that it never gets out of sync in the first place.

Real world example:

I’m having trouble in expressing myself in a simpler way but my setup is just this: if switch is on then relay turns on.
I tried your suggestion but after selecting the thing I see no channels. Am I supposed to see them below?

I would start from the switch thing. There should be some event channels that you could link to the switch item linked to your Shelly thing. In my experience the UI sometimes does not show you all possibilities. In that case you can just add a different item and then change the code manually on the code tab.

Keep in mind that with the Group approach, you don’t necessarily need to keep the switches synced. It’s the state of the Group that matters and it’s the Group that you’ll use in your OH UIs and such. Commanding the Group will command ll members of the Group. But if you change the state of one of the members of the Group to ON, the Group will be ON.

Another way to use Groups for this would be to use a Script Action similar to what @glen_m demonstrates. The rule triggers by members of the Group changing and then you update those members of the Group whose state differs from the new state. This would be relatively simple to implement in Blockly. Using basic UI rules this is going to proliferate into a whole lot of rules. This is usually the point where you need to graduate to Blockly over simple UI rules.

Not all bindings provide an event Channel as often the ON/OFF state of the device is in fact meaningful. I don’t think I’ve seen a binding that provides anything but state Channels for something like a relay.

When it comes to Channels on a Thing, the UI will show everything. You might need to check “Show Advanced” in some cases if the binding author has decided that some Channels are less commonly used than others. It’s mainly Profiles where MainUI will not show all possibilities depending on the type of the Channel and the Item, but I think even that has been fixed.

The relay itself does not need an event channel, just the switch (see my example above). But I agree that of course it largely depends on the binding implementation whether this approach can be used or not.

That would be really cool. It gave me headaches more than once that I could not link stuff even though it should be technically possible :+1:

Maybe this helps I have a largish script that handles 8+ switches depending on available power.
But one could also simply run un a cron job / timer. every couple of seconds plus event trigger.
I do store the actual / requested switch / toggle status in an extra item xx_already_on or so.

The script starts and gets actual and already on and compares these indicating a fail if not equal.
This gives me an indication of switch failure, coms failure, partial power failure etc and regulates itself (or not)

So get s1 & s2 &s3 actual plus s1 stored s2 stored etc. compare if not equal do something.

M

1 Like

Bem vindo irmão! Congrats on your first post and thank you for the hint! :tada:

Ok, that is the same type of use case as I have in my home.

As an example:

ItemA is a device which has the load which can be controlled independently of OpenHAB. Say for an example its a CBUS relay channel with a light attached over in my shed. There are local CBUS switches in the shed which can turn on/off the light

ItemA_virt is a counterpart channel over in the house. It is also on a completely separate CBUS network to my shed so it cannot directly control the load, but allows me to turn on shed lights etc from CBUS wallswitches in the house before I walk over to the shed, (Synced by the rule I posted earlier)

If someone turns on the light in the shed using a switch in the shed, the state/indicator on the switch over in the house will reflect the status, and visa versa (along with the load itself).

The underlying technology/binding doesn’t really matter here… I use this to sync items across CBUS to CBUS, CBUS to MQTT etc.

I also started with a separate rule for each pair of items, and eventually refactored it to be one generic rule covering all items I wanted synced. Only thing is the rule requires the corresponding item to have the exact same item name with a “_virt” suffix.

And then just keep adding all the items (including the _virt) to the rule triggers.

As I mentioned, I never got around to the next step of creating a triggering group approach, where you dont need to add individual items to the rule, but I have been happy with the current solution.

Sorry if the first response was a bit incomplete… Working off a phone at present, and if you require, can give any additional information you require when I am back at a computer next week

With MQTT, I set my state update to “postCommand” (see MQTT Things and Channels - Bindings | openHAB) and I quote here:

  • postCommand: If true, the received MQTT value will not only update the state of linked items, but command it. The default is false. You usually need this to be true if your item is also linked to another channel, say a KNX actor, and you want a received MQTT payload to command that KNX actor.

Let me describe the hypothetical set up first:

  • Hallway_Switch1 A “button” input that toggles, but otherwise not physically connected to the light. To openhab it’s a simple SwitchItem (on/off). This is physically located at one end of the hallway.

  • Hallway_Switch2 another button that does the same as above, located at the other end of the hallway

  • Hallway_Switch3 yet another button to control the hallway light, same as above, but located at the front entry

  • Hallway_Light1 a tuya mqtt SwitchItem to control on/off

  • Hallway_Light2 a tuya mqtt SwitchItem to control on/off

  • … more lights if necessary

Each of the light “buttons” have its own indicator light on/off. When the light is on, the indicator light is on, and vice versa.

Add all of these items into a group, e.g. Hallway_Lights

Add a rule with “member of Hallway_Lights received command” and just propagate that command to the rest of the members whose state isn’t the same.

To make this generic, you can have other “groups” setup the same way, e.g. Kitchen_Lights, Outdoor_Lights, etc. Each of these groups will have members which are their corresponding switches and lights for that group.

Then you have a super group containing the list of all these “Groups”, e.g.

Synchronized_Groups members: Hallway_Lights, Kitchen_Lights, Outdoor_Lights, etc.

Deal with them with one rule. Example in jruby:

Synchronized_Groups.members.each do |synchronized_group|
  received_command(synchronized_group.members) { |event| event.group.members.ensure.command event.command }
end

So now you can control the lights using any of the buttons, or even through tuya app, and everything will be synchronised.

Note in jruby, event.group is the equivalent of triggeringGroup in RulesDSL.

…except triggeringGroup doesn’t work in RulesDSL.

For an even “simpler” setup, put all those things to be synchronised in one single global group Synchronized_Items, and also give them the correct semantics, then you can infer the group from the semantics, e.g. location, or equipment. This means you won’t need to have individual groups like Hallway_Lights, Kitchen_Lights, Outdoor_Lights, etc.

Example code in JRuby:

received_command(Synchronized_Items.members) do |event|
  event.group.members.select { |sync_item| sync_item.location == event.item.location }.ensure.command event.command
end

Olá Pedro, sometime ago I’ve posted a similar question, here’s Rich’s answer

BTW, the HA “gurus” in the portuguese domotics channel were not able to find such a simple solution, and like you have mentioned in the first post, suggested two rules (ON/OFF) for each device that can control others.