OpenHAB3 / Thing Status / How to extract the thing status and work with it on items

Hi,

I am new to OpenHAB and started to work with version 3.

I struggle with a few things and unfortunately I am a bit confused on which instructions still work for OH3 and which don’t. I’ll post separate questions for each of my problems.

This question is about the Thing Status.

Problem / Goal:

While the thing status is very prominently exposed on the thing itself I cannot find anything similar on the items. All UIs however only seem to work with items.
Therefore, I want to see at first glance when taking a look at an arbitrary item whether the underlying thing is still working correctly or not.

I am looking for a generic way which works for all things / items independently from their binding.

Ideally, I could configure this once and it works for all the items.

What I tried so far:

The thing’s UID is shelly:shellyrgbw2-color:light

  • Work with the “Developer Sidebar / Code Tools / Widget Expression Tester” to try to extract the current value of the thing. I tried expressions like
    • =things.shelly:shellyrgbw2-color:light.state
      failing with Error: Unexpected “:” at character 13
    • =ThingAction.getThingStatusInfo("shelly:shellyrgbw2-color:light").getStatus()
      failing with Error: Expected comma at character 38
  • Created a dummy item so that this could be updated via a rule
    • The item’s Name is i_led_health.
      Sorry I have absolutely no idea how to access the item’s code otherwise I would have posted it.
    • Rule:
triggers:
  - id: "1"
    configuration:
      thingUID: shelly:shellyrgbw2-color:light
    type: core.ThingStatusChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      itemName: i_led_health
      state: =shelly:shellyrgbw2-color:light.state
    type: core.ItemStateUpdateAction

Posts I read so far (seems I am only allowed to post 2 links):


Platform information:

  • OS: ArchLinux
  • openHAB version: 3.0.0-2

Here’s the problem. Which underlying Thing? It is not unusual to have multiple Channels from multiple Things linked to the same Item. What about Items that are not linked to any Channels?

The approaches you’ve already linked to show pretty much what is possible on the Things.

However, you probably don’t care about the status of the Thing, you care about the status of the Device. And getting at that is going to differ based on the technology the device uses. For example, some bindings will set Items to UNDEF when the bridge Thing goes OFFLINE which makes detecting those problems super easy. Others frequently update Items on a set polling period and you can use the Expire binding to set those to UNDEF if two or three polling periods are missed. Still others, like MQTT, offer a Channel that will directly tell you whether or not the other device is online or not. You can use another binding to monitor a device, for example the network binding can tell you if a device falls off the network.

tl;dr: There is no generic way to do this. You might be able to do something sort of generic by querying the REST API and parsing the JSON periodically. Beyond that you need to list each Thing separately as a trigger on a Rule or detect the online/offline status through other means.

I am also interested in thing status and tried multiple code examples but all failed at least in ECMA.
In OH2.5 and 3 DSL rules you could get for instance the thing/binding status by using var thingStatusInfo = getThingStatusInfo("mqtt:broker:mosquitto") and it shows you if i.e. the mqtt binding is online/offline, whereas it seems this code is not working in ECMA scripts.
Did not find a solution to it yet.

Due to a friend found this code that worked to get thing status (example mqtt):

var Things = Java.type(“org.openhab.core.model.script.actions.Things”);
var status = Things.getThingStatusInfo(“mqtt:broker:mosquitto”);

1 Like

Right now I have only exactly one thing (sometimes several channels) linked to an item.
However, I’d be interested in an example where it would make sense to e.g. link several things to a single item.

For those I am not interested in the thing’s status :wink:

Sorry for being unclear but none of those approaches actually worked. I am still looking for a solution.

Maybe some more details on my end.
I am currently solely working with Shelly devices and the thing’s state is not propagated to any channel.
So if for example if I loose the WiFi connection of the Shelly device and the last value of a “switch” was “ON” it will stay that way. So far so good. But if I toggle to “OFF” on the UI it will just take the value w/o any error, wrongfully updates the state of the item and the real thing would still remain in state “ON”.

So the problems are

  • that connection errors are silently swallowed and
  • that the state represenation on the UI and in the real world may break due to that w/o me noticing (except I am near the affected device).

This sounds promising. Could you maybe point me to more information on that topic?

How to you execute this?
I tried with ECMAScript and Rule DSL but none worked.

My example rule below:

var telegramAction = actions.get("telegram","telegram:telegramBot:telegram");
var Things = Java.type("org.openhab.core.model.script.actions.Things");
var status = Things.getThingStatusInfo("networkupstools:ups:ups");

//Actions

if (status == "ONLINE") {
  telegramAction.sendTelegram("NUT " + status)
  events.postUpdate("watchdog_binding_nut", "ONLINE")
} 
if (status != "ONLINE") {
  telegramAction.sendTelegram("NUT " + status)
  events.postUpdate("watchdog_binding_nut", "OFFLINE")
}

This checks if the binding/thing is online/offline with the when trigger being networkupstools:ups:ups changed and/or the system reached start level 100.

1 Like

Look at the Follow Profile Items | openHAB for one example.

So why not just use the Network binding to ping it and if it goes offline you’ll have a nice switch to tell you that it’s offline.

If you are using MQTT integration, you could subscribe to the LWT topic and let the MQTT broker tell you when the devices go offline. You could also configure the MQTT Thing itself to subscribe to the LWT topic and set everything to UNDEF when it goes offline.

Ultimately, this is very much an XY Problem I think. As I said, you want the online status of the end device, not the Thing. Focusing on getting the Thing status doesn’t really solve the real problem for you in a reasonable fasion.

But if you insist of using the Thing status, as is talked about in those threads your choices are:

  • run a rule to query and parse the JSON from the REST API to get the Thing status for all your Things periodically, you might be able to get access to Things more directly in JavaScript/Python/Rules DSL without going through the API
  • trigger a rule when Things change their status to OFFLINE, but you need to manually add each Thing as a separate trigger to the rule

These approaches both actually do work and many users do use them. And there are clever tricks one can do to make it even more flexible, for example dynamically creating the rule with all the triggers based on the query for all Things.

It seems there is a way:

However, I couldn’t get this example to work for OH3 yet.

Yes, I know that I could work with such things.

But the thing is that the information of the “things’ statuses” is already there (I have a nice overview when I look at the “Administration >> Settings >> Things” ) and (if possible) I just want to work with that.

In my case the thing is equal to the actual device. So I am very much fine with getting the thing’s status. If the thing’s status is weird / unexpected, I need to take a (personal) look at the device eventually anyways.

This might be a way to go.

I’d rather don’t wanna do that. If possible I “just” want to set OH up and once I add new things, items etc. most of the other “stuff” is just there already.

This sounds very interesting!
Could you maybe point me to some examples or more information on that?

That’s frequently not the case.

I’ve only a Python version.

Hey together,

it is possible to operate on Things if you really want to do that. You need a way to get a reference of ThingRegistry or ItemChannelLinkRegistry. Since the implementation of ThingRegistry is internal you can’t create your own. But both implementations are Services inside the framework and you can use OSGI to get a reference.

The Python Helper Libraries offers a function for that:
core.osgi.get_service(class_or_name)

I don’t know if the helper Libraries are working for OH3.
Here is a working JS-example on how to get the required services inside a rule created with the UI.

// Set this variable to a valid item name!
demoItemName = "LR_Window_State"

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.GeneralTestRule');

// Want reference for
var ItemChannelLinkRegistry = Java.type('org.openhab.core.thing.link.ItemChannelLinkRegistry');
var ThingRegistry = Java.type('org.openhab.core.thing.ThingRegistry')

// OSGI
var Bundle = Java.type('org.osgi.framework.Bundle')
var FrameworkUtil = Java.type('org.osgi.framework.FrameworkUtil')

// Since ItemChannelLinkRegistry & ThingRegistry are in the same bundle we can use either of them
var thingBundle = FrameworkUtil.getBundle(ItemChannelLinkRegistry.class)
var bundleContext = thingBundle.getBundleContext()

// Get Service
var thingRegistryRef = bundleContext.getServiceReference(ThingRegistry.class)
var thingRegistryImpl = bundleContext.getService(thingRegistryRef)

// Get Service
var itemChannelLinkRegistryRef = bundleContext.getServiceReference(ItemChannelLinkRegistry.class)
var itemChannelLinkRegistryImpl = bundleContext.getService(itemChannelLinkRegistryRef) // Instance of ItemChannelLinkRegistry

// To compare Thing status
var ThingStatus = Java.type('org.openhab.core.thing.ThingStatus')

// Get all Things
// https://github.com/openhab/openhab-core/blob/master/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/Thing.java
// https://github.com/openhab/openhab-core/blob/master/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/ThingRegistry.java
// https://github.com/openhab/openhab-core/blob/master/bundles/org.openhab.core/src/main/java/org/openhab/core/common/registry/Registry.java
thingRegistryImpl.getAll().forEach(function(thing){
    if(thing.getStatus() !== ThingStatus.ONLINE) {
      logger.info("Thing with label" + thing.getLabel() + " is " + thing.getStatus())
    }
})

// Get linked Things from given Item via ItemChannelLinkRegistry
// https://github.com/openhab/openhab-core/blob/master/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/link/ItemChannelLinkRegistry.java
// https://github.com/openhab/openhab-core/blob/master/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/link/AbstractLinkRegistry.java
itemChannelLinkRegistryImpl.getBoundThings(demoItemName).forEach(function(thing){
  logger.info("Thing " + thing.getLabel() + " with UID " + thing.getUID() + " is " + thing.getStatus())
})
2 Likes

Awesome!
Just tried this script. It works.
Thank you!

1 Like

There is a PR for Python. I don’t know about JavaScript.

UPDATE: Original solution didn’t work on openhab 3.5, so I’m posting a new solution.

JSR223 Zwave Controller Status (OpenHab 3.5):

from core.actions import Things
# in string format
zwave_status = str(Things.getThingStatusInfo('zwave:serial_zstick:abcd123'));

JSR223 Zwave Controller Status (OpenHab 2.5):

from org.eclipse.smarthome.core.thing import ThingUID
...
thing_status = things.get(ThingUID('zwave:serial_zstick:abcd123')).status

OR for comparison:

zwave_status = str(things.get(ThingUID('zwave:serial_zstick:abcd123')).status)
if zwave_status == "OFFLINE":
...

Dox: