Please test the new Expire Binding

Michael Wyraz wrote a new Expire binding that works on 1.8 and 2.0 beta. It simplifies the process of returning an item’s state to a default value, such as marking a stale sensor reading as Undefined, or turning off a motion sensor indication after some time. You just add this to your .items file:

Number Temperature "Temperature [%.1f °C]" { zwave="12", expire="2m" }
Switch LightSwitch "Light" { myq="2", expire="45s,OFF" }
String Message "Message [%s]" { expire="1h,No activity for one hour!" }

The Temperature item will be reset to Undefined two minutes after its last update or command. The LightSwitch will turn OFF after 45 seconds.

The syntax is

expire="12h 45m12s,<state>"

where the expiration time can include hours, minutes and seconds. You can optionally specify any item state after a comma. where <state> can be any state accepted by the item.

This binding can reduce the number of rules you might be using that create timers to achieve a similar outcome.

Here a test release of the JAR file. It has no configuration file. You can turn on DEBUG or TRACE logging for org.openhab.binding.expire to see what it’s doing. Please report any problems or questions, thanks!

Thank you, Michael for your contribution!

15 Likes

What a great idea. I think we need more of these logic-style bindings - I think they had real value to openHAB.

There was talk of an alert/alarm style binding at one point which lost traction, but I think that is another great idea. Something along the lines of;

Number  GF_Living_Temp  "Living Temp [%d]"    { alert="min:15,max:35,alert:VT_Temp_Alert" }
Number  GF_Kitchen_Temp "Kitchen Temp [%d]"   { alert="min:10,max:35,alert:VT_Temp_Alert" }
String  VT_Temp_Alert   "Alert [%s]"

Then if the temp crosses the min/max threshold you get an upgrade published to VT_Temp_Alert. I would love to see the published message contain a JSON payload with as much detail as possible, e.g. item name, value, threshold breached, etc.

Would then be very easy to build a human readable notification or forward the alert to another system if required.

Would be great to be able to assign this binding to a GROUP as well (not even sure if groups support bindings?). Then you could define a general temp alert for all temp sensors which would automatically be evaluated.

Just spitballing here, but this expire binding has reminded me of this. Great work!

2 Likes

I assume (but am often wrong when I do so) that it does the equivalent of a postUpdate when resetting the state and not a command, right?

I have a bunch of watchdog rules I think I’ll be able to eliminate or at least simplify with this. Looking forward to trying it out.

One unintended use I can see for this is as a way to manually initialize the state of an Item being used to store state. Now I need to use a System started rule and persistence to populate such Items. But that only works if the binding starts running at the time the Item loads and doesn’t require the Item to receive an update or command before it will reset it.

I’m liking this binding more and more every minute! :slight_smile:

I had the understang that

would be equivalent of


rule "test"
when 
      Item LightSwitch received update
then
     createTimer(now.plusSeconds(45)) [|sendCommand(LightSwitch ,OFF)]
end

But maybe I am wrong

Correct. When an item is bound to expire="..." receives a command or update that is not the “expire state,” it sets up the item to be updated in the future to the “expire state.” The “expire state” is Undefined (UnDefType.UNDEF) unless you specify any other state (like 12.5, OFF, a string, etc.). So, for example, the item

Number TargetTemp "Target Temp [%.1f °F]" { expire="15m,66" }

Can be updated to any temperature besides 66 any number of times, but 15 minutes after the last time the item received a command or update to anything other than 66, it will automatically return to the state 66.

Michael initially wrote the binding to cause stale sensor values to become Undefined after some period, but I think the binding can be useful for other situations as well. Please suggest ways in which it can most generically fill the need of “expiring” any item after a period of non-use.

Very nearly the same, except the rule version above keeps creating timers every time the item is updated, while the expire binding will instead keep moving the one expiration further into the future every time an update or command occurs. But if the last update or command received is OFF, then the future expiration is cancelled because the item is already in the “expire state.” And currently, the future expiration is only a postUpdate.

I think it might make sense to change the binding so if the binding reacted to a command to set up the expiration, then the act of expiring would be to send a command and not an update. What do you all think?

Yes, I think that may be a better approach. One other thing that would be useful in helping to reduce timer rules is if the binding could also extend the timeout, i.e. it restarted its internal timer each time the item received a command ON (or other non-expiring event) - I’m thinking of use in a motion sensor environment.

Thanks; I think this change might be a good one. Other feedback on expiring by sending commands?

It does! The item has to be “quiet” for the duration specified, and after the entire time has passed with the item not having received the “expire state” as a state or command, it updates to the expire state.

That’s great (I haven’t actually tried the binding out but looking forward to doing so over the weekend!).

@watou One other piece of functionality that would be very useful is if the expire item binding statement could take the timeout value/parameters from the state of another item - that way we could allow users to change the expiry values during runtime, without having to edit the original expiry item binding configuration.

1 Like

I’m thinking the following syntax might be more flexible:

// Expire to pool temperature sensor state to Undefined after one hour
Number PoolTemp "Pool Temp [%.1f °C]" { expire="1h" }     //  currently supported

// Return thermostat setpoint to 65 after 20 minutes via update
Number SetPoint "Setpoint [%.1f °F]"  { expire="20m,65" } // currently supported

// Turn off whole house fan via OFF command after 30 min being ON
Switch HouseFan "House Fan"           { expire="30m,command=OFF" }

// update state to OFF 2 min after last motion update
Contact Motion  "Motion [%s]"         { expire="2m,state=CLOSED" }

//  same as above (state= is optional)
Contact Motion2 "Motion2 [%s]"        { expire="2m,CLOSED" }  // currently supported

// if my drone hasn't reported its location for ten minutes, command it to fly to the Taj Mahal
Location Drone "Location [%s]"        { expire="10m,command=27.1750151,78.0399665" }

Thoughts?

4 Likes

Looks good. Yet another extension here could be to initiate a state change in a DIFFERENT item, such that we can then trigger a rule of the state change. E.g. maybe something like:

Switch  GarageDoorAlert   "Garage door open alert"     
Contact GarageDoorStatus  "Garage door open/closed status [%s]" { expire ="90m, command=GarageDoorAlert.state=ON" }
1 Like

I’m wary of doing that in a binding, because bindings really ought not have to rely on the ItemRegistry or otherwise address items that they’re not bound to. But if your “expire state” or “expire command” is a value that is unlikely to come from the normal source of updates and commands, it would be easy enough to write a rule like:

rule TempExpired
when
  Item Temperature changed to Undefined
then
  // reboot the source of the sensor reading,
  // send an email or notification to you,
  // send a new request to the source to post a new update,
  // whatever
end

Yes, the thought had crossed my mind as well after posting my earlier message; plus we start having to track how individual items are linked in item files - can get very messy quickly. But the rule example you gave does give a good work around, so pls ignore this suggestion!

1 Like

I updated the test JAR to add support for command= and state= to either post a command or post an update when the item expires. Valid syntax examples:

expire="1m"             // update state to Undefined after one minute
expire="12h30m05s"      // update state to Undefined after 12 hours, 30 min, 5 sec
expire="30h 5s"         // update state to Undefined after 30 hours, 5 sec
expire="45s,CLOSED"     // update state to CLOSED after 45 sec
expire="1h,command=OFF" // post an OFF command after one hour
expire="30m,state=999"  // update state to 999 after 30 min
1 Like

This looks great! I’ll look forward to trying it. I agree that being able to choose state or command is valuable. I could see wanting to do both in different situations.

I have updated the test JAR hopefully one last time. Please report any problems or unexpected behavior and thanks!

Thank you both for your efforts!
I am looking forward to use this binding!

1 Like

This is really good stuff. Do you know if this is going to be in the repo? I have my “prod” failover nodes using just the stuff in the repo for simplicity sake.

@watou I was just looking at some trace logs for the binding and see that something seems to be executing every second:

08:45:08.466 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:09.466 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:10.467 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:11.468 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:12.468 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:13.468 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:14.469 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:15.469 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
08:45:16.469 [TRACE] [inding.expire.internal.ExpireBinding] - Executing... 

Is this intentional? At the moment, all I have is a single 5m expire on one item which should be currently active. If it is some sort of polling, is it not adding unnecessary resource usage?

EDIT: I notice that this continues even after the 5m expiry (at which time the item is correctly switched off):

2016-12-03 08:49:11.415 [DEBUG] [inding.expire.internal.ExpireBinding] - Item Blanket_MasterBed received no command or update for 5m - posting command 'OFF'
2016-12-03 08:49:11.442 [TRACE] [inding.expire.internal.ExpireBinding] - Received command 'OFF' for item Blanket_MasterBed
2016-12-03 08:49:11.564 [DEBUG] [inding.expire.internal.ExpireBinding] - Item Blanket_MasterBed received command 'OFF'; stopping any future expiration.
2016-12-03 08:49:11.565 [TRACE] [inding.expire.internal.ExpireBinding] - Received update 'OFF' for item Blanket_MasterBed
2016-12-03 08:49:11.565 [DEBUG] [inding.expire.internal.ExpireBinding] - Item Blanket_MasterBed received update 'OFF'; stopping any future expiration.
2016-12-03 08:49:11.594 [TRACE] [inding.expire.internal.ExpireBinding] - Received update 'OFF' for item Blanket_MasterBed
2016-12-03 08:49:11.595 [DEBUG] [inding.expire.internal.ExpireBinding] - Item Blanket_MasterBed received update 'OFF'; stopping any future expiration.
2016-12-03 08:49:12.416 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
2016-12-03 08:49:13.419 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
2016-12-03 08:49:14.420 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...
2016-12-03 08:49:15.420 [TRACE] [inding.expire.internal.ExpireBinding] - Executing...

The binding does indeed check its map of item names+expire times every second, but I think the biggest burden it imposes is if TRACE logging is on. The amount of work to check the map is (I think) very minimal. The current implementation does create a new ArrayList of bound item names every second, but I will change that. I think it’s a better implementation than scheduling and cancelling jobs because the code is simpler, but I would be happy to hear contrary arguments.

Your TRACE log above looks correct except for the second OFF update it received. I will look into that.

Once it’s deemed fit, it will be added to the build.

1 Like