I was looking for a simple way to show all the devices that were disconnected from the Zigbee network, but I couldn’t find any solution that I liked.
Most of the solutions I found listed the disconnected entities, but not the disconnected devices. Since a device can have multiple entities, the generated listings contained many duplicates.
After many hours of testing, I got a working solution with the following code:
type: custom:auto-entities
card:
type: entities
unique: false
filter:
template: |
{% set data = namespace(numbers=[]) %}
{%- for da in expand(integration_entities('zha') ) |selectattr( 'state',
'eq', 'unavailable') | list -%}
{% set data.numbers = data.numbers + [device_entities(device_attr(da.entity_id, 'id')) | first] %}
{%- endfor -%}
[
{%- for filt in data.numbers | unique -%}
{{ {"name": device_attr(filt, 'name_by_user'), "secondary": device_attr(filt, 'name'), "state": "", "icon": "mdi:devices", "type": "custom:template-entity-row" } }}
,
{%- endfor -%}
]
else:
type: markdown
content: Ninguno
You will need to first install the cards “Auto Entities” and “Template Entity Row”.
I use the auto-entities vard for this. Copied the setup from some other post here on the formum and edited it for my need. So I do not take any credit for the code.
Old thread, but for those who want to retrieve ZHA devices programmatically. Here a pyscript solution:
The ZHA card retrieves all ZHA info via a web socket call, using this command: {"type": "zha/devices"}
This code can be used for that:
# All credits how to use websockets to retrieve the lovelace configuration goes to https://github.com/qui3xote:
# https://github.com/custom-components/pyscript/discussions/272#discussioncomment-1709728
import json
import websockets
async def websocket_command(command: dict, url=None, token=None):
""" returns json result as python data """
if token==None and 'token' in pyscript.config['global']:
token = pyscript.config['global']['token']
if url==None:
url = 'ws://127.0.0.1:8123/api/websocket'
# ids are returned in the receive phase so you tie back to originating command.
# The API has feelings about these: they must increment, at least per session
websocket_command.counter += 1
command['id'] = websocket_command.counter
async with websockets.connect(url) as websocket:
log.info(websocket.recv()) #first receive will give you HA version, if it matters
await websocket.send(json.dumps({"type": "auth", "access_token": token})) #send auth
log.info(websocket.recv()) #once ok is received we go into command phase
await websocket.send(json.dumps(command))
result = websocket.recv()
log.info(result)
return json.loads(result)
websocket_command.counter = 0
@service(supports_response="only")
def zha_devices(available=None, device_type=None, area_id=None, short=True):
"""yaml
description: Lookup ZHA devices, Optionally filter
fields:
available:
description: optional filter on available true or false
example: true
selector:
boolean:
device_type:
description: optional filter on a particular device_type
example: Router
selector:
select:
options:
- Router
- EndDevice
- Coordinator
multiple: false
area_id:
description: optional filter on a particular area
example: Living
selector:
text:
short:
description: return summary or full device info
example: true
selector:
boolean:
"""
command={"type": "zha/devices"}
response = websocket_command(command)
if 'result' in response and response['success']:
devices=[]
for device in response['result']:
if ((available is None or available == device['available']) and
(device_type is None or device_type==device['device_type']) and
(area_id is None or area_id==device['area_id']) ):
name = device['user_given_name'] if device['user_given_name'] else device['name']
if short and device_type is None and area_id is None:
devices.append({"name":name, "area_id": device['area_id'],"device_type": device['device_type'],"last_seen":device['last_seen']})
elif short and device_type is None:
devices.append({"name":name, "device_type": device['device_type'],"last_seen":device['last_seen']})
elif short and area_id is None:
devices.append({"name":name, "area_id": device['area_id'],"last_seen":device['last_seen']})
elif short:
devices.append({"name":name,"last_seen":device['last_seen']})
else:
devices.append(device)
return {"result": True,"total_devices":len(response['result']),"returned": len(devices),"devices":devices }
return {"result": False }
The script can be called without arguments (all parameters are optional). It allows to filter on a combination of available, device_type and area_id. Example: