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 ?
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.
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."""
...
@property
def ieee(self):
"""Return ieee address for device."""
return self._zigpy_device.ieee
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
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!
I was playing with this, I just wanted to share a slightly improved version of it:
"{{ device_attr('light.room3', 'identifiers') | selectattr(0,'eq','zha') | map(attribute=1) | first }}"
This is more resilient in that if in a future version of ZHA the identifiers attributes (which is an array) returns more than one ID, this will select the one that contains the IEEE, whichever order they’re in.
Also, if someone’s got a progammatical way to get the endpoint_id I’d be game (I’m trying to use zha.issue_zigbee_cluster_command in a blueprint, and trying to see if I can avoid asking for the endpoint id in an input)! Although it seems to always be 1 or 11?
zha-toolkit actually determines the endpoint by matching the cluster_id to the available clusters.
That works if only one endpoint has the cluster id.
As you are trying to send a command, you need zha_toolkit.zcl_cmd. The documentation still show examples using zha_toolkit.execute, but you can use use the zcl_cmd service instead which is more convenient.
The endpoint is an optional parameter, while the cluster is mandatory.