@123 I wonder if you could help me with a template question please? I’ve been trying to follow a lot of your excellent template examples and experimenting with them in the template editor, but I’m stuck trying to count the number of entities that have a datetime attribute longer than x hours.
I have the following working template using for loops at the moment (along with associated automation for completeness)
template:
- sensor:
- unique_id: z2m_last_seen_entities
name: "Z2M Last Seen Entities"
state: >
{% set lapsed_hours = 24 %}
{% set ns = namespace(count=0) %}
{% for state in states.sensor | selectattr('entity_id', 'search', '.*_last_seen$') %}
{% if states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((lapsed_hours | int) * 60 * 60)) %}
{% set ns.count = ns.count + 1 %}
{% endif %}
{% endfor %}
{{ ns.count }}
attributes:
devices: >
{% set lapsed_hours = 24 %}
{% set result = namespace(sensors=[]) %}
{% for state in states.sensor | selectattr('entity_id', 'search', '.*_last_seen$') %}
{% if states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((lapsed_hours | int) * 60 * 60)) %}
{% set result.sensors = result.sensors + [state.name | regex_replace(find='_last_seen', replace='') ~ ' (' ~ relative_time(strptime(states(state.entity_id), '%Y-%m-%dT%H:%M:%S%z', 'unavailable')) ~ ')'] %}
{% endif %}
{% endfor %}
{{ result.sensors | join(', ') }}
automation:
- alias: Offline Zigbee Devices
id: offline_zigbee_devices
description: Sends notification for offline Z2m devices
trigger:
- platform: time
at: '20:00'
condition:
- condition: template
value_template: '{{states(''sensor.z2m_last_seen_entities'')|int > 0}}'
action:
- service: notify.signal_justme
data:
title: Low battery alert
message: '{% set phrase = ''s are '' if states(''sensor.z2m_last_seen_entities'')|int > 1 else '' is '' %}
The following sensor{{ phrase }}missing: {{ state_attr(''sensor.z2m_last_seen_entities'', ''devices'') }}'
The problem though is that this gives me the following errors when rebooting HA, which I assume is because the data isn’t ready straight away:
2022-04-27 11:42:27 WARNING (MainThread) [homeassistant.helpers.template] Template warning: 'as_timestamp' got invalid input 'unknown' when rendering template '{% set lapsed_hours = 24 %} {% set result = namespace(sensors=[]) %} {% for state in states.sensor | selectattr('entity_id', 'search', '.*_last_seen$') %}
{% if states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((lapsed_hours | int) * 60 * 60)) %}
{% set result.sensors = result.sensors + [state.name | regex_replace(find='_last_seen', replace='') ~ ' (' ~ relative_time(strptime(states(state.entity_id), '%Y-%m-%dT%H:%M:%S%z', 'unavailable')) ~ ')'] %}
{% endif %}
{% endfor %} {{ result.sensors | join(', ') }}' but no default was specified. Currently 'as_timestamp' will return 'None', however this template will fail to render in Home Assistant core 2022.1
2022-04-27 11:42:27 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template("{% set lapsed_hours = 24 %} {% set result = namespace(sensors=[]) %} {% for state in states.sensor | selectattr('entity_id', 'search', '.*_last_seen$') %}
{% if states(state.entity_id) == 'unavailable' or ((as_timestamp(now()) - as_timestamp(states(state.entity_id))) > ((lapsed_hours | int) * 60 * 60)) %}
{% set result.sensors = result.sensors + [state.name | regex_replace(find='_last_seen', replace='') ~ ' (' ~ relative_time(strptime(states(state.entity_id), '%Y-%m-%dT%H:%M:%S%z', 'unavailable')) ~ ')'] %}
{% endif %}
{% endfor %} {{ result.sensors | join(', ') }}")
Traceback (most recent call last):
File "/usr/lib/python3.9/site-packages/homeassistant/helpers/template.py", line 407, in async_render
render_result = _render_with_context(self.template, compiled, **kwargs)
File "/usr/lib/python3.9/site-packages/homeassistant/helpers/template.py", line 1820, in _render_with_context
return template.render(**kwargs)
File "/usr/lib/python3.9/site-packages/jinja2/environment.py", line 1291, in render
self.environment.handle_exception()
File "/usr/lib/python3.9/site-packages/jinja2/environment.py", line 926, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<template>", line 2, in top-level template code
TypeError: unsupported operand type(s) for -: 'float' and 'NoneType'
What I would like to do is optimise the code and avoid these errors with something like the following examples, but I can’t figure out what the code should be to manipulate the datetime state from the Zigbee2MQTT *_last_seen
entity (see screenshot below)
https://community.home-assistant.io/t/turn-off-all-light-on-from-3hours-not-using-group/345013/6?u=jarrah
This template lists all lights that have been on for more than 3 hours.
{{ states.light | selectattr('state', 'eq', 'on')
| selectattr('last_changed', 'lt', now() - timedelta(hours=3))
| map(attribute='entity_id') | join(', ') }}
{%- set threshold = 40 -%}
{{ states.sensor | selectattr('entity_id', 'search', '^(?!.*energy).*_power$')
| map(attribute='state') | map('int', 0) | select('<', threshold) | list | count }}
https://community.home-assistant.io/t/improvement-to-sensor-template-with-for-loop/360550/12?u=jarrah
{{ state_attr('weather.kmrb_hourly', 'forecast')
| selectattr('datetime', '<=', today_at('21:00').isoformat())
| map(attribute='temperature')
| max }}
I can count the total number of entities found like so:
{{ states.sensor | selectattr('entity_id', 'search', '.*_last_seen$') | map(attribute='entity_id') | list | count }}
However, the following gives an error that says TypeError: '<' not supported between instances of 'str' and 'datetime.datetime'
, so I assume it’s because the state value is a string rather than datetime object?
{{ states.sensor | selectattr('entity_id', 'search', '.*_last_seen$')
| selectattr('state', 'lt', now() - timedelta(hours=3))
| map(attribute='entity_id') | list | count }}
Thanks in advance.