Rendering thing (not item) status (online / offline / initializing...)

Tags: #<Tag:0x00007f74575b73b8> #<Tag:0x00007f74575b72c8> #<Tag:0x00007f74575b7200>

At home I have a couple bindings having things going offline every now and then, so I wanted to be able to keep track of their status and display it in a sitemap.

In this case I had to create proxy items that will contain the actual thing’s status and a rule takes care of updating these status items whenever needed / requested.

Here’s the code (JSR223 Python, store in /etc/openhab2/automation/jsr223/python/personal/):

from core.rules import rule
from core.triggers import when
from org.eclipse.smarthome.core.thing import ThingUID


@rule("Alert: Key thing status update")
## Update thing status when rule engine starts:
@when("System started")
## Update thing status every 10 minutes:
@when("Time cron 0 0/10 * * * ?")
######################################################################
# TO DO:
# (1) make sure each thing has its @when() rule decorator below;
# (2) make sure each thing also appears in keyThingsDict
# (3) make sure each ThingStatusItem (see keyThingsDict) exists in the Item Registry
######################################################################
## Z-Wave controller (ZME E UZB1)
@when("Thing zwave:serial_zstick:controller changed")
## Roller Shutters:
@when("Thing zwave:device:controller:node2 changed")
# (etc.)
## IKEA TRÅDFRI gateway (replace 'a1b2c3d4e5f6' with your gateway ID):
@when("Thing tradfri:gateway:gwa1b2c3d4e5f6 changed")
## OpenWeathermaps status (replace 'a1b2c3d4' with your OWM Thing identifier):
@when("Thing openweathermap:weather-api:a1b2c3d4 changed")
@when("Thing openweathermap:weather-and-forecast:a1b2c3d4:local changed")
## Buienradar:
@when("Thing buienradar:rain_forecast:home changed")
def KeyThingStatusUpdate(event):
    keyThingsDict = {
        ## Format: "ThingUID": "ThingStatusItemName"
        "zwave:serial_zstick:controller": "ZWave_Controller_Status",
        "zwave:device:controller:node2": "Bedroom_NE_Shutter_Status",
        # (etc.)
        # IKEA TRÅDFRI:
        "tradfri:gateway:gwa0c9a0d644f9": "IKEA_TRADFRI_Gateway_Status",
        # OpenWeatherMaps Binding:
        "openweathermap:weather-api:7f556256": "Wx_OWM_API_Status",
        "openweathermap:weather-and-forecast:7f556256:local": "Wx_OWM_Weather_Status",
        # BuienRadar binding:
        "buienradar:rain_forecast:home": "BuienRadar_Status",
    }
    KeyThingStatusUpdate.log.info("event = " + pp.pformat(event))

    # Store a list of all things that must be updated:
    keyThings = []
    if event:
        # Rulle triggered by a thing status change --> only one thing to process
        keyThings.append(str(event.thingUID))
    else:
        # Rulle has not been triggered by a thing status change --> process all things
        for k in keyThingsDict.keys():
            keyThings.append(k)

    for k in keyThings:
        keyItem = keyThingsDict[k]
        nodeName = k.split(':')[-1]
        # thing state is not available in event if rule triggered by cron:
        nodeState = str(event.statusInfo) if event else things.get(ThingUID(k)).status
        KeyThingStatusUpdate.log.debug("Thing '{node_name}' (item {item_name}) status changed to '{node_state}'".format(
            node_name = nodeName,
            item_name = keyItem,
            node_state = nodeState,
        ))
        # Post the status update to the thing status item:
        events.postUpdate(keyItem, str(nodeState)) 

Here are the status items:

// Z-Wave Things:
String ZWave_Controller_Status "Z-Wave Controller Status [%s]"	<traffic_light>	(gPersist_everyChange)
// This group item with aggregation will have value in 'ONLINE' if all of its direct children
// have their state set to 'ONLINE', else the group item will have value 'ERROR':
Group:String:AND('ONLINE','ERROR') gKeyZWaveThings "Key Z-Wave Things [%s]" <traffic_light>
// The other Z-Wave things  I want to keep status info from:
String Bedroom_NE_Shutter_Status "Bedroom NE Blinds Status [%s]"	<traffic_light>	(gKeyZWaveThings, gPersist_everyChange)
// (all other Z-Wave things defined in the same manner)

// IKEA TRÅDFRI Things:
String IKEA_TRADFRI_Gateway_Status "IKEA TRÅDFRI Gateway Status [%s]"	<traffic_light>	(gPersist_everyChange)

// OpenWeatherMaps Things:
// Aggregator group (see above): 'ONLINE' if all children are 'ONLINE' else set to 'ERROR'):
Group:String:AND('ONLINE','ERROR') gWxOWMKeyThings "Key OWM Things [%s]" <traffic_light>
// OWM API status:
String Wx_OWM_API_Status "OWM Weather API [%s]"	<traffic_light>	(gWxOWMKeyThings, gPersist_everyChange)
// OWM Current weather and forecast status:
String Wx_OWM_Weather_Status "OWM Weather & Forecast [%s]"	<traffic_light>	(gWxOWMKeyThings, gPersist_everyChange)
// Note: local UV currently not added in my setup)

// BuienRadar Things:
String BuienRadar_Status "Buienradar [%s]"	<traffic_light>	(gPersist_everyChange)

Notes:

  1. the gPersist_everyChange group is used for assigning the “everyChange” persistence strategy.
  2. I created a traffic_light dynamic icon set for the purpose:
    SVG: traffic_light_green traffic_light_orange traffic_light_red
    PNG: traffic_light_green traffic_light_orange traffic_light_red

These icons can be placed in /etc/openhab2/icons/classic/
I created the following dynamic icon mappings with symbolic links (replace png with svg for the SVG mappings):

traffic_light-green.png
traffic_light-online.png -> traffic_light-green.png

traffic_light-orange.png
traffic_light-initializing.png -> traffic_light-orange.png

traffic_light-red.png
traffic_light-offline.png -> traffic_light-red.png
traffic_light.png -> traffic_light-red.png
traffic_light-uninitialized.png -> traffic_light-red.png

The sitemap entry reads as follows:

	Frame label="Status Info" icon="error" {
		Default item=IKEA_TRADFRI_Gateway_Status
		Text item=gKeyZWaveThings {
			Default item=ZWave_Controller_Status

			Text label="Bedroom blinds" icon="firstfloor"
			Default item=Bedroom_NE_Shutter_Status
			// (etc.)
		}
		Text item=gWxOWMKeyThings {
			Default item=Wx_OWM_API_Status
			Default item=Wx_OWM_Weather_Status
		}
		Default item=BuienRadar_Status
	}

Have fun!

3 Likes