Devices and Areas

So, I was looking to report on all devices in an area. This led me to looking for a list of areas and devices. Then, listing of devices not in an area.

I am not sure all of this is in one place. So, I thought I’d post it here.

All of these are using tables in Markdown Cards. But, could certainly be used in other ways. You can decide your best method to use them.

They are all setup to sort by area/device name entered by user (or name if not entered) or device name entered by user (or name if not entered)/area depending on the layout.

First, all areas and a list of devices in that area:

|Area|Devices
|:---|---:
{%- set ns = namespace(areas = [], devices=[], area_name = '') -%}
{%- for area in areas() | sort %}
  {%- set ns.area_name = area_name(area) -%}
  {%- set ns.devices = [] -%}
  {%- for device in area_devices(area) %}
    {%- set ns.devices = ns.devices + [{'device_name': device_attr(device, 'name_by_user') if device_attr(device, 'name_by_user') != none else device_attr(device, 'name')}] -%}
  {%- endfor %}
  {%- set ns.areas = ns.areas + [{'area_name': area_name(area),
                                  'devices': ns.devices}] -%}
{%- endfor -%}
{%- for area in ns.areas | sort(attribute='area_name') -%}
  {%- if area.devices | length == 0 %}
| {{ area.area_name }} | None
  {%- else -%}
    {%- set ns.area_name = area.area_name -%}
    {%- for device in area.devices | sort(attribute='device_name') %}
| {{ ns.area_name }} | {{ device.device_name }}
      {%- set ns.area_name = '' -%}
    {%- endfor -%}
  {%- endif -%}
{%- endfor -%}

This shows:
image

Second is a list of devices and the areas they are in.

|Device|Area
|:---|:---
{%- set ns = namespace(devices = []) -%}
{%- for entity in states | map(attribute='entity_id') %}
  {%- if device_id(entity) %}
    {%- set ns.devices = ns.devices + [{'id': device_id(entity),
                                        'name': device_attr(entity, 'name_by_user') if device_attr(entity, 'name_by_user') != none else device_attr(entity, 'name'),
                                        'area': area_name(device_attr(entity, 'area_id'))}] -%}
  {%- endif -%}
{%- endfor -%}
{%- for device in ns.devices | unique(attribute='id') | sort(attribute='name') %}
  | {{ device.name }} | {{ device.area }}
{%- endfor -%}

This shows:

Finally, a list of devices NOT in an area.

|Device|Area
|:---|:---
{%- set ns = namespace(devices = []) -%}
{%- for entity in states | map(attribute='entity_id') %}
  {%- if device_id(entity) %}
    {%- set ns.devices = ns.devices + [{'id': device_id(entity),
                                      'name': device_attr(entity, 'name_by_user') if device_attr(entity, 'name_by_user') != none else device_attr(entity, 'name'),
                                      'area': area_name(device_attr(entity, 'area_id'))}] -%}
  {%- endif -%}
{%- endfor -%}
{%- for device in ns.devices | selectattr('area', 'eq', none) | unique(attribute='id') | sort(attribute='name') %}
  | {{ device.name }} | {{ device.area }}
{%- endfor -%}

This shows:
image

I think I have provided all of what I is needed. Please let me know if something is wrong or can be optimised.

1 Like

Thank you for this, I was looking for a quick way to see all my un-zoned devices and to quickly work through putting them into areas. I’ve modified your last script, adding a column which links to the device config page:

|Device|Area|Link|
|:---|:---|:---
{%- set ns = namespace(devices = []) -%}
{%- for entity in states | map(attribute='entity_id') %}
  {%- if device_id(entity) %}
    {%- set ns.devices = ns.devices + [{'id': device_id(entity),
                                      'name': device_attr(entity, 'name_by_user') if device_attr(entity, 'name_by_user') != none else device_attr(entity, 'name'),
                                      'area': area_name(device_attr(entity, 'area_id'))}] -%}
  {%- endif -%}
{%- endfor -%}
{%- for device in ns.devices | selectattr('area', 'eq', none) | unique(attribute='id') | sort(attribute='name') %}
  | {{ device.name }} | {{ device.area }} | [Link](http://<HOME ASSISTANT DOMAIN>/config/devices/device/{{device.id}})
{%- endfor -%}

Which results in a card like this

I’m sure there’s a way to do it automatically via the template but I CBA since I have a static domain myself but to use replace <HOME ASSISTANT DOMAIN> with your home assistant domain. For example, mine is homeassistant.local for the purposes of this widget.

For future reference, there’s a shorter way to produce a Markdown table of devices without an assigned area.

|Device|Area|Link|
|:---|:---|:---
{% set l = '[Link](http://<HOME ASSISTANT DOMAIN>/config/devices/device/{})' -%}
{%- set ns = namespace(devices = []) -%}
{% for d in states | map(attribute='entity_id') | map('device_id') | reject('none') | unique if area_name(d) is none -%}
{% set ns.devices = ns.devices + [['| ' ~ device_attr(d, 'name_by_user')|default(device_attr(d, 'name'), true), area_name(d), l.format(d)]] -%}
{% endfor -%}
{{ ns.devices | sort(attribute=0) | map('join', ' | ') | join(' |\n')  }}

Settings → System → Network → Host name contains the machine’s hostname. However, to my knowledge, that information is not stored anywhere accessible to a template function like states() or state_attr(), nor is it part of any device’s properties, so it’s inaccessible to templates.


Bonus

Version that lists devices assigned an area.

|Device|Area
|:---|:---
{%- set ns = namespace(devices = []) %}
{% for d in states | map(attribute='entity_id') | map('device_id') | reject('none') | unique -%}
{% set ns.devices = ns.devices + [['| ' ~ device_attr(d, 'name_by_user')|default(device_attr(d, 'name'), true), area_name(d)]] -%}
{% endfor -%}
{{ ns.devices | sort(attribute=0) | map('join', ' | ') | join(' |\n')  }}
1 Like