Lambda Function to get Elapsed Time

Greetings!

I have been learning OpenHAB2 for the last month, while converting my home automation from Vera 3 (Mios) control over to OpenHAB2.2. I am now just using the Vera 3 as the Zwave controller, but all automation is done by OpenHAB2. I didn’t even know OpenHAB existed until a month ago, and I’m hooked! I’m amazed by the community involvement, and would like to start giving back, so I’ll start with this.

I have a notification rule when my garage door is opened, and then a separate notification if it stays open for more than an hour (and every hour after that). I wanted to display the time it’s been open in the notification, and have some other things that would be nice to display an elapsed time for as well, so I made a lambda function that will return a string in the form 00:00:00 (hr:min:sec) or 1d 00:00:00 (days hr:min:sec) if the elapsed time is greater than a day.

Here is the Lambda function, which you would place at the top of any .rules file it is used in:

// Lambda Function to calculate elapsed time
val Functions$Function1<DateTimeType, String> getElapsed= [ startTime |
    // Get the elapsed time from a DateTimeType time to now
    // Call using:  val String elapsed = getElapsed.apply(StartTime_Item.state)
    var String eTime = "00:00:00"
    if (startTime !== NULL) {
        val eSecs = (now.millis - (startTime.zonedDateTime.toInstant.toEpochMilli as Number)) / 1000

        // Calculate d/h/m/s without using modulus
        val d = (eSecs / (60*60*24)).intValue                       // Div by 86400
        val h = ((eSecs - (d*60*60*24)) / (60*60)).intValue         // Div by 3600
        val m = ((eSecs - (d*60*60*24) - (h*60*60)) / 60).intValue  // Div by 60
        val s = (eSecs - (d*60*60*24) - (h*60*60) - (m*60))         // Remainder = secs

        // Format the string as "00:00:00" (< 1 day) or "1d 00:00:00" (>= 1 day)
        eTime = String::format("%1$02d:%2$02d:%3$02.0f",h,m,s)      // 02.1f or 02.1d (float or int)
        if (d >= 1) eTime = String::format("%1$dd %2$02d:%3$02d:%4$02.0f",d,h,m,s)  // Include days (d)
    }
    eTime                                                           // Return the string
]

You then call the lambda function from within a rule passing only the start time item (DateTime item) state:

val String elapsed = getElapsed.apply(StartTime_Item.state)

And then use the variable “elapsed” wherever you need the elapsed time! I could not get modulus (%) to work in the rule, so I did it the long way (thanks to pensionado’s code in this post: Does openhab2 not support % (remainder) operator?). If the DateTime state passed to the function is NULL, the function returns an elapsed time of 00:00:00 (zero) and doesn’t throw an error.

If you have any comments or suggestions, please chime in, I’m pretty new at this.
Cheers!

5 Likes

Continuing the discussion from Lambda Function to get Elapsed Time:

hi i have a error when i place in the rule the lambda function :slight_smile:

val String elapsed = getElapsed.apply(StartTime_Item.state)

i have this message :

Type mismatch: cannot convert from State to DateTimeType(org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types)

can you show the light for me thanks ? :slight_smile:

Sorry it took a while to get back to you on this, I’ve been out of the country.

Without seeing your whole rule (or at least the lambda function, and then the rule from which you call it) I can’t really guess what is going on. If you could post all of that inside code fences I would be glad to take a look.

Thanks!

thanks i try to do that , thanks

You also might need to describe what Type of Item your StartTime_Item is.