Best way to get ZHA device ieee address?


There is currently no direct way to use the zigbee timed switch feature (aka timed_with_on_off) on a Zigbee device. For the curious, this is a more secure way to turn on then turn off a device when you want to be sure that the device will be turned off after a amount of time despite an hass restart/crash/murphy law/etc. For example, you want to be sure your water/gaz valve will be turned off and not flood your neighborhood.

To workaround that I issue a zha.issue_zigbee_cluster_command directly to the device which requires the ieee address of the device.
This service doesn’t accept target or entity args and unfortunately device_attr("light.room3", "ieee") does not work.

Currently to extract the device ieee I use {{ (device_attr("light.room3", "identifiers")|list).0.1 }}. Is this the best way to get the ieee attribute or to match a device with zha.issue_zigbee_cluster_command ?

Here is a complete example:

service: zha.issue_zigbee_cluster_command
  ieee: '{{ (device_attr("light.room3", "identifiers")|list).0.1 }}'
  endpoint_id: 11
  cluster_id: 6
  cluster_type: in
  command: 66
  command_type: server
    - 0
    - 70
    - 0
1 Like

Examining the code that sets up the templating mechanism, we can see that not that many things are exposed:

So this seems to be close to the best approach. I think that one could verify that the first item in the list item is ‘zha’, and a more general implementation would be to go through the list to find the item where the first value is ‘zha’. But I guess that in this case you kind of know what you are talking to and it does not have to be fool-proof.

What I don’t understand is why device_attr(device_id, “ieee”) does not return the ieee address.

The device_attr function is:

def device_attr(hass: HomeAssistant, device_or_entity_id: str, attr_name: str) -> Any:
    """Get the device specific attribute."""
    device_reg = device_registry.async_get(hass)
    if not isinstance(device_or_entity_id, str):
        raise TemplateError("Must provide a device or entity ID")
    device = None
    if (
        "." in device_or_entity_id
        and (_device_id := device_id(hass, device_or_entity_id)) is not None
        device = device_reg.async_get(_device_id)
    elif "." not in device_or_entity_id:
        device = device_reg.async_get(device_or_entity_id)
    if device is None or not hasattr(device, attr_name):
        return None
    return getattr(device, attr_name) 

It basically returns getattr(device, attr_name) after finding the device object and a ZHA Device has this attribute:

class ZHADevice(LogMixin):
    """ZHA Zigbee device object."""
    def ieee(self):
        """Return ieee address for device."""

And getattr() on a property should works in python.

$ ipython
In [1]: class Toto:
…: @property
…: def foo(self):
…: return 42
In [2]: getattr(Toto(), “foo”)
Out[2]: 42

I think a ZHADeivce is not the same as a HA device.

I found this code suggesting that you’re doing it the same way ZHA is doing it:

FYI: I revisited this thread to check the method to get the IEEE of a device.

I added an implementation accepting entity_names and short network addrssses to zha_custom.

That will also allow you to do what you wanted as I added the functionnality to send Cluster commands. But apparently that also exists in ZHA (I just (re)discovered that here).


Is there something similar in ZHA-toolkit for endpoints? I’ve been working on a Blueprint that uses ZHA-toolkit, and I’d love to be able to only need the entity-ID as an input. Thanks!

Edit: Sorry. I just read the documentation and saw that it’s optional. It’s working really well. Thank you!