Timer problems with end end renew

I have a problem with timers in openHAB 3.2. base is Ubuntu Server 20.04 LTS with Zulu Java. Various rules with timers can not be extended or stop not clean running timers.

For example, I have a rule for the basement that should turn off the lights in the stairwell after 3 minutes. If I do nothing, then the light also goes off after exactly these three minutes. However, if I manually switch off the light within the three minutes, and then switch it on again in the remaining timer time, the timer is not executed with the full runtime, but goes off after the remaining runtime. In the worst case, if you walk back and forth a lot, you turn on the light and it goes off again within a few seconds.

This problem also leads in other areas, where I actually work with a motion detector, to the fact that the light is not extended when motion detection stops and you are suddenly in the dark.

Attached is a rule for one of the basement lights. I hope that the German item descriptions are not a problem for understanding.

var Timer s_kg_flur_timer = null

rule "Wandleuchte Kellerdiele"
when
    Item s_kg_diele_wandleuchte changed
then
    if (s_automatisierung_innenbeleuchtung.state == ON) {
        if (s_kg_diele_wandleuchte.state == ON) {
            s_kg_diele_timer = createTimer(now.plusSeconds(180), [ |
                s_kg_diele_wandleuchte.sendCommand(OFF)
                s_kg_diele_timer = null
            ])
        } else {
            if (s_kg_diele_timer.isRunning) {
                s_kg_diele_timer.cancel
                s_kg_diele_timer = null
            }
        }
    }
end

I had before also a little other version:

rule "Wandleuchte Kellerdiele"
when
    Item s_kg_diele_wandleuchte changed
then
    if (s_automatisierung_innenbeleuchtung.state == ON) {
        if (s_kg_diele_wandleuchte.state == ON) {
            s_kg_diele_timer = createTimer(now.plusSeconds(180), [ |
                s_kg_diele_wandleuchte.sendCommand(OFF)
                s_kg_diele_timer = null
            ])
        } else if (s_kg_diele_timer !== null) {
            if (s_kg_diele_timer.isRunning) {
                s_kg_diele_timer.cancel
                s_kg_diele_timer = null
            }
        }
    }
end

That’s not the same variable.

That is probably not doing what you thought.

isRunning NOT meaning “is waiting for appointed time”, it means instead “the time has expired and am now running the code”

The variable name was my mistake when I copy the example of the rules files, while different rules where in the file. So I had this defined:

var Timer s_ga_haustuer_timer = null
var Timer s_kg_diele_timer = null
var Timer s_kg_flur_timer = null

Edit: I changed the rule with .hasTerminated and my first tests are positiv. I have in different combinations the full three minutes before the light get off.

rule "Wandleuchte Kellerdiele"
when
    Item s_kg_diele_wandleuchte changed
then
    if (s_automatisierung_innenbeleuchtung.state == ON) {
        if (s_kg_diele_wandleuchte.state == ON) {
            s_kg_diele_timer = createTimer(now.plusSeconds(180), [ |
                s_kg_diele_wandleuchte.sendCommand(OFF)
                s_kg_diele_timer = null
            ])
        } else if (s_kg_diele_timer !== null) {
            if (s_kg_diele_timer.hasTerminated == false) {
                s_kg_diele_timer.cancel
                s_kg_diele_timer = null
            }
        }
    }
end

You can simplify this.

Your timer execution code sets its own handle to null. You don’t need to check hasTerminated at all, just check the handle for null.

A useful syntax shortcut is the use of ? to avoid method use throwing an error if the object is null.
To explain,

myTimer?.cancel

has the same effect as

if (myTimer !== null) {
   myTimer.cancel
}

so you can replace that whole else-if section with

} else {
          s_kg_diele_timer?.cancel
          s_kg_diele_timer = null
}

That works whether the timer has never been created, is waiting, or is already executing, same end result.

1 Like

Thank you rossko, for this hint. I have adjusted my rules accordingly. However, without your contribution, I don’t know if I can follow it in terms of content then. The short notation is quite abstract. And it has the small disadvantage in connection with the Visual Studio Code extension that the variable is no longer recognized as a variable.

Jruby has a specific feature that makes this easier.

rule 'Wandleuchte Kellerdiele' do
  changed s_kg_diele_wandleuchte, to: ON, for: 180.seconds
  only_if s_automatisierung_innenbeleuchtung
  run { s_kg_diele_wandleuchte.off }
end

Specifically, the for parameter will cause the rule to run only when the item has changed to the given state (in this case, ON) for the given duration (180 seconds).

If the item turned off (changed state different to the parameter), the rule will not run and any internal timer is cancelled and cleared. When it changed again to ON, it will start a new timer from that moment.

I believe it does exactly what you want without having to write the boilerplate code. This scenario is quite common that the feature is built in to the scripting library.

1 Like