Unfortunately, this code won’t work. Let’s say that lamp_A changed, then the first if runs and we send lamp_B a command. So far so good. Now let’s say that lamp_B changed. lamp_A.state != lamp_B.state so the if runs and lamp_B gets the command. The else never exeutes and when lamp_B changes, lamp_A never gets that synchronization command.
I don’t have too much of a problem with having these in separate Rules. Especially for a new user having the two separate Rules is simple and easy to understand.
Michael’s solution looks correct, but @Maximo and @JDLambert, take heed of the comment “you have to decide whether postUpdate or sendCommand should be used.” This is important because sendCommand will go out to the device linked to/bound to the Item whereas a postUpdate will only change the Item’s state inside OH.
When synchronizing Items like this, most of the time postUpdate is the correct answer. In this case however I believe the intended behavior is to actually change a light so sendCommand is probably the right answer.
Another thing to watch out for is infinite loops at worse, or extra executions of your Rule at best. In this case, using Michael’s Rule, consider the following:
- both switches are OFF
- A changes to ON
- sync lights runs
- B gets command ON
- B changes
- sync light runs again
- A gets commanded to ON
- A is already ON so there is no change and the Rule doesn’t trigger again.
In this case the fact that the Rule triggers twice is benign. Nothing results from it. But in many cases the Rule may do something and you don’t want it to do it twice. Also, if one changed the Rule trigger from changed to received command or received update there would be an infinite loop because the Rule would trigger on the command whether or not the command resulted in a change in the Item.
And just to provide another alternative for combining the Rules, I would do it as follows:
rule "sync lights"
when
Item lamp_A changed or
Item lamp_B changed
then
val newState = triggeringItem.state
if(lamp_A.state != newState) lamp_A.sendCommand(newState)
if(lamp_B.state != newState) lamp_B.sendCommand(newState)
end
The advantage of this Rule, besides being simpler and shorter, is that if one were to change the Rule trigger to received command or received update then the Rule would not go into an infinite loop because we wouldn’t even issue the sendCommand if the states are already the same. It will still trigger twice though for each individual change to one of the switches.
If the lamps were in a Group the Rule could be further reduced down to
rule "sync lights"
when
Member of Lamps changed
then
val newState = triggeringItem.state
Lamps.members.forEach[ lamp | if(lamp.state != newState) lamp.sendCommand(newState) ]
end
Personally, I’d put the lamps in a Group and only put the Group on your UI (sitemap/habpanel). Any command sent to the Group gets forwarded to all its members so it would let you control both lamps with on switch without any rules at all.