c0ntax
(Martin)
May 25, 2023, 6:34am
1
I am after some help with creating a template that outputs a list of states in a markdown card.
The attributes are device_class: battery
and state_class: measurement
. The output will be device name and state.
I have checked the Templating Documentation but can’t find an answer for what I’m looking for.
For context, this request is specifically for battery levels but I would want to re-use the template for other states.
This should get you going.
I annotate my batteries like this in customize.yaml
:
sensor.pieter_bedside_light_button_battery:
friendly_name: Pieter's Bedside Light Button Battery
# https://community.home-assistant.io/t/recommended-ways-to-manage-devices-and-entities-names/243815/12
monitor: True
I then use these automations. The message templates would work in a markdown card too:
- alias: "Check For Low Batteries"
initial_state: true
variables:
level: 5
# https://community.home-assistant.io/t/variable-in-automation-not-working-as-expected/431591/2
monitored_batteries: >-
{{
states.sensor
| selectattr('attributes.monitor', 'defined')
| selectattr('attributes.monitor', 'eq', True)
| rejectattr('state', 'in', ['unavailable', 'unknown', 'none'])
| selectattr('attributes.device_class', 'eq', 'battery')
| map(attribute='entity_id')
| list
}}
trigger:
platform: time
at: "09:00:00"
condition: >-
{{
expand(monitored_batteries)
| map(attribute='state')
| map('int')
| select('lt', level)
| list
| count
> 0
}}
action:
- service: notify.mobile_app_ceres
data:
# icon: https://companion.home-assistant.io/docs/notifications/notifications-basic/#notification-icon
# https://companion.home-assistant.io/docs/notifications/actionable-notifications/#icon-values
title: "Batteries"
# https://community.home-assistant.io/t/recommended-ways-to-manage-devices-and-entities-names/243815/12
message: >
The following devices have less than {{ level }}% charge:
{%- for b in monitored_batteries %}
{%- if states(b) | int < level and not is_state(b, 'unavailable') %}
- {{ state_attr(b, 'friendly_name') | replace(' Battery', '') }}: {{ states(b) | int }}%
{%- endif -%}
{%- endfor %}
data:
group: "batteries"
url: homeassistant://navigate/lovelace/devices
# https://community.home-assistant.io/t/why-isnt-there-a-groups-entities-state-trigger/467179
# https://community.home-assistant.io/t/unleash-the-power-of-expand-for-template-sensors/136941/22
# https://community.home-assistant.io/t/trigger-an-automation-based-on-a-groups-individual-entity-state-change/383560
# https://community.home-assistant.io/t/single-automation-for-all-lights/375028/8
- alias: "Check For Flat Batteries"
initial_state: true
variables:
level: 0
monitored_batteries: >-
{{
states.sensor
| selectattr('attributes.monitor', 'defined')
| selectattr('attributes.monitor', 'eq', True)
| rejectattr('state', 'in', ['unavailable', 'unknown', 'none'])
| selectattr('attributes.device_class', 'eq', 'battery')
| map(attribute='entity_id')
| list
}}
trigger:
- platform: state
entity_id: sensor.number_of_flat_batteries
condition: >-
{{
expand(monitored_batteries)
| map(attribute='state')
| map('int')
| select('eq', level)
| list
| count
> 0
}}
action:
- service: notify.mobile_app_ceres
data:
title: "Batteries"
message: >
The following devices have no charge:
{%- for b in monitored_batteries %}
{%- if states(b) | int == level and not is_state(b, 'unavailable') %}
- {{ state_attr(b, 'friendly_name') | replace(' Battery', '') }}
{%- endif -%}
{%- endfor %}
data:
group: "batteries"
url: homeassistant://navigate/lovelace/devices
c0ntax
(Martin)
May 25, 2023, 7:19pm
3
Thank you for the examples. I’ve actually come up with the below which is only returning ‘Undefined’ for each device and I can’t figure out why.
{{ states.sensor
| selectattr('attributes.device_class', 'defined')
| selectattr('attributes.device_class', 'eq', 'battery')
| map(attribute='state')
| reject('in', ['unknown', 'unavailable'])
| map('int', -1) | select('le', 40)
| select('ge', 0)
| map(attribute='name') | list
}}
Work backwords (i.e. remove filters) until you get something.
Your issue is that you have multiple map filters. After the first map, you will have a list of states only. You don’t have the objects anymore. This means, your reject filter will still work, etc., but the last map won’t. Keep operating on the original objects and then the last map will work. Basically, don’t perform the first two maps and rather use rejectattr
instead of reject
.
c0ntax
(Martin)
May 25, 2023, 8:14pm
5
I’ve arrived at the below and now it returns nothing:
{{ states.sensor
| selectattr('attributes.device_class', 'defined')
| selectattr('attributes.device_class', 'eq', 'battery')
| rejectattr('state', 'eq', ['unknown', 'unavailable'])
| select('le', 90)
| map(attribute='name') | list
}}
c0ntax:
select('le', 90)
selectattr('state', 'le', 90)
c0ntax
(Martin)
May 26, 2023, 5:42am
7
Making that amendment still returns a blank list and I definitely have batteries that have a state of less than 90.
c0ntax
(Martin)
May 26, 2023, 6:55am
8
Ah, I’ve come up with the below now which does give a result (added some replace
to clean it up) but it returns just the states whereas I want to return the device name and state (plus % symbol)
{{ states.sensor
| selectattr('attributes.device_class', 'defined')
| selectattr('attributes.device_class', 'eq', 'battery')
| map(attribute='state')
| reject('in', ['unknown', 'unavailable'])
| map('int', -1) | select('le', 90)
|select('ge', 0)
| list | replace(",","<br>")| replace("[","")| replace("]"," ")| replace("\x27","")| replace("\x22","")
}}
Result:
Right, I missed something here. States are always strings, so to use the selectattr
on state
when it’s numerical needs to be a bit hacky to work.
Try this version:
{{ states.sensor
| selectattr('attributes.device_class', 'defined')
| selectattr('attributes.device_class', 'eq', 'battery')
| rejectattr('state', 'in', ['unknown', 'unavailable'])
| selectattr('state', 'ne', '100')
| selectattr('state', 'le', '90')
| selectattr('state', 'ge', '0')
| map(attribute='state')
| list
}}
In case you have non-numeric battery states, you can include | selectattr('state', 'is_number')
, but that unfortunately doesn’t affect the type.
I don’t think there’s a way to cast inside a selectattr
.
c0ntax
(Martin)
May 26, 2023, 1:50pm
10
Thanks Pieter, it returns the correct result, the same as the template in my last post.
All I need to know now, as I can’t figure it out, is how to show the friendly name, state and % symbol together in the list.
It’s in my first post.
{% set batteries = states.sensor
| selectattr('attributes.device_class', 'defined')
| selectattr('attributes.device_class', 'eq', 'battery')
| rejectattr('state', 'in', ['unknown', 'unavailable'])
| selectattr('state', 'ne', '100')
| selectattr('state', 'le', '90')
| selectattr('state', 'ge', '0')
%}
{% for battery in batteries -%}
- {{ state_attr(battery.entity_id, 'friendly_name') }}: {{ states(battery.entity_id) }}%
{% endfor %}
1 Like
c0ntax
(Martin)
May 26, 2023, 4:24pm
12
That’s working now.
Thank you for your help, and your patience, Pieter.
1 Like
RkcCorian
(Rkc Corian)
October 20, 2024, 7:02am
13
Hello together,
I try to use your example, but seems I make a mistake as it is not working for me. Can you help me please?
Below my YAML…
##Works, but only for state "open"
{{ expand('cover.hausrollladen')
| rejectattr('entity_id', 'in', label_entities('Gruppe'))
| selectattr('state', 'eq', 'open')
| list | count | int }}
##Does not work, try to count in states open|opening
{{ expand('cover.hausrollladen')
| rejectattr('entity_id', 'in', label_entities('Gruppe'))
| selectattr('state', 'eq', ['open', 'opening'])
| list | count | int }}
##Does not work, try to count in states open|opening
{{ expand('cover.hausrollladen')
| rejectattr('entity_id', 'in', label_entities('Gruppe'))
| selectattr('state', 'eq', '(open|opening)')
| list | count | int }}
Result is…
##Works, but only for state "open"
5
##Does not work, try to count in states open|opening
0
##Does not work, try to count in states open|opening
0