Can I get the Thing UID that is linked with an Item

Is it possible to get the Thing UID that is linked with an Item(s)? i.e. given a Item, I want to find the corresponding Thing so that I can get its status (programmatically).

Probably not. The challenges there are:

  • an Item can have between 0 and N links to a Channel on it, which one do you want?
  • the links are actually separate entities and are not actually a part of the Item itself

So it’s not going to be straight forward, if possible at all.

There is a links.py which shows how to add and remove Links from an Item. Looking through the JavaDoc for ManagedItemChannelLinkProvider shows it inherits a getAll method. So calling that will probably return a Set<ItemChannelLink> and ItemChannelLink has a getItemName method and getLinkedUID method. So you can search through all the Links until you find the one(s) matching your Item name. Then you can look at the LinkedUID. But the code implies that more than just Channels can be linked to an Item (e.g. metadata perhaps). So you’ll need to do some more processing to identify the ones that are for a Thing.

1 Like

Thanks Rich … I’ll let you know if I can make it work (for my limited case).

Note that last paragraph was written the way it was with a purpose. I basically narrated how I answered your question so you (and future readers) can see how to answer similar questions themselves.

  1. Look to see if the Helper Libraries already implements something like this.
  2. If it implements exactly what you want you are done. Just use the Helper Libraries or copy that code. If not…
  3. Look at the JavaDocs for the relevant openHAB Classes involved to see if there is a way to do what you are after.
2 Likes

For anyone else that wants to try this, here is code that can be placed in your library that implements a get_thing() function … major limitation: it only returns the first, if any, Thing UID that is associated with an Item also might not work for all Thing binding types

"""
This module allows discovery of first Thing UID for given Item.
"""

try:
    import typing as t
    if t.TYPE_CHECKING:
        try:
            from org.openhab.core.thing.link import ItemChannelLinkRegistry, ManagedItemChannelLinkProvider
        except:
            from org.eclipse.smarthome.core.thing.link import ItemChannelLinkRegistry, ManagedItemChannelLinkProvider
except:
    pass

from core import osgi
from core.log import getLogger
from core.utils import validate_item   #, validate_channel_uid

ITEM_CHANNEL_LINK_REGISTRY = osgi.get_service(
        "org.openhab.core.thing.link.ItemChannelLinkRegistry"
    ) or osgi.get_service(
        "org.eclipse.smarthome.core.thing.link.ItemChannelLinkRegistry"
    ) # type: ItemChannelLinkRegistry

LOG = getLogger(u"get_thing")

def get_thing(item_or_item_name):
    """
    This function returns the first Thing UID from an Item using a
    ManagedItemChannelLinkProvider.

    Args:
        item_or_item_name (Item or str): the Item object or name to create
            the Link for

    Returns:
        Thing or None: the Thing UID or None
    """
    try:
        item = validate_item(item_or_item_name)
        if item is None:
            return None

        things = ITEM_CHANNEL_LINK_REGISTRY.getBoundChannels(item.name)
        if len(things) > 0:
            Thing,Channel = str(things.pop()).rsplit(":",1)
            return Thing
        else:
            return None
    except:
        import traceback
        LOG.warn(traceback.format_exc())
        return None


And here is what I used to test it:

import personal.get_thing
reload(personal.get_thing)
from personal.get_thing import get_thing

from org.openhab.core.thing import ThingUID

from org.slf4j import LoggerFactory
from configuration import LOG_PREFIX
log = LoggerFactory.getLogger("{}.test_get_thing".format(LOG_PREFIX))

def test_getthing(item):
    thing = get_thing(item)
    if (thing != None):
        log.info("Thing for item: " + item + " is: " + thing)
        log.info("Status for Thing is: " + str(things.get(ThingUID(thing)).status))
    else:
        log.info("No Thing found for item: " + item)

This is all core openHAB stuff so it should work with all bindings.

That getBoundChannels method is a good find. However, I notice there is a getBoundThings(item.name)? With that you wouldn’t need to do the string manipulation to get the ThingUID which could be brittle for some bindings if they use an unexpected patter or OH decides to change the formatting of the IDs or the like.

    if len(things) > 0:
        return things.pop().getUID().getId()

Note: the order in a Set is not defined so you are not guaranteed to always get the same Thing every time you call pop if there is more than one Thing linked to the Item.

To return all the UIDs as a list using this approach…

   return [ t.getUID().getId() for t in things ]

It would not be too much I think to return a list of all the Thing IDs for those who want that.

1 Like

much better … mine is a ‘bit’ of a hack :slight_smile:

Yes, good to point that out! I am still not clear of when you want more than one Thing linked to an Item, but I’ve got a lot to learn!

You might for example have separate channels, even different bindings, for “in” and “out”. Or a pair of devices “slaved” to a single Item.

1 Like