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.
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!
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.
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?
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:
This will avoid infinite loops since nothing will be done when the two Items are already the same state. An example flow would be:
Luz_Cozinha_Ilha changes state from OFF to ON
The rule triggers
The two Items are a different state so the rule doesn’t immediately exit
Luz_Cozinha_Ilha is the Item that triggered the rule so we “calculate” that Luz_Bancada_Cozinha is the Item that needs the command
An ON command is sent to Luz_Bancada_Cozinha
Eventually, Luz_Bancada_Cozinha changes
The rule triggers
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.