Get Thing from Item to tell Item status (e.g. online or offline)

I’m no expert but my first guess is channelUID is not the same as ThingUID

if you omit the last part of the channeluid, the getThingStatusInfo should return something else than NULL

for example getThingStatusInfo(“nest:thermostat:DeviceToken:mode”) returns NULL
and getThingStatusInfo(“nest:thermostat:DeviceToken”) should do the trick

var thingName = output.split(":").get(0)+":"+output.split(":").get(1)+":"+output.split(":").get(2)

Also The JSONPath Transformation Addon is needed for var output = transform(“JSONPATH”, filter, allLinks) to return the correct output

That makes sense now. @Sebastian_Zimmermann’s code recreated the ChannelUID because he included the last segment - the Channel, i.e., get(3) . So, dropping the Channel would make it the Thing. Thanks for spotting that nuance! I’ll give getThingStatusInfo a try again.

Mike

2 Likes

Can I ask the motivation for wanting this? Is it because there are cases where you can’t rely on an item’s state being changed to UNDEF when the bound thing is offline?

I don’t think all bindings respect the convention to force a channel to UNDEF in the event of comms failure. Probably not sensible in the case of e.g. battery devices going for a long sleep.
And there are write-only channels as well.

Yes, basically this. Times when acting on what appears to be an Item in “good standing” when it is actually offline.

This is specifically for my TP-Link devices. Thus, I have a routine that checks the Thing status for these devices and sends me an alert when they go offline.

Interesting; in my experiments with a binding I developed, when transition a thing to offline, I don’t explicitly set the associated channels to UNDEF, but it happens anyway. Might be a OpenHab 2.4 change?

I was testing it because I was testing a change I was working on for HomeKit, and noticed this behavior, and was like “oh geez I guess I don’t need to write all of this code afterall”.

Can you provide some more insight related to the TP-Link devices? Because the binding does set the channels to UNDEF if it’s offline. At least that is intended.

My items were not turning ‘undef’ when my things were going offline, at least z-wave items on earlier releases of OpenHAB (I haven’t tested 2.4).

I cannot be absolutely certain that the Items were not set to UNDEF. All I know is that in my rules, they were not responding to ON/OFF requests. Now that I am aware of the UNDEF state, I suppose I could add that check to my rule before I try to set the Item state. However, what I require is a way to be alerted that a device is offline before I actually need to use it so that I could take action to get it back online before it was called upon in my automations. The approach I used was to check on the status of the Thing. When the Thing Status changes to offline, I send a notification. This gives me a chance to investigate (usually unplug and plug back in is all that is required). But having it operational when required rather than finding out at the time it was needed is what I’m after. I suppose I could monitor the Item state changing to UNDEF instead?

Well, it’s a little more complicated than that; some devices have channels that don’t receive values until their state changes (things like Z-wave devices). So if you add a z-wave device alarm sensor, the device will be online but the value will be UNDEF. You have to uses persistence and trigger the device on/off in order for the UNDEF to clear.

Aside from that caveat, UNDEF seems to be pretty reliable. Like I said, this is OpenHab setting it in response to thing transitioning to offline, so at least you don’t need to rely on binding authors to do this.

I’m wondering rather if an issue here is that the offline status isn’t surfaced through basic UI? It might be possible to do a conditional icon for UNDEF state in the sitemap, I don’t know, I’ve not tried it, but seems like sometime like that should be possible.

I was having a problem with one of my devices not responding to my requests, I didn’t know what was causing it until I “stumbled” on the OFFLINE status when I was poking around in Paper UI. So, Paper UI is reporting the status. I was wanting to be automatically alerted rather than having to manually inspect Paper UI. That’s why I coded a rule that runs every few minutes to check the status of my TP-Link Things. This way I get an e-mail so I am audibly notified within a very few minutes of when the problem arises.

that’s pretty straightforward in fact e.g. myswitch.png , myswitch-on.png myswitch-off.png where you use a big red question mark for myswitch.png. That’ll show up for NULL or UNDEF

Ok makes sense. Even when channels go to undef it doesn’t tell anything about the why.

I think it’s possible to create a rule that would trigger on the status change. That way you don’t need to use a timer.

I also have a lot problems with connectivity with one device (to far away. I guess) and had also problems with it getting a different ip address after it came back online. Therefor in the latest version of the binding it also keeps track of the id. If the ip address changes it will update the ip address (with manual configuration it requires to set the id to make this work and with things created with an older binding they need to be readded to get the id configuration).

1 Like

It is possible. See Rules | openHAB. However, it is less than ideal because if you want to know when a specific Thing goes offline you need to have one Rule for each Thing because there is no way to figure out which Thing going offline cause the Rule to trigger if you have more than one trigger.

Some have done some work arounds using a lambda and the REST API to pull down the list and figure out which Things are offline but I can’t find the post at the moment.

This should be qualified… this is true for the Rules DSL, but the new rule engine does provide event.thingUID for ThingStatusInfoEvent and ThingStatusInfoChangedEvent, when using a GenericEventTrigger. Here is an example for Kodi system states…

from core.rules import rule
from core.triggers import when

@rule("Alert: Kodi system status update")
@when("Thing kodi:kodi:familyroom changed")
@when("Thing kodi:kodi:bedroomupstairs changed")
@when("Thing kodi:kodi:bedroomdownstairs changed")
def kodiSystemStatusUpdate(event):
    kodiDict = {"kodi:kodi:familyroom"        : "DS_FamilyRoom_Kodi_System",
                "kodi:kodi:bedroomupstairs"   : "US_MasterBedroom_Kodi_System",
                "kodi:kodi:bedroomdownstairs" : "DS_MasterBedroom_Kodi_System"}
    kodiName = kodiDict[str(event.thingUID)]
    kodiSystemStatusUpdate.log.debug("Kodi system update: [{}]: [{}]".format(kodiName, event.statusInfo))
    if items[kodiName] == OFF and str(event.statusInfo) == "ONLINE":
        events.sendCommand(kodiName,"ON")
        log.info("Kodi system update: [{}]: ON".format(kodiName))
    elif items[kodiName] == ON:
        events.sendCommand(kodiName,"OFF")
        kodiSystemStatusUpdate.log.info("Kodi system update: [{}]: OFF".format(kodiName))

Note: you could put the Items in a group, iterate through them, and use ItemChannelLinkRegistry to compare the associated ThingUIDs to the one that came through the event, but the dictionary is much cleaner.

The new rules engine is a completely different rules language syntax? :roll_eyes: I’m barely able to plagiarize code for the current rules DSL as it is… I’m afraid; very afraid. :cry:

Sorry… I thought the link to the openhab-jython repo would be enough to explain. This example is for the new rules engine, utilizing JSR223, Jython, and using modules with decorators to simulate Rules DSL syntax. IMO, it’s only a small learning curve, with much more support than when I got into it.

Yes but because the new engine allows the creation and use of libraries, you should find you don’t have to plagerize code that much. Instead you download and use it.

That’s the vision at least. You should find you have to actually write code far less.

But it’s not ready yet. Soon…

Hi Scott, I’m interested in getting corresponding Channels for a given item name and would like to use ItemChannelLinkRegistry as you have indicated.
could you maybe help me on how to use this class in a jython based rule?
(my clumsy try:)


from org.slf4j import LoggerFactory
import org.eclipse.smarthome.core.thing.link.ItemChannelLinkRegistry
import org.eclipse.smarthome.core.thing.ChannelUID
import java.util
scriptExtension.importPreset("RuleSupport")
scriptExtension.importPreset("RuleSimple")

class ItemChannelFinder(SimpleRule):
    def __init__(self):
		self.triggers = [
            TriggerBuilder.create()
                    .withId("ItemAddedTrigger")
                    .withTypeUID("core.GenericEventTrigger")
                    .withConfiguration(
                        Configuration({
                            "eventTopic": "smarthome/*",
							"eventSource": "",
							"eventTypes": "ItemAddedEvent"
                        })).build()
        ]
		self.name = "Jython find Channel for created items"
		self.description = "This rule is triggered on every new Item creation. If its Channel..."
		self.log = LoggerFactory.getLogger("jsr223.jython.BTItemFinder")
		self.reg = org.eclipse.smarthome.core.thing.link.ItemChannelLinkRegistry()
    def execute(self, module, input):
		test = self.reg.getBoundChannels("CC2650SensorTag_Authenticated").toArray()
		self.log.info(str(input["event"]))
		for channeluuids in test:
			self.log.info(str(channeluuids.getId()))

automationManager.addRule(ItemChannelFinder())

getBoundChannels sadly doesn’t seem to return anything

ItemChannelLinkRegistry is registered as an OSGi service. To get to it, I suggest using the helper libraries. Here’s something from my test scripts, which provides the Links for a particular Item…

from core import osgi
from core.log import logging, LOG_PREFIX, log_traceback
log = logging.getLogger("{}.TEST".format(LOG_PREFIX))
from org.eclipse.smarthome.core.thing import ChannelUID

my_item_name = "DS_FamilyRoom_Ceiling_Motion"

ItemChannelLinkRegistry = osgi.get_service("org.eclipse.smarthome.core.thing.link.ItemChannelLinkRegistry")
channels = ItemChannelLinkRegistry.getBoundChannels(my_item_name)
log.warn("Thing Channels [{}]".format(channels))
from org.eclipse.smarthome.core.thing.link import ItemChannelLink
links = map(lambda channel: ItemChannelLink(my_item_name, channel), channels)
log.warn("Links [{}]".format(links))
2019-08-01 13:40:31.215 [WARN ] [jsr223.jython.TEST] - Thing Channels [[zwave:device:55555:node5:sensor_binary]]
2019-08-01 13:40:31.216 [WARN ] [jsr223.jython.TEST] - Links [[DS_FamilyRoom_Ceiling_Motion -> zwave:device:55555:node5:sensor_binary]]

Here’s some other stuff I found in there…

log.warn("getBoundChannels=[{}]".format(ItemChannelLinkRegistry.getBoundChannels(my_item_name)))
log.warn("ChannelUID=[{}]".format(list(ItemChannelLinkRegistry.getBoundChannels(my_item_name))[0]))
log.warn("ThingUID=[{}]".format(list(ItemChannelLinkRegistry.getBoundChannels(my_item_name))[0].getThingUID()))
log.warn("statusInfo=[{}]".format(things.get(list(ItemChannelLinkRegistry.getBoundChannels(my_item_name))[0].getThingUID()).statusInfo))
log.warn("location=[{}]".format(things.get(list(ItemChannelLinkRegistry.getBoundChannels(my_item_name))[0].getThingUID()).location))
log.warn("getBoundThings=[{}]".format(ItemChannelLinkRegistry.getBoundThings(my_item_name)))
log.warn("ThingUID=[{}]".format(list(ItemChannelLinkRegistry.getBoundThings(my_item_name))[0].UID))
log.warn("Item from ChannelUID=[{}]".format(list(ItemChannelLinkRegistry.getLinkedItemNames(list(ItemChannelLinkRegistry.getBoundChannels(my_item_name))[0]))[0]))
1 Like