Hi there, I am haveing a small Problem with switching a central light in my house.
It is needed to switch this light from five different places, that all have different things to sense the buttonpress.
What I need ist a possibility to update the state of all the connected points if one of the states changes.
My problem ist, that by changing the states with a rule I retrigger the rule.
My script is like this.
If button a oder button b or button c changes to on
change switch thing on
change a to on b to on c to on.
same for off.
These are all Items? All these Items are linked to Channels?
As long as you are not ending up in an infinite loop there really isn’t a problem. You don’t show your code but based on the way you wrote it there might be some things you can do to make that code simpler. But as long as the rule needs to be triggerable from any one of the switches, you cannot avoid retriggering the rule during the synchronization.
rule "Sync Switches and Light"
when
Member of gSyncSwitches changed
then
val newState = triggeringItem.state
gSyncSwitches.members.filter[ light | light.name != triggeringItem.name && light.state != newState ]
.forEach[ light | light.postUpdate(newState.toString) ]
end
This approach won’t really work the way you think it will. Since OH 3 each rule gets it’s very own thread but only one thread. That means if the rule triggers while it’s already running, it will queue up those triggers and work them off in sequence and in order.
So you will never have a case where the rule actually starts running and isRuleRunning is true. So all of that is doing nothing productive.
To avoid the infinite loop all you need to do is postUpdate instead of sendCommand to the other Items. Updates won’t cause the rule to trigger.
There are other problems too. triggeringItemName doesn’t exist in Member of triggered rules and newState doesn’t exist for command triggered rules.
rule "Sync Switches and Light"
when
Member of gSyncSwitches changed
then
gSyncSwitches.members.filter[ light | light.name != triggeringItem.name && light.state != newState ]
.forEach[ light | light.postUpdate(newState.toString) ]
end
That’s all you need. Making sure that only one instance of the rule runs at a time is handled by the rule engine for you. The filter avoids updating the Item that triggered the rule (probably unnecessary because even if you update it again, the state won’t change so there will be no infinite loop) or updating a switch that is already in the desired state (again not really necessary because of our choice in triggers, but it helps the queued triggers unroll really quickly).
If a changes state to ON:
rule triggers for a changing to ON
a. updates b, c, d, and e to ON
rule triggers for changing b to ON
a. nothing because, depending on timing, a, c, d, and e are already ON
rule triggers for changing c to ON
a. nothing because by now a, b, d, and e are already ON
rule triggers for changing d to ON
a. nothing because a, b, c, and e are already ON
rule triggers for changing e to ON
a. nothing because a, c, d, and d are already ON
You can’t avoid the rule triggers but that simple loop means that after the first trigger, none of the other triggers have anything to do and they just exit. Obviously, if there are some switches that are already ON, those will be skipped right out of the gate and the rule will trigger fewer times.