Problem Statement
Often we have one device that populates the states of multiple Items. When that device goes offline, it can be important in some cases to modify those Items to UNDEF so Rules and the user knows that there is something wrong and it may take alternative actions.
In some cases, the binding will handle this for you. For example, the MQTT 2.x binding will set all Items linked to one of it’s Thing’s Channels to UNDEF if the connection to the broker is lost. But other bindings may not support this.
This posting provides an approach to get the same behavior using Rules.
Concept
Create a Group of all the Items that represent the online/offline status of a device that has multiple Items that are populated by it. I called this Group DeviceControllers.
For each device’s online status Item, create another Group using Design Pattern: Associated Items which and add all the Items populated by that device to that Group.
Example Items
Group:Switch:AND(ON, OFF) DeviceControllers
Switch vNest_Online "Nest Status [MAP(hvac.map):%s]"
<network> (DeviceControllers)
{ nest="<[thermostats(Entryway).is_online]" }
Group vNest_Items
DateTime vNest_LastConnection "Last Nest Connection [%1$tm/%1$td %1$tH:%1$tM]"
<time>
{ channel="nest:thermostat:nest:blahblahblah:last_connection" }
Number:Dimensionless vNest_Humidity "Main Floor Humidity [%d%%]"
<humidity> (gChart, gIndoorHumidity, vNest_Items)
{ channel="nest:thermostat:nest:blahblahblah:humidity",
name="Main floor humidity" }
Number:Temperature vNest_Temp "Main Floor Ambient Temp [%d °F]"
<temperature> (gChart, gIndoorTemps, gMaxTemp, LowerFloorsTemps, UpperFloorsTemps, vNest_Items)
{ channel="nest:thermostat:nest:blahblahblah:temperature" }
String vNest_State "Heating State [%s]"
<fire> (gChart, vNest_Items)
{ channel="nest:thermostat:nest:blahblahblah:state" }
String vNest_Heating "Heating Active [%s]"
<fire> (gChart, vNest_Items)
Number:Temperature aNest_TargetTemp "Furnace Target Temp [%.0f °F]"
<temperature> (gChart)
{ channel="nest:thermostat:nest:blahblahblah:set_point" }
Switch aNest_Fan "Fan [%s]"
<fan> (gChart, vNest_Items) ["Switchable"]
{ channel="nest:thermostat:nest:blahblahblah:fan_timer_active" }
Notice how there are some Items where it makes sense to not reset to UNDEF like last contact.
Rules
Python
"""Rule that sets all Items assocaited with a given device to UNDEF when that
device is determined to be offline.
Author: Rich Koshak
Functions:
- device_offline: Rule triggered by a member of DeviceControllers changing.
"""
from core.rules import rule
from core.triggers import when
@rule("Reset Offline",
description=("When a device that controls the state of multiple Items "
"goes offline, set all of those Items to UNDEF."),
tags=["admin"])
@when("Member of DeviceControllers changed")
def device_offline(event):
"""Called when a member of DeviceControllers goes offline, finds the Items
that are populted by that device and sets them to UNDEF. This Rule uses the
Associated Items design pattern to get the Group of Items populated by the
given device.
"""
if event.itemState == ON:
return
device_items = "{}_Items".format(event.itemName.split("_")[0])
for sensor in ir.getItem(device_items).members:
events.postUpdate(sensor, UNDEF)
NOTE: The above uses the Helper Libraries.
Rules DSL
import org.eclipse.smarthome.model.script.ScriptServiceUtil
rule "Reset Offline"
when
Member of DeviceControllers changed
than
if(triggeringItem.state == ON) return
val items = ScriptServiceUtil.getItemRegistry.getItem(triggeringItem.name.split("_").get(0)+"_Items")
items.members.forEach[ i | i.postUpdate(UNDEF) ]
end
Theory of Operation
When a device goes offline, meaning it is any state that is not ON, we acquire the Group that has all the Items controlled by that device using Associated Items DP. Then we loop through them all and update them to UNDEF.