I have an automation to monitor low batteries that’s been working fine. I want to optimise the automation by removing some duplication, by storing a list of filtered entities in a variable. The odd thing is that while a test version of this works in the template editor, it doesn’t when actually executing the automation. Note that I’m not triggering the automation manually: I’ve modified the trigger to run every minute for testing purposes.
This is the working automation:
- alias: "Check For Low Batteries"
initial_state: true
variables:
threshold: 15
trigger:
platform: time
at: "09:00:00"
condition: >-
{{ states.sensor
| selectattr('attributes.monitor','eq',True)
| selectattr('attributes.device_class','eq','battery')
| map(attribute='state')
| map('int')
| select('le', threshold)
| list
| count
> 0
}}
action:
- service: notify.mobile_app_ceres
data:
title: "Batteries"
message: >
{%- set batteries = states.sensor
| selectattr('attributes.monitor','eq',True)
| selectattr('attributes.device_class','eq','battery')
| map(attribute='entity_id')
%}
The following devices have less than {{ threshold }}% charge:
{%- for b in batteries %}
{%- if states(b) | int < threshold 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
This is the optimised version:
- alias: "Check For Low Batteries"
id: "5ff59069-6f3c-4f9d-bc66-b50bea8e184e"
initial_state: true
variables:
# test threshold to be reverted
threshold: 85
monitored_batteries: >-
{{ states.sensor
| selectattr('attributes.monitor', 'defined')
| rejectattr('state', 'in', ['unavailable', 'unknown', 'none'])
| selectattr('attributes.monitor', 'eq', True)
| selectattr('attributes.device_class', 'eq', 'battery')
}}
# test trigger to be reverted
trigger:
platform: time_pattern
minutes: "/1"
condition: >-
{{
monitored_batteries
| map(attribute='state')
| map('int')
| select('le', threshold)
| list
| count
> 0
}}
action:
- service: notify.mobile_app_ceres
data:
title: "Batteries"
message: >
{%- set batteries = monitored_batteries | map(attribute='entity_id') %}
The following devices have less than {{ threshold }}% charge:
{%- for b in batteries %}
{%- if states(b) | int < threshold 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
This is the error from the log:
2022-06-16 16:41:00 WARNING (MainThread) [homeassistant.components.automation] Error evaluating condition in 'Check For Low Batteries':
In 'condition':
In 'template' condition: UndefinedError: 'str object' has no attribute 'state'
And the same error in the trace:
Also note the |-
above – not sure why it’s included or where it comes from. It may be relevant, but I don’t know. I know what it normally means when used in YAML.
I thought that perhaps the variable(s) get serialised between steps, so I tried this in the template editor to try and replicate the error at least, but there’s no error (in Python a string can be handled like a list):
{% set foo = "bar" %}
{{ foo | map(attribute='state') }}
This works fine in the template editor: