[SOLVED] Rule to turn on a second light when I turn the first one, sometimes starts an infinite loop

I am using a RPi4 8Gb with OH3 in an SSD. The system is now very stable with a lot of rules and many different equipments connected. But from time to time there are some things that does not work as intended. :slight_smile:

So I have these two very basic rules to trigger a second light in my kitchen whenever I turn ON or OFF one of those two lights.

rule "Alterar luz da bancada com base na luz da ilha"
when
   Item Luz_Cozinha_Ilha changed
then
   switch (Luz_Cozinha_Ilha.state) {
      case ON: {
         Luz_Bancada_Cozinha.sendCommand(ON)
      }
      case OFF: {
         Luz_Bancada_Cozinha.sendCommand(OFF)
      }
   }
end

rule "Alterar luz da ilha com base na luz da bancada"
when
   Item Luz_Bancada_Cozinha changed
then
   switch (Luz_Bancada_Cozinha.state) {
      case ON: {
         Luz_Cozinha_Ilha.sendCommand(ON)
      }
      case OFF: {
         Luz_Cozinha_Ilha.sendCommand(OFF)
      }
   }
end

Problem is, sometimes this get into an infinite loop and lights start VERY quickly to change ON and OFF both - which was somewhat scary the first time! :smiley:

Any suggestions on how should I solve this to avoid a loop?

It happens because it takes real time for an Item state to respond to a command.
For simplicity, I’d just add a 100mS sleep at the beginning of each rule, to allow things to settle down.

You could also reduce churn by not sending new commands unless the target Item is not already in the desired state.

Thank you for your help!

This approach seems very interesting and more reliable than adding a “waiting time”. I’ve searched for “openhab reduce churn” but I found nothing about it. So how could I use it?

Sorry, language - “churn” just means “doing stuff it does not need to do”

if (Luz_Cozinha_Ilha.state !=ON) {
   Luz_Cozinha_Ilha.sendCommand(ON)
}

especially important for devices like zwave where you really do not want to be using up your bandwidth sending unnecessary commands.

I think you will need that short delay in the rules, anyway.

This is one of the cases where Design Pattern: How to Structure a Rule can help make rules like this a little easier to write and understand.

I would also combine this into one rule which I think will eliminate the need for any sort of delay because only one copy of the rule can run at a time.

when
   Item Luz_Cozinha_Ilha changed or
   Item Luz_Bancada_Cozinha changed
then
    // 1. determine if there is something to do
    // If the two Items are already the same state there's nothing to do
    if(Luz_Cozinha_Ilha.state == Luz_Bancada_Cozinha.state) return;

    // 2. Calculate what to do
    // Figure out what Item triggered the rule so we can command the other one
    // We'll use newState as the command to cmdItem
    val cmdItem = it(triggeringItemName == 'Luz_Cozinha_Ilha') 'Luz_Bancada_Cozinha' else 'Luz_Cozinha_Ilha'

    // 3. Do it
    sendCommand(cmdItem, newState)

end

If the ternary operator is too weird an equivalent using if is:

var cmdItem = 'Luz_Cozinha_Ilha'
if(triggeringItemName == cmdItem) {
    cmdItem = 'Luz_Bancada_Cozinha'
}

This will avoid infinite loops since nothing will be done when the two Items are already the same state. An example flow would be:

  1. Luz_Cozinha_Ilha changes state from OFF to ON
  2. The rule triggers
  3. The two Items are a different state so the rule doesn’t immediately exit
  4. Luz_Cozinha_Ilha is the Item that triggered the rule so we “calculate” that Luz_Bancada_Cozinha is the Item that needs the command
  5. An ON command is sent to Luz_Bancada_Cozinha
  6. Eventually, Luz_Bancada_Cozinha changes
  7. The rule triggers
  8. The two Items are the same state now so the rule immediately exists.

I’ve on my to dos to create a rule template to handle simple synch cases like this where the Follow Profile is no sufficient but time is in short supply these days.

2 Likes

Ok, now a feel a little bit dumb! Ahaha.

Very interesting indeed! I will surely read this very carefully.

So smart! Congrats, this is very clean. I love clean codding. :slight_smile:

Yes, this is clever and a really good idea to help others with these type of doubts.

EDIT: @rlkoshak please check that in your example you have “it” on the second “if”. :slight_smile:

EDIT 2: Just a minor correction that I had to do to your code in order for it to work:

sendCommand(cmdItem.toString, newState.toString)

Hope this helps future visitors and thank you once again. :slight_smile:

PS: I’m now improving all my other rules with DP in mind.

1 Like