Hi @haesslo many thanks for the suggestion. I am not sure if it is really much simpler than creating a rule though.
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ā¦
Just for information, this is how I do it (in a rule)ā¦
// lambda to update an (Alarm) Item to reflect a Thing's Offline state
val Functions$Function2<String, SwitchItem, Boolean> setOfflineAlarm =
[ String thingId, SwitchItem alarmItem |
val thingStatus = getThingStatusInfo(thingId)
if ((thingStatus !== null) && (thingStatus.getStatus().toString() == "ONLINE")) {
alarmItem.postUpdate(OFF)
} else {
alarmItem.postUpdate(ON)
}
true
]
rule "Hub Offline Status Checks (at *:*:5)"
when
Time cron "5 1/1 * * * ?"
then
setOfflineAlarm.apply("siemensrds:climatixic:cloud", Siemens_Cloud_Server_Offline_Alarm)
setOfflineAlarm.apply("neohub:neohub:g24", Heatmiser_NeoHub_Offline_Alarm)
setOfflineAlarm.apply("tado:home:g24", Tado_Home_Hub_Offline_Alarm)
setOfflineAlarm.apply("hdpowerview:hub:g24", Luxaflex_Hub_Offline_Alarm)
setOfflineAlarm.apply("hue:bridge:g24", Philips_Hue_Hub_Offline_Alarm)
setOfflineAlarm.apply("harmonyhub:hub:g24", Logitech_Harmony_Hub_Offline_Alarm)
setOfflineAlarm.apply("velux:klf200:g24", Velux_KLF200_Hub_Offline_Alarm)
setOfflineAlarm.apply("zwave:serial_zstick:g24", ZWave_USB_Stick_Offline_Alarm)
setOfflineAlarm.apply("astro:sun:g24", Astro_Offline_Alarm)
setOfflineAlarm.apply("homeconnect:api_bridge:g24", Bosch_Home_Connect_Offline_Alarm)
setOfflineAlarm.apply("darksky:weather-api:g24", DarkSky_Weather_API_Offline_Alarm)
end
You can simplify the lambda definition a bit:
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 ā¦
The same thing with HABApp:
from HABApp import Rule
from HABApp.core.events import ItemNoChangeEvent
from HABApp.openhab.items import Thing
class CheckThing(Rule):
def __init__(self, name: str):
super().__init__()
self.thing = Thing.get_item(name)
watcher = self.thing.watch_change(60)
self.thing.listen_event(self.thing_no_change, watcher.EVENT)
def thing_no_change(self, event: ItemNoChangeEvent):
print(f'Thing {event.name} constant for {event.seconds}')
print(f'Status: {self.thing.status}')
CheckThing('chromecast:chromecast:xyz123')
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.
You might be able to put all ChromeCasts into a group, and then react on changes in the group.
In the end I decided to write them with a loop in the Ansible template. This way I change the template and when it is deployed, it created a rule for every CC.
I use this
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.
Rickytr, can you share your rule using Log Reader? Iām trying this but canāt get it working.
@fullmoonguru I used the trigger to catch a new custom event and added every received event to a linked queue to be processed (because usually you receive more than one event if a thing goes offlineā¦)
rule āEvent log managementā
when
Channel ālogreader:reader:b211c4e3:newCustomEventā triggered
then
if (logEvents.peek === null && evento.state.toString == āONā)
evento.postUpdate (OFF)
logEvents.add(receivedEvent.toString())
if(timer === null && evento.state.toString != āONā) {
timer = createTimer(now.plusSeconds(5), [ |
if (evento.state.toString != āONā) {
evento.sendCommand(ON)
timer = null
}
])
}
end
I put in patterns for the logreader thing āto ONLINE|to OFFLINEā and filtered out ItemStateChangedEvent to avoid the loop.
@Rickytr Iām pretty new at this. When you say:
I put in patterns for the logreader thing āto ONLINE|to OFFLINEā and filtered out ItemStateChangedEvent to avoid the loop.
How did you do that?
Then in the script, Iām not clear what itās doing. It looks like itās posting an event (a virtual switch you created?) as OFF if something is offline and ON if nothing is offline. Not clear what teh timer is doing.
Sorry for my noob questions & thanks for your help.
Youāll want to read up on
@fullmoonguru I use the switch to start another piece of code that parse every event in the linked queue. I decided to use the timer to start parsing after some seconds because in this way I can manage better when I receive several offline errors together, for example when Hue hub goes offline with every connected light.
@rossko57 thanks for replying I DID read up on this before trying it. Hereās what I tried:
First I did:
Rule ID = Device_Offline_Alert
When > Thing Event > Log Reader > A Trigger Channel Fired > Channel > New Error Event > Event = COMMUNICATION_ERROR
Then > Execute a script (my email script)
That didnāt work so then I tried:
When > Thing Event > Log Reader > Trigger Channel Fires > Channel: newCustomEvent > Event = COMMUNICATION_ERROR
No luck there either.
I also tried Status change to OFFLINE and Status updated to OFFLINE, in the Logreader thing which didnāt work (I assume thatās because itās referring to the Logreader thing itself).
I can see the alerts in the logfile so I know thatās working, and I know the email is working because I can get successful results by making the trigger an offline alert from a specific Thing.
@rossko57 do you have any ideas why this isnāt working for me?
is difficult to diagnose. Did the rule run, is it your email that doesnāt work? Itās up to you to find out. You could add a log at the start of your rule to say when itās triggered.
Do you see that in your events.log
? May we see? Does it match your rule trigger? May we see that? ('codeāif you are using UI rules)
Are there any new options in OH3 to support āmonitoring a group of thingsā
a) thing status changed
b) certain channels are triggered
This should be based on groups. I just started to implement a rule monitoring my Shellys in an alarm is triggered. After the 15h āChanel xxx triggered oirā I stopped and looking for other options. For me it doesnāt make sense that I need to list every channel and hard code the thing uid. Why is it not possible to build a group of channels?
or could I
- build a group of things (possible with the OH3 model)
- have a periodic rule (once a minute)
- iterate on the group, get thing status and check for OFFLINE
That would be ok for checking the thing status, but even doesnāt cover the aspect that things raise an alarm by triggering a channel.
As with pretty much all āwhyā questions in openHAB, the answer is because no one has implemented it. Adding support for something like this will require changes to the core API and rule engine triggers since the ThingRegistry doesnāt have any way to get all Things or all Things with a given tag or anything like that.
Not possible, The model is just a way to organize your Items.
This is very much possible.
Given you canāt use the ThingRegistry to get the list of all Things and you canāt create a Group of Things about the only remaining thing you can do is to query the REST API for all the Things and parse through the returned JSON. You could put that into a once a minute triggered rule or the like.
@rossko57 I had a logfile running and could see the Thing drop. I just never saw the rule trigger. The email is the same script I use for other alerts and I also manually triggered the rule and got the email. I am working on some other issues right now but Iāll get back on this and try to give more detailed info. I appreciate the help.