This works but the resulting list is a list of entities, not devices (because it’s entities that can be unavailable). That’s fine, because I can then iterate over the resulting list, and display the output grouped by device:
{%- set ns = namespace(device_id='') -%}
{%- for entity_id in entity_ids -%}
{%- if ns.device_id != device_id(entity_id) -%}
{%- if ns.device_id != '' %}
{% endif -%}
**[{{ device_attr(entity_id, "name_by_user") or device_attr(entity_id, "name") }}](/config/devices/device/{{ device_id(entity_id) }}) in {{area_name(entity_id)}}**
{%- set ns.device_id = device_id(entity_id) %}
{%- endif %}
- {{ state_attr(entity_id, 'friendly_name') }}
{%- endfor -%}
However, because the list does not group entities belonging to the same device together, I end up with the same device sometimes listed several times, with different entities in each entry. How can I sort the initial list so that entities belonging to the same device are consecutive? Or otherwise how should I do this?
I initially went down the same path as you, but then found a lot of unavailable entities I didn’t really care about (eg. Christmas lights that are in the cupboard most of the year). So I created a “monitor-availability” label and then attached that label to everything I wanted to monitor. Since I only attached it to one entity per device, the problem you mentioned goes away.
Similarly I have labels for “monitor-low-percent” (eg. batteries) and “monitor-high-percent” (eg. disk space).
{% set entity_ids = states
| rejectattr('domain','in',['stt','tts','conversation','select','number', 'event','group','input_button','input_text','scene'])
| rejectattr('attributes.device_class', 'in', ['update', 'restart', 'identify', 'wled__live_override', 'firmware'])
| selectattr('state', 'in', ['unavailable', 'unknown'])
| map(attribute='entity_id')
| select("ne", None)
| map("string")
| unique
| list
%}
{% set device_ids = entity_ids
| map("device_id")
| select("ne", None)
| unique
| list
%}
{%- for d_id in device_ids -%}
**[{{ device_attr(d_id, "name_by_user") or device_attr(d_id, "name") }}](/config/devices/device/{{ d_id }}) in {{area_name(d_id)}}**
{%- for e in device_entities(d_id) | select('in', entity_ids) %}
- {{ state_attr(e, 'friendly_name') }} <span style='color: grey'>is {{ states(e) }}</span>
{%- endfor %}
{% endfor %}
This actually feels a bit more straightforward than what I had before, and the output in the template debugger is perfect, but it just produces blank output when I put it in a markdown dashboard card . Do markdown cards only support limited templates? It’s a bit weird.
The problem was that for some reason, in the Markdown card, it was struggling to do the rejectattr('attributes.device_class', 'in'... filter because the list clearly contained some objects that didn’t have a device class attribute. So I added a selectattr('attributes.device_class', 'defined') filter before that, and now it works great.