The Expire binding/NULL error checking is a great idea, and I’ll go ahead and do that. Must make sense to combine with an external script that checks across all Things - my crappy Expect script already does that, although I’d be very interested to see something more sophisticated, e.g. in Python.
The main reason I didn’t recommend that to OP in the first place is because anything based on the Expire binding is going to require that the Item linked to the channel to receive an update or command on a regular schedule (e.g. always posts update once per hour whether there is a change in state or not). I wasn’t sure if all of the Things op was interested in do that and I didn’t want to waste time if they don’t.
For completeness, here is a generic approach that will work if the Items are periodically updated whether or not there is a change.
Look at the bottom of the top post for the Expire based example.
When one is using the MQTT binding (subscribe to the topics the device reports on and set the online switch to ON for any message) or devices that have a heartbeat channel (some ZWave devices, e.g zcombo smoke/co alarms) or online status channel (e.g. Nest) you don’t need most of the code in that example as the Expire binding handles everything but the reporting.
But can you iterate over all the Things to get their status? That is the core of OP’s problem.
I agree with this statement and OH itself really isn’t built that well to support this type of monitoring. However, often in a Rule one will want to do something different if OH can know that something is down so whatever system you are using needs to report this status to OH which kind of puts you back in the same situation of OH monitoring itself.
But I think of it like this. OH really isn’t monitoring itself in this case, it is monitoring the status of the actuators and sensors that it interacts with and their online status can be very important. I suppose it all depends on where do you draw the boundaries between OH and Not OH.
Just upgraded to 2.4, and ThingAction is no longer working.
This is my rule
rule "TV Binding State Changed"
when
Thing "samsungtv:tv:familyroom" changed
then
var status = ThingAction.getThingStatusInfo("samsungtv:tv:familyroom").getStatus()
logInfo("Family Room TV", "TV Thing status changed to: " + status)
postUpdate(TV_Status, status.toString)
end
This throws the error
23-Dec-2018 14:30:46.570 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'TV Binding State Changed': The name 'ThingAction' cannot be resolved to an item or type; line 3586, column 18, length 11
23-Dec-2018 14:30:46.570 [DEBUG]
Thanks for inspiring me with this discussion! I added some Thing monitoring to my rules and optimized logging to suppress some unavailable or unhelpful strings from getThingStatusInfo():
rule "TV"
when
Thing 'samsungtv:tv:14dc9380_XXX' changed
then
val ThingStatusInfo = getThingStatusInfo("samsungtv:tv:14dc9380_XXX")
if(ThingStatusInfo===null) return;
var String thingStatusInfo_Msg = ""
if(ThingStatusInfo.statusDetail.toString!="NONE") thingStatusInfo_Msg = thingStatusInfo_Msg + ThingStatusInfo.statusDetail
if(ThingStatusInfo.description!==null) thingStatusInfo_Msg = thingStatusInfo_Msg + ThingStatusInfo.description
if(thingStatusInfo_Msg!="") logInfo("RULE","@R TV: {} [{}]", ThingStatusInfo.status, thingStatusInfo_Msg)
else logInfo("RULE","@R TV: {}", ThingStatusInfo.status)
end
I agree with @rlkoshak that adding a rule for each Thing is suboptimal.
It would be easier if something like triggeringItem exists for Things as you may find in this non-working example:
rule "TV"
when
Thing 'samsungtv:tv:livingroom' changed or
Thing 'samsungtv:tv:bedroom' changed or
Thing 'samsungtv:tv:kitchen' changed
then
val TriggeredThing = triggeringThing
val ThingStatusInfo = getThingStatusInfo(TriggeredThing)
hmmm…I was warned to revive the topic after one year, but I think it might be quite of interest and want to contribute a solution that was not mentioned here before (I hope) and did do the trick for me.
I dont want to really monitor all my things but for sure also not create a rule for every single thing. But creating an item to hold the status for every thing I want to monitor seemed ok for me. So I use http binding with REST API and very simply created an item:
You can have than a rule for gOnline group changed if you want to alert getting the triggering item.
You could do some more transform in JS to use a switch item (having JS return ON/OFF)
You can also do more transform in JS to get more out of the Json returned by the REST api (thing label or thing UID…)
And through http binding you can obviously set the timing how often you want to check the thing.
And also nice in my experience: You can monitor via persistance (using Grafana or similar)
I can contribute something for all the HABApp users, too.
HABApp listens to the Thing events and it is really easy to trigger on a change of the status.
import HABApp
from HABApp import Rule
from HABApp.openhab.events import ThingStatusInfoChangedEvent
from HABApp.openhab.items import Thing
class CheckAllThings(Rule):
def __init__(self):
super().__init__()
for thing in HABApp.core.Items.get_all_items():
if isinstance(thing, Thing):
thing.listen_event(self.thing_status_changed, ThingStatusInfoChangedEvent)
print(f'{thing.name}: {thing.status}')
def thing_status_changed(self, event: ThingStatusInfoChangedEvent):
print(f'{event.name} changed from {event.old_status} to {event.status}')
CheckAllThings()
I tried and what should work is :
Define item as switch with http binding and transform JS: Switch OnlineAstroMoon2 "Online AstroMoon [%s]" (gOnline) { http="<[http://localhost:8080/rest/things/astro:moon:gg:30000:JS(online.js)]"}
Then in your transform directory you create a fiel “online.js” which should contain:
(function(i) {
var obj = JSON.parse(i);
var status = obj.statusInfo.status;
if (status == "ONLINE") {
return "ON"
} else {
return "OFF"
}
})(input)
Maybe question of taste, but just to clarify:
The rules proposed here were one rule per Thing
My solution is one item per thing and one generic JS for all, which is only needed if you want to have the ON/OFF feature.
I feel managing items is much easier than managing rules…
val setOfflineAlarm = [ String thingId, SwitchItem alarmItem |
val thingStatus = getThingStatusInfo(thingId)
if ((thingStatus !== null) && (thingStatus.getStatus().toString() == "ONLINE")) {
alarmItem.postUpdate(OFF)
} else {
alarmItem.postUpdate(ON)
}
]
It’s smart enough to figure out what type setOfflineAlarm needs to be on it’s own and since you don’t actually use the return value, it will generate a Procedure instead of a Function.
Had to implement Things monitoring as well, however in my case quite often the Thing only goes offline for a couple seconds, before the Binding reconnects (ChromeCasts). Here are the two rules I use for this:
// use a timer to avoid notifications for short outages
rule "ChromeCast Living Room offline - timer"
when
Thing "chromecast:chromecast:xyz123" changed from ONLINE to OFFLINE
then
logInfo("ChromeCast Status", "ChromeCast Living Room offline")
if (timerLivingRoom === null) {
timerLivingRoom = createTimer(now.plusMinutes(1), [ |
// there was no cancel because the Thing never came online in the past minute
// ... send notification here
logInfo("ChromeCast Status", "ChromeCast Living Room is offline")
])
}
end
rule "ChromeCast Living Room online - timer"
when
Thing "chromecast:chromecast:xyz123" changed from OFFLINE to ONLINE
then
logInfo("ChromeCast Status", "ChromeCast Living Room is online")
if (timerLivingRoom === null) {
// recovered from longer downtime, > 1 minute
logInfo("ChromeCast Status", "Timer for chromecast:chromecast:xyz123 is already stopped")
} else {
logInfo("ChromeCast Status Debug", "Timer for chromecast:chromecast:xyz123 is running, stopping it")
timerLivingRoom.cancel()
timerLivingRoom = null
// no further notification required, was a short downtime
}
end
Need to pour that with more details into a blog post as well …
I was looking for the same thing but I didn’t want to write a rule for every thing so I choose to use the logreader binding to trap ONLINE/OFFLINE events and an hashmap to associate things to items.