Disclaimer: There’s nothing new that does not really exist in this post. It brings together ideas and recipes from other contributors. I’m just sharing them together. Attributions at the end.
In this post I explain how I get the real last open/close status of my doors and windows, and the real last detected for PIR. I share the code for dashboard that shows their real last changed and status, and they are also ordered by last changed (optional).
Result:
You can either use one group and one template trigger OR use different groups per sensors. See explanation in step 2) for choosing what’s best for you.
Steps:
- Create 2 or 3 groups (One or two for windows and doors), one for presence detectors (PIR and others)
- Create template triggers for each group. You will need to manually list of the sensors of this group in the template sensor. That’s my main remaining “problem” (see “Bonus” below).
I use different template triggers because I may have different triggers for each group. For instance, I use “to: on” for Presence Sensors. I consider that a door being open or closed is a sign of presence. However, for detectors, I consider it applies only when it goes to “on”. You may want to keep the “any change state” behavior if you consider that it’s important for you to know when a presence sensor goes to “off”. I think it may be relevant for millimeter-wave sensors like Aqara FP1/2.
Here’s the code in configuration.yaml for 3 groups:
template:
- trigger:
- platform: state
entity_id:
- binary_sensor.buanderie_presence
- binary_sensor.cellier_motion_sensor
- binary_sensor.couloir_motion_sensor
to:
- "on"
not_from:
- unavailable
- unknown
sensor:
unique_id: dbf841e2-ae6f-4fc1-9534-a10462040001
name: Presence Sensors Change History
state: "{{ trigger.entity_id }}"
attributes:
changes: >
{% set current = this.attributes.get('changes', {}) %}
{% set new = {trigger.entity_id: trigger.to_state.last_changed.isoformat()} %}
{{ dict(current, **new) }}
- trigger:
- platform: state
entity_id:
- binary_sensor.bureau_julien_fenetre
- binary_sensor.bureau_morgane_fenetre
- binary_sensor.wc_fenetre
not_to:
- unavailable
- unknown
not_from:
- unavailable
- unknown
sensor:
unique_id: dbf841e2-ae6f-4fc1-9534-a10462040000
name: Window Sensors Change History
state: "{{ trigger.entity_id }}"
attributes:
changes: >
{% set current = this.attributes.get('changes', {}) %}
{% set new = {trigger.entity_id: trigger.to_state.last_changed.isoformat()} %}
{{ dict(current, **new) }}
- trigger:
- platform: state
entity_id:
- binary_sensor.buanderie_porte
- binary_sensor.cuisine_porte
- binary_sensor.exterieur_portail
not_to:
- unavailable
- unknown
not_from:
- unavailable
- unknown
sensor:
unique_id: dbf841e2-ae6f-4fc1-9534-a10462040002
name: Door Sensors Change History
state: "{{ trigger.entity_id }}"
attributes:
changes: >
{% set current = this.attributes.get('changes', {}) %}
{% set new = {trigger.entity_id: trigger.to_state.last_changed.isoformat()} %}
{{ dict(current, **new) }}
This is the type of sensor it automatically creates:
Bonus (not required for the cards): An alternative for the latest activated binary sensor of a group) using a template trigger
template:
# https://community.home-assistant.io/t/automation-trigger-on-group-of-sensors-and-sent-specific-triggering-sensor-in-notification-so-close/375213/15?u=mincka
- sensor:
- name: Latest Opening
state: >
{% set x = expand('binary_sensor.ouvertures') | selectattr('state', 'eq', 'on') | sort(attribute='last_changed', reverse=true) | list %}
{{ (x[0].entity_id if now() - x[0].last_changed < timedelta(seconds=3) else '') if x | count > 0 else '' }}
Sadly, I have issues to leverage this “Latest Opening” sensor ,which benefits from reading groups, with my trigger sensor. This is because there are conflicts when multiple sensors are updated simultaneously. Ultimately, it would be perfect to get TheFes trick work with a group.
- Use
custom:auto-entities
for the Lovelace card.
This part, that is the real “new” thing of this thread, was a little bit tricky because I wanted the sorting by last change and we must use a template filter to achieve this. There are also tricks to show the relative time as secondary attribute (the main purpose of this post), and to show the active color. If you don’t want the sorting by last changed, it’s easier to configure the card.
To get the proper labels for “on”/“off”, udpate the last part of the templates. For instance, I use iif("Detected","Clear")
for the presence detectors card, instead of iif("Open","Closed")
.
type: custom:auto-entities
card:
type: entities
title: Portes
state_color: true
filter:
template: >
{% set entities = state_attr('sensor.door_sensors_change_history',
'changes') | dictsort(false, 'value', reverse = True) %}
[{% for entity in entities %}
{"entity": "{{entity[0]}}", "name": "{{state_attr(entity[0],
'friendly_name')}}", "type": "custom:template-entity-row", "secondary": "{{
relative_time(state_attr("sensor.door_sensors_change_history",
"changes")[entity[0]]| as_datetime)}} ago", "color": "{{ is_state(entity[0],
"on") | iif("var(--state-active-color)") }}", "state": "{{
is_state(entity[0], "on") | iif("Open","Closed") }}"},
{% endfor %}]
sort:
method: none
- A markdown card for the latest status of each history sensor:
{% set entities = state_attr('sensor.door_sensors_change_history', 'changes') | dictsort(false, 'value', reverse = True) %}
{% set entity_id = entities[0][0] %}
{% set entity_name = state_attr(entity_id, 'friendly_name') %}
{% set entity_last_update = entities[0][1] %}
{% set datetime = (entity_last_update| as_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', True)) %}
{% set relative_datetime = relative_time(strptime(datetime,"%Y-%m-%d %H:%M:%S")) %}
<ha-icon icon="mdi:door-open"></ha-icon> {{ entity_name }} - {{ relative_datetime }} ago
Le {{ entity_last_update | as_timestamp | timestamp_custom('%d/%m/%Y')}} à {{ entity_last_update | as_timestamp | timestamp_custom('%H:%M:%S') }}
{% set entities = state_attr('sensor.presence_sensors_change_history', 'changes') | dictsort(false, 'value', reverse = True) %}
{% set entity_id = entities[0][0] %}
{% set entity_name = state_attr(entity_id, 'friendly_name') %}
{% set entity_last_update = entities[0][1] %}
{% set datetime = (entity_last_update| as_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', True)) %}
{% set relative_datetime = relative_time(strptime(datetime,"%Y-%m-%d %H:%M:%S")) %}
<ha-icon icon="mdi:motion-sensor"></ha-icon> {{ entity_name }} - {{ relative_datetime }} ago
Le {{ entity_last_update | as_timestamp | timestamp_custom('%d/%m/%Y')}} à {{ entity_last_update | as_timestamp | timestamp_custom('%H:%M:%S') }}
{% set entities = state_attr('sensor.window_sensors_change_history', 'changes') | dictsort(false, 'value', reverse = True) %}
{% set entity_id = entities[0][0] %}
{% set entity_name = state_attr(entity_id, 'friendly_name') %}
{% set entity_last_update = entities[0][1] %}
{% set datetime = (entity_last_update| as_timestamp | timestamp_custom('%Y-%m-%d %H:%M:%S', True)) %}
{% set relative_datetime = relative_time(strptime(datetime,"%Y-%m-%d %H:%M:%S")) %}
<ha-icon icon="mdi:window-open"></ha-icon> {{ entity_name }} - {{ relative_datetime }} ago
Le {{ entity_last_update | as_timestamp | timestamp_custom('%d/%m/%Y')}} à {{ entity_last_update | as_timestamp | timestamp_custom('%H:%M:%S') }}
- Open/close and enable all the sensors at least one time to initialize everything. You may get a few errors in the logs during the setup.
Attribution:
@TheFes
@thomasloven for Auto-Entities
Related WTH topic, please vote!