Please test the new Expire Binding

It is a 1.x version binding. It can only be used with .items files.

Hi @rlkoshak, sorry for dredging up an old post but your suggestion is not working for me:

.items file:

 String myStringItem {expire="5s"}

.rules file:

...
if (myStringItem.state == NULL) {
	\\ match
} else {
	\\ no match
}
...

If I command the item myStringItem to some value and then wait 5s, the code always follows the else path.
If I display the state of myStringItem in the sitemap it shows ā€˜UNDEFā€™.

I am running OH 2.2 release version.
The only difference I see is that you were describing testing a Number item and I am testing a String item.

Has something changed?
What should I be using to test for UNDEF on String item?
Thanks

Either test for UNDEF or add {expire=ā€œ5s,state=NULLā€}

With {expire=ā€œ5s,state=NULLā€}
Then if (myStringItem.state == NULL) still does not evaluate to true
but if (myStringItem.state == "NULL") (note the quotes marking ā€˜NULLā€™ as string - does evaluate to true

Since my item is a StringItem and there is no way to tell the expire binding to use the NULL keyword rather than the ā€œNULLā€ string.

However, using {expire=ā€œ5sā€}
and if (myStringItem.state == UNDEF) does evaluate to true.

I will use this method, I just thought it was interesting that :
A) There is no way (that I can see) to set a string item to NULL using the expire binding
B) The syntax for checking for UNDEF is now different from @rlkoshak 's code posted in Aug '17

I have items declared with expire=ā€œ15m,NULLā€ and in the rule I check if itemname.state == NULL and that works well. Must be something else wrong. Canā€™t see what it could be thoughā€¦ But if you tell Expire to set it to NULL and then check the log, can you see what itā€™s actually set to?

1 Like

Doesnā€™t work for me:

String Item: String myStringItem {expire="5s,NULL"}

I send a command ā€œhello worldā€ to this item to trigger the expire countdown. Then 5s later in events.log:
myStringItem changed from hello world to NULL

The using this code:

if (expString.state == NULL) {
	resultString.postUpdate("yup")
} else {
	resultString.postUpdate("nope")
}

resultString is set to ā€œnopeā€.

If I change the code to:

if (expString.state == "NULL") {
	resultString.postUpdate("yup")
} else {
	resultString.postUpdate("nope")
}

then resultString is set to ā€œyupā€.

According to what I am seeing the expire binding is setting the value of the String item to the String representation of NULL. If you are seeing something different with the exact same test then I donā€™t understand what I could be doing wrong.

Correct. The reason is that the StringType is the first listed accepted data type here and this code is used to parse the expire state. The best solution is to not specify any expire state in the binding config string (leave off the ,NULL) which defaults to UNDEF and just check for UNDEF in your rule (see code here for how default is set as described in the docs here).

1 Like

But how come it works for me when comparing with just NULL? Is this something that has changed recently (Iā€™m on 2.2 stable)?

I donā€™t see where in your earlier messages a comparison with NULL (as opposed to "NULL") worked for String items. The Expire binding cannot use UnDefType.NULL as an expire state for String items because of what I explained/linked to earlier. Any item type can use UnDefType.UNDEF as an expire state by not specifying an expire state.

1 Like

Oh, my fault. No, the Item Iā€™m using is a switch. Sorry for confusing the discussion :blush:

Is it possible to use the expire binding to monitor a group that holds all of the lights for a room and have them all turned off when it expires?

I would like to have a group that contains 2 bathroom lights (both dimmers) and an exhaust fan. I would like all of them to turn after 10 minutes of no other events.

Since they are a mix of switches and dimmers, I declared the group as a switch using the OR aggregator.

I see this error from the binding: The string ā€˜OFFā€™ does not represent a valid command

AFAIK you cannot send ANY command to a group (which is what the Expire binding presumably does) but just to individual items.

Iā€™m pretty sure groups can receive commands, for example a light group should accept OFF command and remit this to all direct group members.

According to the docs and examples you canā€¦

https://docs.openhab.org/configuration/items.html

Right, ok.
Now that you mention your group is composed of items of different type, that might be your problem. I believe a dimmer will not accept OFF just as a switch does. Try with a homogenous group.

As an item of type dimmer accepts ON and OFF, an assorted group of dimmers and switches should also accept ON and OFF :slight_smile:

The plumbing of what Michael is trying to do should work.

You can indeed send a command to a Group and the command will be forwarded to all the members of the Group. If do this all the time. @mjcumming, I donā€™t know however whether that command will filter down to subGroups. Are you using nested Groups here?

And a Dimmer Item can receive ON/OFF commands (from Items | openHAB):

Dimmer Percentage value for dimmers OnOff, IncreaseDecrease, Percent

The third column defines those command types the Item can accept.

One thing that does pop out as a potential problem is we may not be able to have a binding config on a Group. The Group docs (Items | openHAB) does not include any { } clause. Since Expire is a binding Iā€™m thinking that what you would like to do is not possible. The error you report is surprising though. I would have expected to see syntax errors when the .items file was loaded.

This is an interesting use case.

I am trying to find an easy way to use expire to turn off lights in a room when nothing has happened in that room for a period of time. Have read a lot of your posts on DP and would really like to find a solution along those lines.

Another example I am working on is our Mudroom. In that room I have a closet light (switch) a dimmer (overhead lights), motion sensor, and a door contact. I would like to use any event from those 4 sources to say that the room is occupied. If there are no events from any of those sources for 10 minutes, then turn off all the lights in that room.

Certainly, could code rules to manage that but for all the rooms I would like to do that inā€¦ yuck! :slight_smile :slight_smile:

Below are a few screenshots from a Occupancy plugin I wrote for Girder about 10 years agoā€¦ it accomplished all of this by using Locations within the house, the devices/sensors in that location to set when the room was occupied, each room would have a preset decay rate, and when empty, the various devices could be set to turn off ā€¦.

image

image

image

Each room has a Group for the lights (e.g. Kitchen_Lights, Hall_Lights, etc). That Group gets put into a parent Group (RoomLights) so we can access it later. Each room has a Timer Item with Expire binding config (e.g. Kitchen_Timer, Hall_Timer, etc) and all the Timers go into a Group (RoomTimers). Each Sensor goes into another Group (RoomOccupancySensors).

All Items are named using Assocaited Items DP.

rule "Sensor detected occupancy in a room"
when
    Member of RoomOccupancySensors received update
then
    // schedule/reschedule the timer
    sendCommand(triggeringItem.name.split("_").get(0) + "_Timer" , "ON") 
end

rule "A room is no longer occupied"
when
    Member of RoomTimers received command OFF
then
    // turn off the lights
    sendCommand(triggeringItem.name.split("_").get(0) + "_Lights", "OFF")
end

Theory of operation: When any sensor updates, use Assocaited Items to send a command to the associated Timer. You may need to do more checking here to make sure the update indicates presence. When a Timer Item expires another Rule runs which sends the OFF command to that roomā€™s lights. You may need to loop through the Group and send a different command depending on the Item type. If you do you need to pull the Group out by name:

val lights = RoomLights.members.findFirst[ lts | lts.name == triggeringItem.name.split("_).get(0) + "_Lights" ]
lights.filter[ l | l instanceof SwitchItem ].forEach[ l | l.sendCommand(OFF) ]
lights.filter[ l | l instanceof NumberItem ].forEach[ l | l.sendCommand(0) ]
...

The magic happens by using the Associated Item DP naming scheme and Groups so you can use the name of triggeringItem of the Rule to access the Items you need to interact with.

1 Like