Template - More than one attribute

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

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.

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
}}
selectattr('state', 'le', 90)

Making that amendment still returns a blank list and I definitely have batteries that have a state of less than 90.

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.

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

That’s working now.

Thank you for your help, and your patience, Pieter.

1 Like

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