Save the last status change of a motion detector and calculate based on that


After hours of searching through year-old forum posts, I have to ask here now. I would like to know the date and time when a motion detector switches from “motion detected” (occupancy “on”) to “no motion detected” (occupancy “off”). In other words, the time when a motion detector was last triggered.

I’d like to display this time on a sensor and also use it in a template for calculations.

So far, I’ve written something like this, but unfortunately, it only returns “Unknown” for the “states” under “Developer Tools”.

  - trigger:
      - platform: state
        entity_id: binary_sensor.bewegungsmelder_schreibtisch
        to: 'off'
      - name: "Bla bla bla"
        state: "{{ as_timestamp(states.binary_sensor.bewegungsmelder_schreibtisch.last_changed) }}"

Could someone help me?
Thank you very much!

I think you’re overthinking it. If you’re only triggering updates based on changing “to on”, you can just use the {{ now() }} to record the time of the last trigger.

So I think the below code should do what you want:

  - trigger:
      - platform: state
        entity_id: binary_sensor.bewegungsmelder_schreibtisch
        to: 'off'
      - name: "Bla bla bla"
        state: "{{ now() }}"
        device_class: timestamp
1 Like

Thank you very much for your quick help! Your code works wonderfully! Well, almost at least. It now finally gives me date and time. Unfortunately, the time is shifted by one hour. Apparently, it returns a value in the UTC timezone. How do I need to adjust my code so that it displays the time one hour later?

Please forgive the silly questions :slight_smile:

sounds like the timezone of your homeassistant isn’t set right. so it’s defaulting to utc.

if you go to settings->general, what does it say it thinks the timezone is?

1 Like

Thank you for the hint. I checked it out. I did set the time zone correctly with (GMT +01:00) when setting up Home Assistant. Unfortunately, that’s not where the mistake lies :frowning: Still, thanks for the help :slight_smile:

huh. that is indeed odd. now is certainly supposed to give you localtime as opposed to utcnow(). when you go to logbook, and you see the most recent event, is that time correct? or is that off by 1 as well?

you don’t have an override in your config yaml like this:

  time_zone: America/Los_Angeles

and if you change the timezone it in settings, then go to dev-tools->template and do {{ now() }} does it change what it thinks local time is? and still off by 1 from the new timezone?

1 Like

Hello armedad!

Thank you very much for your response and your help! Unfortunately, that didn’t help further.
When I look into the logbook, the correct time is displayed (UTC + 01:00). If I enter the expression “{{ now() }}” in the “Developer Tools” under “Template”, the correct time is also displayed (UTC + 01:00).

The strange thing is that I haven’t written any expression with “time_zone” in the configuration.yaml. The only place where I work with times in the configuration.yaml is here.

  - platform: time_date
      - "time"
  - sensor:
    - name: "Alarm"
      state: "{{ states('input_boolean.alarm') }}"
  - sensor:
    - name: "Wecker"
      state: "{{ state_attr('input_datetime.wecker', 'timestamp') | timestamp_custom('%H:%M', None) }}"

Here, I define the wake-up time and a switch (whether the alarm is “on” or “off”), which I previously pass from the iPhone to HA via a shortcut, as a sensor. An automation is then triggered by a template, which compares the current time with the wake-up time:

{{ now().timestamp() | timestamp_custom('%H:%M:%S') == ((state_attr('input_datetime.wecker', 'timestamp')) - 900) | timestamp_custom('%H:%M:%S', false) }}

This also works correctly (UTC + 01:00). Or could the problem lie in this place where I define the sensor as time date?

Nevertheless, it doesn’t seem to work with the motion sensor example above.
Does anyone else have an idea what could be the problem? I would be very grateful for any help!

It’s not clear to me what code you are having an issue with. But the documentation you should need is here.


now() returns a datetime object that represents the current time in your time zone.

as_local() converts datetime object to local time. This function can also be used as a filter.

Filter timestamp_custom(format_string, local=True, default) converts an UNIX timestamp to its string representation based on a custom format, the use of a local timezone is the default.

From the “other state examples” section:

{{ as_timestamp(states.binary_sensor.garage_door.last_changed) }}

{{ as_local(states.binary_sensor.garage_door.last_changed) }}

{{ as_timestamp(now() - as_timestamp(states.binary_sensor.garage_door.last_changed) }}

{{ as_local(states.sensor.time.last_changed) }}

When working with datetimes, you need to be careful about whether the value you are working with is timezone-aware, and if it is, what timezone it is referring to.

And be aware that datetimes in the recorder database will be timezone-aware in UTC. So if you are accessing the last_changed property of a sensor, you should expect to receive a UTC result. If you want to see that value in your own timezone, the as_local function or filter is what you want to use (reference the example above from the docs).

Edit: one more note from the docs that is important to you:

UNIX timestamp is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970.

The key point being that UNIX timestamps are UTC only