Template to determine last time state changed to

Hi,

Trying to figure out how to construct a template to determine when the door was last closed. I’ve been using last_changed on the door sensor, but of course that doesn’t work because it also changes when the door is opened.

As a construct, this works, but the problem is that I need states.sensor.frontdoorstatus.last_changed to tell me when it changed to closed only.

{% if (states.vacuum.neato.last_changed) > (states.sensor.frontdoorstatus.last_changed) %}

  {%- if (is_state('vacuum.neato', 'unavailable')) -%}
  The vac went offline at {{(as_timestamp(states.vacuum.neato.last_changed) | timestamp_custom('%I:%M %p'))}}. Its current state is {{states('vacuum.neato')}}. Probably got stuck on a sock then its battery went flat.

  {%- elif (is_state('vacuum.neato', 'error')) -%}
  The vac tried to eat something stupid and got stuck at {{(as_timestamp(states.vacuum.neato.last_changed) | timestamp_custom('%I:%M %p'))}}. Don't know where it is, you'll have to go find it. Its battery is only {{states('sensor.neato_battery')}} percent. Useless thing.

  {%- elif (is_state('vacuum.neato', 'cleaning')) -%}
  The vac is still going. Watch out!

  {%- elif (is_state('vacuum.neato', 'docked')) -%}
  Miraculously, the vac finished and went back to bed at {{(as_timestamp(states.vacuum.neato.last_changed) | timestamp_custom('%I:%M %p'))}}.

  {%- endif -%}

(This is part of my ‘Welcome Home’ speech Alexa gives).

Thanks for any pointers

:slight_smile:
Amanda

1 Like
{% if (states.vacuum.neato.last_changed) > ((states.sensor.frontdoorstatus.last_changed) and is_state('sensor.frontdoorstatus', 'on')) %}

or whatever state of the sensor represents closed.

Not sure thats gonna do it??? This gets triggered every time the door is opened, but I need the template to do stuff based on the time difference between when the door was closed and the time the neato state is updated.

So like…
Door closed.
(Vac could start (dependant on other stuff))
(Vac finishes)
Door opens
Triggers script
Script creates message for Alexa to say.
Alexa says things dependant on whether vac has been on since door closed or not - it needs to run every time the door opened, but it needs to know when the door closed in order to do this.

Thanks

1 Like

Oops, actually I just realized I put the (…) in the wrong place.

{% if ((states.vacuum.neato.last_changed) > ((states.sensor.frontdoorstatus.last_changed)) and is_state('sensor.frontdoorstatus', 'on') %}

Again it depends on what the actual state of the sensor is when the door is closed.

But what that template does is checks that the door is “closed” (state == ‘on’ or whatever) and that the “states.vacuum.neato.last_changed” time is greater than the “states.sensor.frontdoorstatus.last_changed” time.

I think that’s what you are asking for unless I’m misunderstanding.

Also, have you checked to make sure you can actually compare datetime objects like that (using > directly on the object instead of converting to a timestamp)? I think so but I’ve never actually tried it myself.

Nope. That’s what this part of the template is for:

Except you want the state 'off' for closed.

Thanks for replying :slight_smile:
Not sure I’m explaining myself very well, soz…

The script is triggered by an automation when the door changes to ‘open’.

For info, this is the automation and works fine…

- id: Welcome Home
  alias: Welcome Home
  trigger:
  - platform: state
    entity_id: sensor.frontdoorstatus
    from: 'Closed'
    to: 'Open'
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: switch.hall_presence
        state: 'off'
        for: '00:20:00'
  action:
  - service: script.turn_on
    entity_id: script.welcomehome

What I need the template to do is compare the time the vac status updated with the time the door changed to ‘closed’.

  welcomehome:
    sequence:
      - service: script.turn_on
        data:
          entity_id:
          - script.welcomehome_heaters
          - script.welcomehome_lights
      - service: logbook.log
        data_template:
          name: "Welcome Home Debug"
          message: "Neato Last State Change: {{(states.vacuum.neato.last_changed)}}. Front door opened at {{(states.sensor.frontdoorstatus.last_changed)}}. Neato state is: {{states('vacuum.neato')}}"   
      - delay: 00:00:10
      - service: notify.alexa_media_kitchen_echo
        data: {
        "message":"Welcome home! Its {{ (states('sensor.living_room_temp_sensor_zigbee'))}} degrees inside.
{% if (states.vacuum.neato.last_changed) > (states.sensor.frontdoorstatus.last_changed) %}

  {%- if (is_state('vacuum.neato', 'unavailable')) -%}
  The vac went offline at {{(as_timestamp(states.vacuum.neato.last_changed) | timestamp_custom('%I:%M %p'))}}. Its current state is {{states('vacuum.neato')}}. Probably got stuck on a sock then its battery went flat.

  {%- elif (is_state('vacuum.neato', 'error')) -%}
  The vac tried to eat something stupid and got stuck at {{(as_timestamp(states.vacuum.neato.last_changed) | timestamp_custom('%I:%M %p'))}}. Don't know where it is, you'll have to go find it. Its battery is only {{states('sensor.neato_battery')}} percent. Useless thing.

  {%- elif (is_state('vacuum.neato', 'cleaning')) -%}
  The vac is still going. Watch out!

  {%- elif (is_state('vacuum.neato', 'docked')) -%}
  Miraculously, the vac finished and went back to bed at {{(as_timestamp(states.vacuum.neato.last_changed) | timestamp_custom('%I:%M %p'))}}.

  {%- endif -%}
{% endif %}

The script is executed as it should (ie, only when the door is to ‘open’ state and only if we’ve come in from outside (which is what the hall_presence automation condition does, as you can’t get to the door from the inside without triggering hall presence sensor), the problem is the content in the message and the first IF statement.

This is the bit that I’m stuck with…

{% if (states.vacuum.neato.last_changed) > (states.sensor.frontdoorstatus.last_changed) %}

Whats wrong with it is that states.sensor.frontdoorstatus.last_changed will always be recent as the door state must have changed recently in order to trigger the script.

If we add another condition to the IF statement as suggested…

{% if ((states.vacuum.neato.last_changed) > ((states.sensor.frontdoorstatus.last_changed)) and is_state('sensor.frontdoorstatus', 'on') %}

This still won’t work because the whole thing only gets executed when the door is opened.

What I need is:

{% if ((states.vacuum.neato.last_changed) > 'the exact time the door last changed to closed' %}

rather than and is_state('sensor.frontdoorstatus', 'on') which will won’t compare the times.

I’ve figured out that comparing times with < and > does work.

:slight_smile:
THANKS!!!

All I’ve been able to think of is getting an automation to set an input.datetime when the door changes to closed. Then changing the troublesome if statement to compare the last update time of the input.datetime instead.

Feels a bit messy, but I can’t think of a better way.

Create a triggered template sensor for when the door changes to closed:

template:
  - trigger:
      - platform: state
        entity_id: sensor.frontdoorstatus
        from: 'Open'
        to: 'Closed'
    sensor:
      - name: Door Last Closed
        state:  "{{ now() }}"

Use this sensor in your automation.

Is there any reason you are using a sensor for your door instead of a binary sensor with device_class door?

6 Likes

THATS IT!!! :smiley:

Perfect, thank you.

Of all my thousands of lines of config, automations and scripts, i’d never even realised triggered template sensors were a thing.

Yeah, you’re right about the door sensor, just something i’ve not got around to. The actual sensor is a binary sensor, but the one I’ve ended up using is a template that translates to ‘open’ and ‘closed’.

Thanks!!!

That’s exactly what adding:

device_class: door

To your binary sensor will do.

Well sort of.

In the Lovelace frontend you get the displayed states Open and Closed, and as a bonus the icon changes (an open door and a closed one).

However in the backend, in your automations, you still use the states 'on' and 'off'.

https://www.home-assistant.io/integrations/binary_sensor/#device-class

Thanks, i think this is one of the many bits of tidying up i should do in my whole config.

Many of my ‘early creations’ def need a bit of work - i just got so caught up in the euphoria of actually getting stuff working.

This is just what I need! Thank you.

But, I can’t get it to pass config check.

Any ideas:

- platform: template
    - trigger:
        - platform: state
          entity_id: binary_sensor.test_switch_1
          from: 'off'
          to: 'on'
      sensor:
        - name: time_between_washes
          state:  "{{ (((as_timestamp(states.binary_sensor.test_switch_1.last_changed))) - (as_timestamp(states.input_boolean.previous_drum_wash.last_changed))) | round(0) }}"

I get the following error:

mapping values are not allowed here
in "/config/sensors.yaml", line 2, column 14

The first line should be just template

1 Like