I’m trying to create a sensor that shows the last triggered motion sensor. I’ve managed to get the last state change using this:
{%- set pirs = [states.binary_sensor.back_room_motion, states.binary_sensor.downstairs_toilet_motion, states.binary_sensor.hallway_motion, states.binary_sensor.kitchen_motion, states.binary_sensor.landing_motion] %}
{% for pir in pirs %}
{% if as_timestamp(pir.last_changed) == as_timestamp(pirs | map(attribute='last_changed') | max) %}
{{ pir.name }}
{% endif %}
{% endfor %}
But obviously that counts every state change, rather than the last sensor to have changed to an “on” status so it also triggers when a motion sensor resets to off, which is not what I want.
I’ve tried the following:
{%- set pirs = [states.binary_sensor.back_room_motion, states.binary_sensor.downstairs_toilet_motion, states.binary_sensor.hallway_motion, states.binary_sensor.kitchen_motion, states.binary_sensor.landing_motion] %}
{% for pir in pirs %}
{% if is_state(pir.state, 'on') %}
{% if as_timestamp(pir.last_changed) == as_timestamp(pirs | map(attribute='last_changed') | max) %}
{{ pir.name }}
{% endif %}
{% endif %}
{% endfor %}
My thinking here was that it would first check if the state had turned to “on” before comparing timestamps but this doesn’t return anything at all, so i’ve obviously ballsed that one up!
Is someone kindly able to point me in the wrong direction please?
I think that makes sense, this templating stuff has always been my downfall. Is there another way that this can be accomplished then maybe? I just want it to output the last triggered “on” motion sensor which seems fairly trivial but I haven’t be able to get it working so far.
I like your idea about the template sensor for last change. I do display that information via a history graph:
You just have to scroll over the graph to get the time of the last change:
I do like the idea of easily identifying the last state change. I would show that in addition to my current graph since I like to be able to easily see the pattern.
The template is evaluated whenever one of the five listed binary sensors changes state.
The template selects all that are currently on.
It sorts them by last_changed in reverse order (reverse chronological order) and converts it to a list.
If there’s more than one item in the list, it reports the first (zeroth) item’s friendly_name (“name”) and last_changed converted to local time.
If there are no items in the list, it reports the sensor’s existing value. (NOTE: This value will initially be unknown until one of the binary sensors changes state.)
Thankyou! That definitely looks closer. Unfortunately now though it changes back to “unknown” when no motion is detected again. Is there a way of making it store the last value rather than returning to unknown?
Basically i’m using it for an automation which auto arms the alarm at between certain times at night if we forget to. To be certain that we’re all in bed I check 2 things:
That the harmony remote shows that everything is turned off.
The last motion sensor triggered has been the landing (upstairs) for 15 minutes.
That way if we’re downstairs and doing something other than watching TV or listening to music the last motion will be from downstairs and so the alarm won’t arm. If everything is off, the last motion was upstairs and it has been that way for 15 minutes then it’s pretty certain that we’re in bed and it’s safe to arm the alarm.
My original template in the opening post was working great until one night the kitchen sensor took longer to reset (I don’t know why but they sometimes do this). We came up to bed and the landing reset before the kitchen did. When the kitchen then finally set to “off” the sensor thought the last motion was in the kitchen when really it had just taken longer to reset so the alarm was never auto-armed. If the sensor only took “on” changes into account this would never happen as the last “on” trigger would always be the last place that we walked by, regardless of reset times.
Hope that makes sense, I thought it might help to put a bit of context to things. This is the automation it’s used in:
alias: Alarm Auto On at Night
description: ''
trigger:
- platform: state
entity_id: sensor.last_motion
to: Landing Motion
for: '00:15:00'
condition:
- condition: and
conditions:
- condition: time
after: '22:00:00'
before: '06:00:00'
- condition: state
entity_id: remote.home
state: 'off'
- condition: state
entity_id: alarm_control_panel.yale_smart_alarm
state: disarmed
action:
- service: alarm_control_panel.alarm_arm_home
data:
entity_id: alarm_control_panel.yale_smart_alarm
- service: notify.notify
data:
message: Alarm has been auto-armed for the night.
mode: restart
The example I provided does not behave like that. In fact, I have had it running since yesterday and it reports the name of the most recently active motion sensor even though I’ve restarted Home Assistant at least twice (I upgraded from 0.117.2 to 0.117.4 this morning).
Did you modify it in any way, such as change its name? If you did rename it, you must change sensor.recent_motion in this line to the new name:
You’re absolutely right, for some reason that wasn’t working properly earlier, I even came back and tested it a few minutes ago. Same thing, it would just revert to “unknown”, It did this whether I added it to config and in the templating dev tools.
I restarted HA and it’s now working as it should… It saves the last state absolutely fine now so I have no idea what happened there. Thanks for your help with this! Much appreciated.
I’ll get the hang of this templating stuff one day…
To add to the template sensor above as given by @123 (thanks), this fails in the following situation:
Sensor A becomes active (e.g. Kitchen) and afterwards sensor B (e.g. hallway) becomes active. If hallway now goes back to off earlier than the kitchen sensor (i.e. kitchen still on), it will switch back to kitchen while the last was actually hallway. This can happen if you have different motion sensors with different off times.
By adding a simple ((now - last_changed) < 1), you prevent this situation as the kitchen sensor is still on and last_changed >1.
Below what I use:
template:
sensor:
- name: "Last area motion detected"
icon: "mdi:motion-sensor"
state: >-
{% set x = expand('group.motion')
| selectattr('state', 'eq', 'on')
| sort(reverse=true, attribute='last_changed')
| list %}
{% if (x | count > 0) and (((as_timestamp(now()) - as_timestamp(x[0].last_changed)) | int) < 1) %}
{% if (area_name(x[0].entity_id) != None) %}
{{ area_name(x[0].entity_id) }}
{% else %}
{{ x[0].name }}
{% endif %}
{% else %}
{{ states('sensor.last_area_motion_detected') }}
{% endif %}
Or without groups (i.e. all motion classed sensors):
Not really a failure; your requirements are different. The solution post determines the most recent and currently active motion sensor (meaning where is there motion happening right now, regardless of a sensor’s cooldown period).
In the example you provided, that would be the kitchen sensor because it’s still active whereas hallway, even though it occurred after kitchen, is no longer active. If one wants to know the most recent sensor to record a state-change, regardless if it’s currently on or off, you could simply remove the selectattr that specifies the sensor’s state must be on.