how to find out when an Item has last changed

823 views
Skip to first unread message

leutholl

unread,
May 6, 2015, 11:23:15 AM5/6/15
to ope...@googlegroups.com
Hi

In a "when Item ... changed from ... to ... then" rule, I would like to find out when a given item has been previously (before entering the rule) changed. After that I would like to calculate the delta to the time now (when the rule has fired) to see if the time delta is longer than a threshold (let's say 1 sec). Having this I could detect long or short key presses

I tried:

if (itemXYZ.lastUpdate().compareTo(now.plusSeconds(1).toDate)>0) but it logs "Error during the execution of rule 'rule_name': cannot invoke method public int java.util.Date.compareTo(java.util.Date) on null"


HOw can I further select the state I would like to get the time from? in my use case the time of state change I'd like to retrieve is for OPEN of OFF as my itemXYZ is a Switch or Contact item bound to tinkerforge io16 or lcd_button respectively.


Thanks.

Richard Koshak

unread,
May 7, 2015, 10:30:49 AM5/7/15
to ope...@googlegroups.com
Is your persistence set up correctly and working? I had the same problem and discovered it was because my rrd4j settings were all messed up so any calls to get past data on an item (lastUpdate, changedSince, etc) threw a null exception like you are seeing.

Check your log for errors and warnings pertaining to persistence.
Make sure you have a persist file in the persistence folder that matches the persistence:default=XXX property in openhan.cfg (e.g. if XXX is rrd4j make sure you have an rrd4j.persist file in the configuration/persistence folder) and you have the corresponding persistence jar file in your addons folder (in my case org.openhab.persistence.rrd4j-1.6.2.jar).
Finally, make sure the strategy for itemXYZ includes "everyChange" and "restoreOnStartup".

Another problem I had was the rules were being loaded before the persist files. This mainly showed up when I split my rules and items into multiple files. I had to update the polling times (top of the openhab.cfg) to make sure the persistence, items, and scripts loaded before the rules.

Once I fixed those two things everything started working great.

Also, you can simplify your if statement by using updatedSince or changedSince:


    if (!itemXYZ.changedSince(now.minusSeconds(1)) // True if itemXYZ has changes state more than a second ago
    if (!itemXYZ.updatedSince(now.minusSeconds(1)) // True if itemXYZ received and update, whether or not the state changed, more than a second ago

I've successfully done this in a rule that I only want to trigger when an item changed five minutes ago or longer.


Rich

Lukas Leuthold

unread,
May 7, 2015, 10:59:57 AM5/7/15
to ope...@googlegroups.com
That's a great tutorial! Thanks. 

Actually my intension is to look back in time for a specific (=named) state - not the last update or state change. Need something like "changedSince(now.minusSeconds(1), OFF)" giving back the boolean if a change has occured to OFF (be it from any state incl. Undefined) in the given time window. 

Is this possible in a easy way?

Thanks again!


--
You received this message because you are subscribed to a topic in the Google Groups "openhab" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/openhab/R9FQkBnS8xo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to openhab+u...@googlegroups.com.
To post to this group, send email to ope...@googlegroups.com.
Visit this group at http://groups.google.com/group/openhab.
To view this discussion on the web visit https://groups.google.com/d/msgid/openhab/4e8ba025-3333-45aa-bfca-827df4550621%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Richard Koshak

unread,
May 7, 2015, 1:14:12 PM5/7/15
to ope...@googlegroups.com
If I assume that you only care about the most recent change in the time period this can be done easily:

if(itemXYZ.changedSince(now.minusSeconds(1) && itemXYZ.previousState(true).state == OFF) ...

An equivalent if statement that only hits the database once (a good thing if performance is an issue for you i.e. you do this check a whole lot):

val lastState = itemXYZ.previousState(true)
if(lastState.state == OFF && lastState.timestamp > now.minusSeconds(1)) ...

However, if you want to know whether the item was in the OFF state (in these examples) at any time during that time period no matter how many changes occurred (which is what it seems you are asking for) you will need to iterate over the historicState. The following loop starts at the timestamp of the last change and goes back to one second in 1 millisecond increments. You can change the i-- to i-10 or i-100 to go in ten millisecond or 100 millisecond increments to get better performance with less resolution. Personally I'd use 100 or even 250 which should catch all the changes that I'd expect to occur in a seond.

if(itemXYZ.changedSince(now.minusSeconds(1)) {
    var changed = false
    for(var i=itemXYZ.lastUpdate; i> now.minusSeconds(1); i--) {
        if(!changed && itemXYZ.historicState(i) == OFF) changed = true
    }
    if(changed) ...
}

There might be ways you can get at what you are looking for as the previousState method will take a String which allows you to pass additional parameters to your database where all this info is stored. However, my only experience is with rrd4j and I don't think it accepts any additional parameters in this way (I'd love to hear I'm wrong though).

Rich
Reply all
Reply to author
Forward
0 new messages