Design Pattern: Expire Binding Based Timers

What version of OH and how did you install?

openHAB 2.5.0 Build #1715 using a docker on a Synology

I tried it again:

  • uninstall expire
  • shotdown openha
  • clear cache
  • start openhab
  • install expire

Now I get following error within the logs:

2019-10-16 19:45:26.815 [INFO ] [b.core.service.AbstractActiveService] - Expire Refresh Service has been started
2019-10-16 19:45:26.822 [ERROR] [core.karaf.internal.FeatureInstaller] - Failed installing 'openhab-binding-expire1': Error restarting bundles:
	Exception in org.eclipse.smarthome.io.rest.sse.internal.SseActivator.start() of bundle org.openhab.core.io.rest.sse.

@NoTechi If you are not testing for errors and reporting them on GitHub, why are you running an unstable snapshot? Things are expected to be broken there.
Testing & Stable builds are designed for the average user.

@Bruce You are right actually I went through stable, testing to snapshot (since it is pretty easy to do with a docker) to get a functionality in a different binding which is only in the snapshot for now. But yes I should consider going back to testing and be patient or live with the expire binding not working in the snapshot for now.
Sorry for looking for a solution to a problem in an unstable build and just ignore my question :slight_smile:
NoTechi

Don’t forget expire is a 1.x binding, and you need “enable legacy bindings”

I have legacy enabled yes but thanks for the hint.
NoTechi

I think this should iterate the members:

gResetExpire.members.forEach[ timer | timer.sendCommand(timer.state) ]

I also frequently get IDE errors on things like timer.sendCommand(timer.state).
I usually have to use timer.sendCommand(timer.state.toString)

Thanks for catching the bug. The IDE sometimes is sometimes more strict than it needs to be. I don’t use Rules DSL any more so haven’t see the error you refer to myself, but indeed, using toString would sort it out.

Hi,
This looks like the perfect solution for me.
I tried the DSL sample but the timer is never expiring. What is wrong in the code below?
I hope someone can help me with this.

// item created Switch MyTimer { expire=“20s,command=OFF” }

rule “System started”
when
System started
then
MyTimer.sendCommand(OFF)
end

rule “BadkamerMovement”
when
Item Beweging_gEVBadkamer changed from OFF to ON
// state will change from OFF to ON every 10 sec if no movement is detected for 10 sec and then detects movement.
then {
logInfo(“default.rules”, “Movement detected”)
if(MyTimer.state !== ON ) {
logInfo(“default.rules”, “Badkamer timer not started so start it”)
MyTimer.sendCommand(ON)
} else {
logInfo(“default.rules”, “Badkamer timer already started”)
// Here I want to reset the timer. Is the this the way to do. Can’t test if becase I first need to detect MyTimer is expired.
// MyTimer.postUpdate(OFF)
// MyTimer.sendCommand(ON)
}
}
end

// The rule below is never started.
rule “BadkamerTimerExpired”
when
Item MyTimer received command OFF
then {
logInfo(“default.rules”, “Badkamer timer 10m received off”)
// Do I need to do something if MyTimer is expired.
}
end

Does the trigger event occur? Look in your events.log

The first post says

It requires installation of the Expire binding.

and you’ve not mentioned doing that.

Thanks. I added the Expire binding and it works perfect.

Hi all,

I’ve been using the expire binding and similar dummy items to the design pattern above as a timer for a while. I thought it was a hack to avoid timers and sleep rather than an actual way to do it so pretty pleased with it all.

I’ve one question on the expire binding now as I’m implementing a new rule for a light switch. I’ve a motion sensor that turns ON when it senses motion, which in turns turns on the light item itself and also a dummy item with a 30 second expire to then turn the light off again after 30 seconds.

My issue is that I want the expire time to reset if the motion sensor detects more movement, ie the person is still milling about in the area.

I know from the docs that if you update the state of the item to be the same state it already was then it resets the timer, (which is what I want), but in this case is there a difference between sendcommand(ON) and postupdate(ON)? Will one rest the timer and the other do nothing???

Either one will reset the timer. From the Expire binding’s perspective, assuming you have not configured the Item with autoupdate=false, it’s the same as the command will result in an update. If you have autoupdate=false, that will prevent the command from automatically updating the Item so the Expire binding would not see the update. What I don’t know is whether Expire would still see the command or not.

2 Likes

Thanks for document many design patterns it makes life much easier. I’ve a question: If upon system restart you send each timer a command. Would that mean if all timer Items were initially OFF, now you will got all alert triggered by doing a system restart? Assuming command OFF to those timers usually are defined as some notification.

I’m not sure of the question really, but it is probably answered by understanding expire’s simple rule.
From the docs -

The expiration time will be started or restarted every time an item receives an update or command other than the specified “expire” update/command.

So yes, the existing state of an Item affects what expire will do.

To elaborate on rossko57’s answer, the “resting” state of an Expire Timer, as written in the original post, is OFF. When you update or command the Timer Item to OFF it cancels the Timer. That Rule triggers at startup to restart those timers that were not OFF when OH went down. Restore on startup does not trigger the Expire binding to start a Timer even if it restored an Item to ON. This rule ensures that those Timers that were running before OH went down are restarted when it comes back up.

I still don’t think I understand it completely.

Say I’ve this Item and rule:

Switch S_GarageDoor_Open_Timer "Garage door open timer" (gDoorsTimers) {expire="30m, command=OFF"}

rule "Set Door timer when opened"
when
    Member of gDoorSensors changed
then
   ...
    // Set the timer if the door is open, cancel if it is closed
    if(state == OPEN) sendCommand(name+"_Timer", "ON")
    else postUpdate(name+"_Timer", "OFF")
    ...
end

rule "Timer expired for a door"
when
    Member of gDoorsTimers received command OFF
then
    ......
    // send notification
    Alert_Text.sendCommand(doorName + " has been left open for 30 minutes.")
   Echo_Family_PlayAlarmSound_Alert.sendCommand(ON)
end

Basically, An alert will be sent whenever Timer item received command ‘OFF’, versus receiving state ‘OFF’ will cancel the timer. If everything is fine and my door is OFF when system restarted. Your pattern will send ‘OFF’ command to the timer again. Would that generate another alert?

Yes, as you have it written it would trigger your rule. So in that case you would want to filter the group and only send the commands to those Timer Items that are ON. As with all the DPs, the intent is to customize it to work with your specific environment.

Thanks for the response. That makes total sense, and sendCommand(ON) to timers which was ON fits me.