This post is a bunch of simple little Rules which rounds out the transfer from my admin.rules file.
Send a system status alert every morning and when OH restarts
Rules DSL
rule "Reminder at 08:00 and system start"
when
Time cron "0 0 8 * * ? *" or
System started
then
val numNull = gSensorStatus.members.filter[ sensor | sensor.state == NULL ].size
if( numNull > 0) logWarn("admin", "There are " + numNull + " sensors in an unknown state")
val offline = gSensorStatus.members.filter[ sensor | sensor.state == OFF ]
if(offline.size == 0) return;
val message = new StringBuilder
message.append("The following sensors are known to be offline: ")
offline.forEach[ sensor |
var name = transform("MAP", "admin.map", sensor.name)
if(name == "") name = sensor.name
message.append(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
Get the list of Items that are OFF and build a message listing those Items and alert. Set the alerted flag to ON.
I’ve not touched this Rule in years and as written it could be improved some.
Python
from core.rules import rule
from core.triggers import when
from core.metadata import set_metadata, get_key_value
from personal.util import send_info
@rule("System status reminder", description="Send a message with a list of offline sensors at 08:00 and System start", tags=["admin"])
@when("Time cron 0 0 8 * * ? *")
@when("System started")
def status_reminder(event):
status_reminder.log.info("Generating daily sensor status report")
numNull = len(filter(lambda item: isinstance(item.state, UnDefType), ir.getItem("gSensorStatus").members))
if numNull > 0: status_reminder.log.warning("There are {} sensors in an unknown state!".format(numNull))
offline = filter(lambda item: item.state == OFF, ir.getItem("gSensorStatus").members)
if len(offline) == 0:
status_reminder.log.info("All sensors are online")
return
status_reminder.log.info("Building message")
offlineMessage = "The following sensors are known to be offline: {}".format(", ".join(map(lambda sensor: "{}".format(get_key_va
lue(sensor.name, "Static", "name") or sensor.name), sorted(sensor for sensor in offline))))
status_reminder.log.info("Updating all of the alerted flags")
for sensor in offline: set_metadata(sensor.name, "Alert", { "alerted" : "ON"}, overwrite=False)
status_reminder.log.info("Sending the message")
send_info(offlineMessage, status_reminder.log)
Power Meter Status
My Zwave whole house power meter often falls offline. This little Rule converts the ONLINE/OFFLINE Thing statuses to an Online Item used by the rest of the Rules.
Rules DSL
rule "Power Meter OFFLINE"
when
Thing "zwave:device:dongle:node7" changed from ONLINE to OFFLINE
then
vPowerMeter_Online.sendCommand(OFF)
end
rule "Power Meter ONLINE"
when
Thing "zwave:device:dongle:node7" changed to ONLINE
then
vPowerMeter_Online.sendCommand(ON)
end
Python
from core.rules import rule
from core.triggers import when
@rule("Power Meter online status", description="Zwave has marked the power meter as offline", tags=["admin"])
@when("Thing zwave:device:dongle:node7 changed")
def pm_online(event):
pm_online.log.info("Power meter Thing changed status {}".format(event.statusInfo.status))
if event.statusInfo.status == ONLINE: events.sendCommand("vPowerMeter_Online", "ON")
else: events.sendCommand("vPowerMeter_Online", "OFF")
Process Heartbeat
Rules DSL
I’ve a number of devices (Sonoffs, ESPEasy, my own sensorReporter scripts) that report their uptime periodically as a heartbeat. This Rule will ping the Online Item when a heartbeat is received to reset the Expire binding and keep the device/service online.
rule "Process heartbeat"
when
Member of SensorEvents received update
then
sendCommand(triggeringItem.name.replace("Uptime", "Online"), "ON")
end
Python
from core.rules import rule
from core.triggers import when
@rule("Process heartbeat", description="Process an uptime heartbeat message to ping the online status of a sensor", tags=["admin"])
@when("Member of SensorEvents received update")
def heartbeat(event):
events.sendCommand(event.itemName.replace("Uptime", "Online"), "ON")
Update Items to UNDEF when the service goes offline
These are currently three different Rules. Eventually I’ll merge them into one more generic approach.
Rules DSL
rule "Hydra went offline"
when
Item vHydra_SensorReporter_Online changed to OFF
then
logInfo("admin", "Hydra went offline, setting relevant Items to UNDEF")
vFrontDoor.postUpdate(UNDEF)
vFrontDoor_Timer.postUpdate(OFF)
vBackDoor.postUpdate(UNDEF)
vBackDoor_Timer.postUpdate(OFF)
vGarageDoor.postUpdate(UNDEF)
vGarageDoor_Timer.postUpdate(OFF)
end
rule "Cerberos went offline"
when
Item vCerberos_SensorReporter_Online changed to OFF
then
logInfo("admin", "Cerberos went offline, setting relevant Items to UNDEF")
vGarageOpener1.postUpdate(UNDEF)
vGarageOpener1_Timer.postUpdate(OFF)
vGarageOpener2.postUpdate(UNDEF)
vGarageOpener2_Timer.postUpdate(OFF)
end
rule "Manticore sensorReporter went offline"
when
Item vManticore_SensorReporter_Online changed to OFF
then
logInfo("admin","Manticore went offline, setting relevant Items to UNDEF")
vJennPhone_Manticore_Net.postUpdate(UNDEF)
vRichPhone_Manticore_Net.postUpdate(UNDEF)
vGJPhone1_Manticore_Net.postUpdate(UNDEF)
vGJPhone2_Manticore_Net.postUpdate(UNDEF)
end
Python
from core.rules import rule
from core.triggers import when
# TODO: make generic
@rule("Hydra Offline", description="Sets relevant Items to UNDEF when this sensor goes offline", tags=["admin"])
@when("Item vHydra_SensorReporter_Online changed to OFF")
def hydra_offline(event):
hydra_offline.log.warn("Hydra went offline, setting relevant Items to UNDEF")
events.postUpdate("vFrontDoor", "UNDEF")
events.postUpdate("vFrontDoor_Timer", "OFF")
events.postUpdate("vBackDoor", "UNDEF")
events.postUpdate("vBackDoor_Timer", "OFF")
events.postUpdate("vGarageDoor", "UNDEF")
events.postUpdate("vGarageDoor_Timer", "OFF")
@rule("Cerberos Offline", description="Sets relevant Items to UNDEF when this sensor goes offline", tags=["admin"])
@when("Item vCerberos_SensorReporter_Online changed to OFF")
def cerberos_offline(event):
cerberos_offline.log.warn("Cerberos went offline, setting relevant Items to UNDEF")
events.postUpdate("vGarageOpener1", "UNDEF")
events.postUpdate("vGarageOpener1_Timer", "OFF")
events.postUpdate("vGarageOpener2", "UNDEF")
events.postUpdate("vGarageOpener2_Timer", "OFF")
@rule("Manticore Offline", description="Sets relevant Items to UNDEF when this sensor goes offline", tags=["admin"])
@when("Item vManticore_SensorReporter_Online changed to OFF")
def manticore_offline(event):
manticore_offline.log.warn("Manticore went offline, setting relevant Items to UNDEF")
events.postUpdate("vJennPhone_Manticore_Net", "UNDEF")
events.postUpdate("vRichPhone_Manticore_Net", "UNDEF")
events.postUpdate("vGJPhone1_Manticore_Net", "UNDEF")
events.postUpdate("vGJPhone2_Manticore_Net", "UNDEF")
Previous: Journey to JSR223 Python 2 of 9
Next: Journey to JSR223 Python 4 of 9
EDIT: Corrections and improvements from 5iver.