OH3 script for time since last update

Hey all,
I’m trying to create a rule to get the time that has past since the last update of an item. I managed to get it working somehow, but I want to define it as a general rule and to apply it to all items in a group.
This is the script:

from core.rules import rule
from core.triggers import when
from core.actions import LogAction
from core.actions import PersistenceExtensions
from java.time import ZonedDateTime

from core.date import seconds_between


@rule("Time since last update", description="Time from the last persistence record until now", tags=["system"])
@when("Time cron 0/20 * * * * ?")

def timeSincelastUpdates(event):
    itemName = "ESP101LivingroomEnvironment_Temperature" #here it should be all the items in a group

    timeNow = ZonedDateTime.now()
    lastRecord = DateTimeType(PersistenceExtensions.lastUpdate(ir.getItem(itemName))) #time from the last update
    betweenS = seconds_between(lastRecord, timeNow)

    LogAction.logWarn("TSLU", "Item name is {}", itemName)
    LogAction.logWarn("TSLU", "Current time is: {}", timeNow)
    LogAction.logWarn("TSLU", "Last record was at: {}", lastRecord)
    LogAction.logWarn("TSLU", "Last record was: {}", betweenS)

And this is the log:

[WARN ] [org.openhab.core.model.script.TSLU   ] - Item name is ESP101LivingroomEnvironment_Temperature
[WARN ] [org.openhab.core.model.script.TSLU   ] - Current time is: 2021-06-14T17:45:00.673972+03:00[Europe/Bucharest]
[WARN ] [org.openhab.core.model.script.TSLU   ] - Last record was at: 2021-06-14T17:44:12.959+0300
[WARN ] [org.openhab.core.model.script.TSLU   ] - Last record was: 47

What I want is to check every 10 or 20 minutes all the items in a group and to send an alert. At the moment the trigger is set at 20 seconds but this is just for testing.
I don’t know how to iterate thru all the items in a group. As you can see the rule checks only the ESP101LivingroomEnvironment_Temperature item at the moment.

Can someone point me in the right direction?
I’m using the helper libraries maintained by CrazyIvan359

Thank you!

There are a number of Python examples for working with Groups at Design Pattern: Working with Groups in Rules

One thing to note is if you are using rrd4j for persistence, this will only ever return a time of one minute ago or less because rrd4j requires a value be saved to the database every minute and there is no way to distinguish between an update to the Item or a record saved on the minute because that’s what rrd4j requires.

Thank you Rich. I’m using influx as persistence.
I did some small modifications and this is the new rule:

from core.rules import rule
from core.triggers import when
from core.actions import LogAction
from core.actions import PersistenceExtensions
from java.time import ZonedDateTime

from core.date import seconds_between


@rule("Time since last update", description="Time from the last persistence record until now", tags=["system"])
@when("Time cron 0/20 * * * * ?")

def timeSincelastUpdates(event):
    for i in ir.getItem("gCheck20Minutes").members:
        itemName = format(i.name)

        timeNow = ZonedDateTime.now()
        lastRecord = DateTimeType(PersistenceExtensions.lastUpdate(ir.getItem(itemName)))
        betweenS = seconds_between(lastRecord, timeNow)

        LogAction.logWarn("TSLU", "Item name is {}", itemName)
        LogAction.logWarn("TSLU", "Current time is: {}", timeNow)
        LogAction.logWarn("TSLU", "Last record was at: {}", lastRecord)
        LogAction.logWarn("TSLU", "Last record was: {}", betweenS)

        if betweenS > 5:
            LogAction.logWarn("TSLU", "Send alert {}", itemName)

And the logs:

[WARN ] [org.openhab.core.model.script.TSLU   ] - Item name is ESP101LivingroomEnvironment_Temperature
[WARN ] [org.openhab.core.model.script.TSLU   ] - Current time is: 2021-06-14T21:23:20.500544+03:00[Europe/Bucharest]
[WARN ] [org.openhab.core.model.script.TSLU   ] - Last record was at: 2021-06-14T21:22:13.022+0300
[WARN ] [org.openhab.core.model.script.TSLU   ] - Last record was: 67
[WARN ] [org.openhab.core.model.script.TSLU   ] - Send alert ESP101LivingroomEnvironment_Temperature
[WARN ] [org.openhab.core.model.script.TSLU   ] - Item name is ESP121Bedroom1Environment_Temperature
[WARN ] [org.openhab.core.model.script.TSLU   ] - Current time is: 2021-06-14T21:23:20.503359+03:00[Europe/Bucharest]
[WARN ] [org.openhab.core.model.script.TSLU   ] - Last record was at: 2021-06-14T21:22:53.741+0300
[WARN ] [org.openhab.core.model.script.TSLU   ] - Last record was: 26
[WARN ] [org.openhab.core.model.script.TSLU   ] - Send alert ESP121Bedroom1Environment_Temperature

Now I just need to configure an alert and do some more testing by trial and error.

I added the alert part but here I have a big problem.

actions.get("telegram", "telegram:telegramBot:alert").sendTelegram(1755292235, "Alert, Item " + itemName + " was last updated " + str(betweenS) + "minutes ago")

I get a notification every 20 seconds :frowning_face:

Well, as written the rule runs every 20 seconds. It loops through all the members of the Group and for any one that has five or more seconds since the last update an alert is generated. Unless an Item updates it will be alerted again the next time the rule runs. There is no book keeping in the rule to check whether or not you’ve already sent an alert for that Item.

I know the rule is working exactly as it should, but is not what I want.
I think I will try something else. When the rule is true I will change the item to UNDEF and then I will check if there are items with the state UNDEF and send alerts for those.
I remember you have a post somewhere with something similar regarding UNDEF and NULL.

Alternative approaches:

That won’t help. Have considered having another rule triggered when Item changes to UNDEF? (for a one-time message). You can trigger off Group members changing, to make one rule serve many Items.

Thank you @rlkoshak and @rossko57!
I think I did it:

from core.rules import rule
from core.triggers import when
from core.actions import LogAction
from core.actions import PersistenceExtensions
from java.time import ZonedDateTime

from core.date import minutes_between

@rule("Process sensor update")
@when("Time cron 0 0/1 * * * ?")

def heartBeat20m(event):
    for i in ir.getItem("gCheck20Minutes").members:
        itemName = format(i.name)

        timeNow = ZonedDateTime.now()
        lastRecord = DateTimeType(PersistenceExtensions.lastUpdate(ir.getItem(itemName)))
        lastUpdate = minutes_between(lastRecord, timeNow)

        if lastUpdate > 20:
            events.sendCommand( itemName + "_DS", "ON" )

@rule("A device stopped reporting")
@when("Member of gDeviceStatuses changed from OFF to ON")
@when("Member of gDeviceStatuses changed from UNDEF to ON")
@when("Member of gDeviceStatuses changed from NULL to ON")

def sensorOffline(event):
    actions.get("telegram", "telegram:telegramBot:alert").sendTelegram(1755292235, "Item " + event.itemName + " is offline")

It would be nice if I could send the item label by telegram and not the item name, but I didn’t find how.

i.label

Personally, I set a name metadata on the Item and use that because the label on my UIs don’t always match what I want to use in the alerts. There are Help Library functions to set and read Item metadata.