Hi,
i have a sitemap where i can see, how long in minutes the last update of an item was ago.
So with cron i get a new calculation every minute and i can see: last update: 5 minutes, 6 minutes and so on
Here is my rule:
rule "Update Xiaomi Temp time since"
when
Time cron "0 * * * * ?"
then
if(SystemStarting.state == OFF) {
gXiaomiZeit.members.forEach[ DateTimeItem lastTime |
logInfo("temp-anz-5 rule","lastTime : "+lastTime)
val lastMillis = (lastTime.state as DateTimeType).getZonedDateTime().toInstant().toEpochMilli()
val mins = (now.toInstant().toEpochMilli() - lastMillis) / 60000
//val split = lastTime.split("_") // so we can reconstruct the time_since Item name
val split = lastTime.name.split('_')
(split.get(0)+"_"+split.get(1)+"_"+split.get(2)+"_time_since").postUpdate(mins.toString)
]
}
end
loginfo output and error in openhab log:
2022-12-20 14:32:00.519 [INFO ] [ab.core.model.script.temp-anz-5 rule] - lastTime : Xiaomi_Temp_1_last_connection (Type=DateTimeItem, State=NULL, Label=Temp 1, Category=clock, Groups=[gXiaomiZeit])
2022-12-20 14:32:00.520 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'temperatur_anzeigen-5' failed: Could not cast NULL to org.openhab.core.library.types.DateTimeType; line 100, column 21, length 30 in temperatur_anzeigen
2022-12-20 14:32:06.520 [WARN ] [b.core.model.script.actions.BusEvent] - Cannot convert '2022-12-20T14:32:06.520505+01:00[Europe/Berlin]' to a state type which item 'Xiaomi_Temp_10_last_connection' accepts: [DateTimeType, UnDefType].
As I said before, you need to check whether lastTime.state is a DateTimeType before casting it.
Maybe something like this:
gXiaomiZeit.members.forEach[ DateTimeItem lastTime |
var status = ""
if (lastTime.state instanceof DateTimeType) {
val lastMillis = (lastTime.state as DateTimeType).getZonedDateTime().toInstant().toEpochMilli()
val mins = (now.toInstant().toEpochMilli() - lastMillis) / 60000
status = mins.toString
}
val split = lastTime.name.split('_')
(split.get(0)+"_"+split.get(1)+"_"+split.get(2)+"_time_since").postUpdate(status)
]
}
Updated… I REALLY hate rulesdsl now… so tedious
You don’t show your Item naming pattern but I bet something like: lastTime.name.replace('sensor', 'time_since') would make more sense here than splitting and reassembling the name like this.
By the way… With the new rule errors are gone, but now i get warnings:
2022-12-21 14:27:01.471 [WARN ] [b.core.model.script.actions.BusEvent] - Cannot convert '' to a state type which item 'Xiaomi_Temp_1_time_since' accepts: [DecimalType, QuantityType, UnDefType].
It seems, that i get no value to my datetime item. I will wait some time until the Temp Sensors give me new values.
Ahh your “time_since” item is a Numeric item! I thought it was a String item.
If I were you I would either change it to a DateTime item (and do the formatting of time / duration using state description format thingy), or a String. But assuming you want to keep things as is, what would you want the “time_since” to be updated to, if the lastTime is NULL? That’s what you need to do in the “else” clause.
GOOD catch! I didn’t even pay attention to that!
Incorporating the excellent suggestions from @rlkoshak:
gXiaomiZeit.members.forEach[ DateTimeItem lastTime |
val timeSinceItemName = lastTime.name.replace('sensor', 'time_since')
if (lastTime.state instanceof DateTimeType) {
val mins = java.time.Duration.between((lastTime.state as DateTimeType).zonedDateTime, now).toMinutes
postUpdate(timeSinceItemName, mins.toString)
} else {
postUpdate(timeSinceItemName, NULL)
}
]
Note I switched the order for Duration.between. I think it should be Duration.between(older, newer) to get a positive duration. See Duration (Java Platform SE 8 )