PIR - Motion Last Seen Sensor

So I’ve got a PIR motion sensors in each room of my home. I wanted a single sensor reading to show which PIR triggered last. This is the config yaml I kludged to make it work:

platform: template
sensors:
  template_pir_motion:
    friendly_name: 'Motion Location'
    value_template: >
                {% for pir in  [states.binary_sensor.pir_living_room, states.binary_sensor.pir_office_room, states.binary_sensor.pir_bed_room] %}
                  {% if as_timestamp(pir.last_changed) == as_timestamp([states.binary_sensor.pir_living_room, states.binary_sensor.pir_office_room, states.binary_sensor.pir_bed_room] | map(attribute='last_changed') | max) %}
                    {{ pir.name }}
                  {% endif %}
                {% endfor %}

I’m new to Jinja templating. Can anyone point out what might be done better?

It works well enough, but I’m thinking this might be better done with a custom component…

3 Likes

Nicely done. Another way you might approach this is to have an input_select with each pir.name and update that value when motion is triggered.

1 Like

Nice!

Here is a small enhancement you can do to prevent two duplicate lists of pirs:

platform: template
sensors:
  template_pir_motion:
    friendly_name: 'Motion Location'
    value_template: >
                {%- set pirs = [states.binary_sensor.pir_living_room, states.binary_sensor.pir_office_room, states.binary_sensor.pir_bed_room] %}
                {% for pir in pirs %}
                  {% if as_timestamp(pir.last_changed) == as_timestamp(pirs | map(attribute='last_changed') | max) %}
                    {{ pir.name }}
                  {% endif %}
                {% endfor %}

You can probably also loop trough all states available and extract any values that contain pir_ to have it always up-to-date if you add more PIR’s to your home.

5 Likes

Makes sense, thanks for the thought.

Ah, excellent note. I was so confounded with not being able to persist variables set in the for block scope… didn’t think to pull the list out.

Yeah, I guess that wouldn’t be too unreasonable to loop through all the states. I made a group of them, hoping I could iterate through just the group, but haven’t seen a way to do that yet.

Thanks for the insights!

Hi, is there some code that would allow me to list all my motion sensors individually, their current status and when each one was last tripped ?

I’ve done this by using an input_slider basically each time a PIR is triggered I set the input_slider to a preset value. 1 for bedroom, 2 for living room and so on, but this method looks much cleaner. Nice work!

No straightforward way so far as I can see, but it can indeed all be done through a combination of sensor configs / value_templates. As you can see in my config above, you can pull the sensor state’s last change from the state object itself (docs on that here: https://home-assistant.io/docs/configuration/state_object/)

Thanks, has been working well except in the situation where I move quickly from one room to a an adjacent room. What happens is: the room I walk to updates my template_pir_motion field before the room I walked from switches off, which then becomes the “last_changed” state when it receives that off message…

suppose I could only have the sensors report when the motion is first seen… I just wouldn’t get an on/off indication.

Or as I’ve been thinking in the back of my mind all along, this may be a situation where it’s better to write a custom component. Been fun to learn about the templating and see how far I could get with just them alone.

Anyone see a way to ignore the off message?

1 Like

My way of ignoring the off messages is to have an automation for each binary sensor that triggers when the motion sensor triggers to the on state. That then checks which motion sensor was triggered and sets an input_slider to a predefined integer value for the specific motion sensor that was triggered.

Then another automation gets called when the input_slider moves from one integer to another and that is what triggers automations to turn on/off lights depending on my location.

1 Like

Thanks, I’ve implemented a version of your code in my own setup using my BRUH Multisensors.

input_select:
  last_room_with_motion:
      name: "Last room with motion"
      options:
        - Livingroom
        - Bedroom
        - Unknown
      initial: Unknown

Along with

automation:
  - alias: Store Motion Sensor 1
    trigger:
     - platform: state
       entity_id: sensor.sn1_pir
       from: 'standby'
       to: 'motion detected'
    action:
      service: input_select.select_option
      data:
        entity_id: input_select.last_room_with_motion
        option: Livingroom
  - alias: Store Motion Sensor 2
    trigger:
     - platform: state
       entity_id: sensor.sn2_pir
       from: 'standby'
       to: 'motion detected'
    action:
      service: input_select.select_option
      data:
        entity_id: input_select.last_room_with_motion
        option: Bedroom

There’s another way to do this by logging timestamps of motion detectors and comparing those, though it’s more complicated and I don’t know how to up-scale past 2 sensors with that method. (this method can up-scale though)

2 Likes
  - platform: template
    sensors:
      template_last_motion:
        friendly_name: 'Laatste Beweging'
        value_template: >
          {%- set pirs = [states.binary_sensor.motion_sensor_158d00013f91dd, states.binary_sensor.motion_sensor_158d0001560bd2, states.binary_sensor.motion_sensor_158d00018739f0, states.binary_sensor.sensor_4, states.binary_sensor.motion_sensor_158d0001e62f31, states.binary_sensor.motion_sensor_158d0001e6300c] %}
          {% for pir in pirs %}
            {% if as_timestamp(pir.last_changed) == as_timestamp(pirs | map(attribute='last_changed') | max) %}
              {{ pir.name }}
            {% endif %}
          {% endfor %}

Any suggestion to change this to add date and time to the last motion? Thanks in advance for any reply, suggestion.

. . .
          {% for pir in pirs %}
            {% if as_timestamp(pir.last_changed) == as_timestamp(pirs | map(attribute='last_changed') | max) %}
              {{ pir.name }} {{pir.last_changed}}
            {% endif %}
          {% endfor %}

Thanks!!!

Now I’m looking for info to transform the timestamp ( 2018-05-22 16:19:45.654266+00:00 ) to
22-05 18:19:45
DD-MM HH-MM-SS (time in UTC+2 (summertime for UCT+1)).

Any suggestion? Sorry for my noobness.

See http://strftime.org/. The timezone should be set by HASS I think.

{{pir.last_changed.strftime('%d-%m %X') }}

Perfect! Thanks again for your help!!

Time offset (-2 hours is still there), despite: time_zone: Europe/Amsterdam.

Also searched (but not found yet) for a way to add a line break between {{ pir.name }} and {{pir.last_changed}}.

Sorry for keep asking questions, have to learn a lot :wink:

Any suggestion??:

  • to add a line break after {{pir.name}}, so {{pir.last_changed.strftime(’%d-%m %X’) }} wil be on a new line ?
  • to show local time instead of now UTC time? So how can I add 1 hour (normal) or 2 hours (during summertime) to the pir.last_changed time?

Thanks in advance for any help/suggestion !

Been figuring it out myself this morning, pick one of your sensors and consider the following:

AA: {{ states.binary_sensor.testdevice.last_changed.tzinfo }}
BB: {{ now().tzinfo }}

On my system - shows that internal dates are UTC, and ‘now’ returns in the local timezone (Europe/London)

AA: UTC
BB: Europe/London

Now we can look at an actual sensor-last-changed, and re-render it in the local timezone as follows:

CC: {{ states.binary_sensor.testdevice.last_changed }}
DD: {{ states.binary_sensor.testdevice.last_changed.astimezone(now().tzinfo) }}

Which outputs

CC: 2018-06-03 10:41:00.201056+00:00
DD: 2018-06-03 11:41:00.201056+01:00
1 Like

That did it! Thanks a lot!!! :smile:

    sensors:
      template_last_motion:
        friendly_name: 'Laatste Beweging'
        value_template: >
          {%- set pirs = [states.binary_sensor.motion_sensor_158d00013f91dd, states.binary_sensor.motion_sensor_158d00018739f0, states.binary_sensor.sensor, states.binary_sensor.sensor_12, states.binary_sensor.sensor_2, states.binary_sensor.motion_sensor_158d0001e62f31, states.binary_sensor.neo_coolcam_battery_powered_pir_sensor_sensor, states.binary_sensor.sensor_3] %}
          {% for pir in pirs %}
            {% if as_timestamp(pir.last_changed) == as_timestamp(pirs | map(attribute='last_changed') | max) %}
              {{ pir.name }} {{pir.last_changed.astimezone(now().tzinfo).strftime('%d-%m %X')}}
            {% endif %}
          {% endfor %}
2 Likes

Hi guys,

Sorry for the n00b question, I want to show the value of the input-select, but without the controls, so that it just looks like: Lost motion triggered and the value the input-select value.

I can show the input-select on the frontpage, but still can change the input.

Hope somebody can show me in the direction, just started using HASS.io.