Sensor trigger last_changed

Hello,
how can I trigger the last changed of a sensor? (automation)

  - alias: "Test"
    trigger:
      - platform: state
        entity_id: sensor.temperature
        for: "00:30:00"
    action:
      - service: notify.prowl
        data:
          message: "{{states.sensor.time.state}} Temperature has not changed since 30min "

can you explain what you mean here?

last_changed updates when the sensor updates. You cannot force a sensor to update unless you have a special sensor like an MQTT sensor that you can publish to.

If you are trying to trigger off the last changed state, you need to use a value template that references a time sensor.

sensor:
  - platform: time_date
    display_options:
      - 'date_time'
- alias: Test
  trigger:
    - platform: template
      value_template: >
        {% set duration_minutes = 30 %}
        {% set last_changed_seconds = as_timestamp(states.sensor.temperature.last_updated) %}
        {% set current_time_seconds = as_timestamp(strptime(states('sensor.datetime'),'%Y-%m-%d, %H:%M')) %}
        {{ last_changed_seconds + duration_minutes * 60 < current_time_seconds }}
  action:
    - service: notify.prowl
      data_template:
        message: "{{ states.sensor.time.state }} Temperature has not changed since 30min "
4 Likes

Thank you very much!! :slight_smile:

I am trying to accomplish same process with shorter code, but it’s not working:

- alias: Sensor notification
  trigger:
    platform: template
    value_template: >
        {{ (as_timestamp(now()) - as_timestamp(states.sensor.szoba_homerseklet.last_changed)) > 180 }}
  action:
    service: notify.notify
    data:
      message: 'There is no update from sensor from last 3min.'

dev-template panels is showing:

{{ now() }}
{{states.sensor.szoba_homerseklet.last_changed}}

2018-11-12 20:08:21.287755+01:00
2018-11-12 19:11:42.860498+00:00: 

Trigger seem to be working correctly:

{{ (as_timestamp(now()) - as_timestamp(states.sensor.szoba_homerseklet.last_changed)) > 180 }}

Gives me True output.

1 Like

You can’t shorten that code. The reason it is so verbose is because we are forced to use sensor.datetime because this is a trigger. You cannot use now() because it does not create a listener for Home Assistant. When home assistant parses a template, it pulls out all the entities to monitor and creates a listener for those entities. Anytime a listener see’s a change, it fires the automation. So in the template you are using, the only entity that is pulled out would be the sensor.szoba_homerseklet. So your automation would only trigger when that item updates. It would never trigger at when now() updates. If you were to use the sensor.datetime object instead of now(), it would update when the datetime changes and when sensor.szoba_homerseklet changes

Anyways, onto your datetime differences:

Now() is in your local timezone
last_changed is in UTC.

But none of that matters because as_timestamp moves them both to UTC. So they will compare properly.

I’m guessing when you say:

You mean it’s not triggering. And if that’s the case it’s because you are trying to shorten the code when you can’t. You need to use the sensor.datetime.

2 Likes

HI,

I use this in most of my presence automations, and it works just fine, without using the sensor.time in the entity_id section of the trigger, or the value_template:

  - condition: template
    value_template: >
      {{ (now() - trigger.from_state.last_changed | default(0)).total_seconds() > 
                                        states('input_number.presence_timer')|int }}

triggering states are like this:

  - alias: Presence Tracking
    id: 'Presence Tracking'
    trigger:
      platform: state
      entity_id:
        - group.person1
        - group.person2
        - group.person3
        - group.person4

whenever the group changes state and it is longer than the time I have set the timer to check, it evaluates true, and fires the action.

Surely the poster could replace the state with the sensor.temperature and the value_template use 30*60?
Unless he wanted it to fire, even when no last_change has happened of course, in which case this template wouldn’t suffice.
This only fires if there has been a minimum of time between the 2 checked times, and not if anything happens sooner.

That’s because it’s a condition @Mariusthvdb. @madrian is trying to use it as a trigger. Conditions do not create listeners, conditions are functions that are run after a trigger. You can use now() in that case.

No, he has to use sensor.time or sensor.datetime. This is just like template sensors. Template sensors do not update when you use now(), neither will triggers. Trigger templates and template sensors are essentially one and the same.

Conditions are executed after the trigger, meaning they do not need an entity_id to update in order to execute. They are executed everytime the automation fires without fail.

Trigger templates and sensor templates only update when a entity_id inside the template updates. now() is not considered a entity_id.

A yes, missed that, sorry.

wonder what would happen if he’d try this then:

 - alias: "Test"
    trigger:
      platform: state
      entity_id: sensor.temperature
    condition:
      condition: template
      value_template: >
        {{ (now() - trigger.from_state.last_changed | default(0)).total_seconds() > 60*30 }}
    action:
      service: notify.prowl
      data_template:
        message: >
          {{states('sensor.temperature') }} Temperature has not changed since 30min
2 Likes

that would work as well. Probably want to get rid of that commented line for the example though. Might confuse people.

1 Like

done, tested locally and it seems to do the job.

I don’t think this will do what the OP wanted. As I understand it, the automation should fire when the sensor’s state has not changed – or to put that another way, when the sensor’s state has stayed the same – for some period of time (e.g., 30 min.) But this will fire when the sensor’s state, or any of its attributes, do change and the previous state change was at least 30 min ago. Those are two different things. E.g., if the sensor’s state changed, and then its state and all of its attributes stayed the same for an hour, and then its state or one of its attributes changed, Petro’s automation would fire 30 minutes after the first change, whereas your automation would not fire until an hour after the first change.

Also, I’m wondering. Can you explain what the default filter is for in this:

{{ (now() - trigger.from_state.last_changed | default(0)).total_seconds() > 60*30 }}

If trigger.from_state.last_changed does not exist, then of course the filter would provide the value zero. But you can’t subtract an integer (zero) from a datetime (now()), so I don’t see how adding the default filter helps. I would think you’d want something the following:

{{ trigger.from_state.last_changed is not defined or
   (now() - trigger.from_state.last_changed).total_seconds() > 30*60 }}

well, tbh, I was in doubt about that. I have set the sensor myself here to see what happens, but sofar I haven’t got a temp sensor that has been the same for 30 min :wink:

If I use a real state and not the trigger variant, it works as expected.

about the attributes: correct, I have another template in my presence trackers for that in place also. Didn’t think it to be necessary here, since the temp sensor only has state temp? No attributes of note that can change

ok, it might not be necessary in the first place, but I could live with your alternative template, which then might be shortened to:

{{ (now() - trigger.from_state.last_changed).total_seconds() > 30*60 }}

although we’d have to see when this triggers. at 30 min, or as you stated above, only after an hour.

for that, the trigger sensor.time would have to be added, and as a consequence the trigger_to replaced by the triggering sensor:

 - alias: "Test"
    trigger:
      - platform: state
        entity_id: sensor.temperature
      - platform: state
        entity_id: sensor.time
    condition:
      condition: template
      value_template: >
        {{ (now() - states.sensor.temperature.last_changed).total_seconds() > 60*30 }}
    action:
      service: notify.prowl
      data_template:
        message: >
          {{states('sensor.temperature') }} Temperature has not changed since 30min

Finally I was able to test Petro’s solution and it’s work nicely.

One thing not worked for first time: date_time generates entity with double underscore? So it is: sensor.date__time.

 - platform: time_date
    display_options:
      - 'date_time'

Yes that’s because whoever made the component named the attribute 'date_&_time' and home assistant removes all invalid characters so you end up with 'date__time'. It’s a poor design but no one has bothered changing it because it works.

1 Like

I m not sure i better off creating new thread, but since it is basically the same topic, i figured i just ask here.
Anybody can help to point out why this isnt working. Seems like the condition not met, so it never triggers.
For record, i ve tried using “states.binary_sensor.motion_porch.attributes.last_triggered” as well, but it doesnt seem to work. What i wanted to achieve is that for the automation to not trigger if last triggered is below 60 secs, to avoid multiple triggers firing at short time.

- alias: notify Gate motion
  trigger:
  - entity_id: binary_sensor.motion_porch
    platform: state
    to: 'on'
  condition:
    - condition: template
      value_template: "{{(as_timestamp(now()) - 
 as_timestamp(states.binary_sensor.motion_porch.last_triggered))>60)}}"
  action:
  - service: notify.tellme
    data:
      message: 'Gate Motion detected'

A binary sensor probably doesn’t have a last_triggered attribute. And, besides, that’s not what you’re asking for. You’re asking that the automation not trigger if the automation hasn’t triggered in the last 60 seconds. So you need to look at the automation’s last_triggered attribute.

      value_template: >
        {{ as_timestamp(now()) -
           as_timestamp(state_attr('automation.notify_gate_motion', 'last_triggered'))
           > 60 }}

Thanks @pnbruckner
i have just figured that i could probably use last_changed instead of last_triggered if i still wanna keep binary sensor as the condition, rather than the automation.
Now i managed to get it to work. Thanks!

Um, I don’t think so. The trigger is evaluated when binary_sensor.motion_porch changes to on. Therefore last_changed would be when it changed to on as well. Then the condition is evaluated, and last_changed would already be the time it just changed to on, not the time it changed (to something other than on) before that. I think you do need to use the automation’s last_triggered attribute.

1 Like

Awesome,

I used the template in node red to restart ESP home module if the Xiaome BLE sensoris offline for more than 60 minutes

searching pays off