I don’t understand this statement.
If you are worried about making sure OH knows your script is still running, then there are lots of ways it can figure that out without needing to poll for its online status, particularly if you used MQTT.
I use the following to determine and alert when my external scripts and services go offline:
First I created a Group:
Group:Switch:AND(ON, OFF) gSensorStatus
Then I create an Online Item to track the online status of a single server or device I care about. When I’m receiving messages via MQTT then I just subscribe to the same topic and any message received on the topic will set the online status to ON. then I use an exipre binding config to make the Item turn OFF when it hasn’t been updated after a certain period of time.
Switch vCerberos_SensorReporter_Online "Cerberos sensorReporter [MAP(admin.map):%s]"
<network> (gSensorStatus)
{ mqtt="<[mosquitto:status/sensor-reporters:command:OFF:.*cerberos sensorReporter is dead.*],<[mosquitto:status/cerberos/heartbeat/string:command:ON]", expire="11m,command=OFF" }
The above Item subscribes to one of the topics sensorReporter (see link above) publishes to periodically and expires when no message is received for 11 minutes.
If you can’t do something like this you will need a rule to update the Online Item. See the Generic Is Alive Deisgn Pattern for one approach.
Then I have the following rules which will send an alert to me when any member of gSensorStatus goes OFF along with an alert when OH restarts and in the morning listing all the offline devices.
import java.util.concurrent.locks.ReentrantLock
import java.util.Map
val ReentrantLock statusLock = new ReentrantLock
val Map<String, Timer> timers = newHashMap
rule "A sensor changed its online state"
when
Item gSensorStatus received update
then
try {
statusLock.lock
Thread::sleep(100)
val recentUpdates = gSensorStatus.members.filter[sensor|sensor.lastUpdate("mapdb") != null && sensor.lastUpdate("mapdb").isBefore(now.minusSeconds(1).millis)]
recentUpdates.forEach[sensor|
val alerted = gOfflineAlerted.members.filter[a|a.name==sensor.name+"_Alerted"].head
if(alerted == null) logError("admin", "Cannot find Item " + sensor.name+"_Alerted")
if(alerted != null && alerted.state == sensor.state && timers.get(sensor.name) == null){
val currState = sensor.state
// wait a few seconds and check again before sending alert
timers.put(sensor.name, createTimer(now.plusSeconds(15), [|
if(sensor.state == currState) {
aInfo.sendCommand(transform("MAP", "admin.map", sensor.name) + " is now " + transform("MAP", "admin.map", sensor.state.toString) + "!")
alerted.postUpdate(if(sensor.state == ON) OFF else ON)
}
]))
}
]
}
catch(Exception e){
logError("admin", "Error processing an online status change: " + e.toString)
}
finally {
statusLock.unlock
}
end
rule "Reminder at 08:00 and system start"
when
Time cron "0 0 8 * * ? *" or
System started
then
val message = new StringBuilder
val offline = gSensorStatus.members.filter[sensor|sensor.state != ON]
if(offline.size > 0) {
message.append("The following sensors are offline: ")
offline.forEach[sensor|
message.append(transform("MAP", "admin.map", sensor.name))
message.append(", ")
gOfflineAlerted.members.filter[a|a.name==sensor.name+"_Alerted"].head.postUpdate(ON)
]
message.delete(message.length-2, message.length)
aInfo.sendCommand(message.toString)
}
end
Everything is event driven and therefore requires no polling.