Eliminating lingering timers

Not that I’ve experienced or read from others on this forum. For the most part, assuming:

  • you keep a handle on the timer in a global var
  • you do not change any .rules files while the Timer is running
  • you do not explicetly cancel the Timer

Timers are pretty reliable, even really long running ones (hours). I’ve help noone with rescheduleing issues either.

It is hard to say what is going on with your system. Check the logs, are you certain that nothing happened to cause the .rules files to be reloaded when the Timer went away?

I’ve made the recommendation before but understand your reasons for not wanting to use them. I like them but that doesn’t mean I judge those who don’t use them. I’d like to get your Timers working as is as well.

I assume timer_u is a gloval val initialized to null, correct?

Under what circumstances would this Timer ever be canceled? As written right now, the Timer never gets cancels and just keeps being rescheduled forever. Is this correct?

If so I suspect the problem is your Timer is being garbage collected. This might be worth reporting as a bug on the ESH repo, though I imagine Kai’s initial reaction will be “you should not be using timers like this.”

A better way to implement something that is to run every 19 minutes forever is to use a cron triggered rule instead. Something like:

rule "get Utetemperature changed"
when
    Item Utetemperatur changed or
    Time cron "0 */19 * * * ? *"
then
    sendHttpGetRequest("http://www.temperatur.nu/rapportera.php?hash=supersecret&t=" + Utetemperatur.state)
    logDebug("temprule", "Resending " + Utetemperatur.state + " to temperatur.nu and rescheduling timer")
end

The timing won’t be exactly the same (it will post every 19 minutes AND post the changes rather than posting every 19 minutes after the last temperature change) but I think the end result will work for this service.

If you must have exactly the same timing, instead of rescheduling the Timer forever, create a new one each time. This gets tricky because it is really hard to write code inside a timer to recreate itself without hitting an infinite regression. Luckily I wrote up a way to do it here.

Honestly, I can’t say I would recommend this recursive timers approach. It is IMHO really kludgy. But it should work.

Another perhaps less kludgy way to do it could be to use an Unbound Switch to retrigger the rule when the Timer expires. That would look something like:

rule "Utetemperatur changed"
when
    Item Utetemperatur changed or
    Item Utetemperature_Timer received command
then
    sendHttpGetRequest("http://www.temperatur.nu/rapportera.php?hash=supersecret&t=" + Utetemperatur.state)
    logDebug("temprule", "Sending " + Utetemperatur.state + " to temperatur.nu")

    timer_u.?cancel // I'm not sure I have the ? and the . in the right order
    timer_u = createTimer(now.plusMinutes(19), [|
        logDebug("temprule", "Resending " + Utetemperatur.state + " to temperatur.nu and rescheduling timer")
        Utetemperature_Timer.sendCommand(ON)
        timer_u = null
    ])
end

The .?cancel is a shortcut way of doing:

if(timer_u != null) timer_u.cancel

In the above, when either Utetemperature changes or Utetemperature_Timer receives a command the Rule triggers. In either case we send the temp and log it.

If the rule triggered because of a temp change then we cancel the existing timer and create a new one. If the rule triggered because of the Timer then the Timer is already null and we create a new one.

When the Timer goes off it logs and sends a command to the Timer Item which triggers the rule.