Automation condition renders true but it's not

I have set up an automation on the dishwasher door state, if it opens it checks when the operation state sensor was last changed, if within 90 minutes (which means it’s still steaming hot) then there’s a reminder through the Google speaker. Unfortunately the 90 minutes condition always renders true since a week ago, even though the last state change was many hours ago. What am I missing? Here is the code.

alias: Dishwasher Door Reminder
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.dishwasher_door
    from: closed
    for:
      hours: 0
      minutes: 0
      seconds: 10
    to: open
conditions:
  - condition: template
    value_template: >-
      {{ states.sensor.dishwasher_operation_state.last_changed > (now() -
      timedelta(minutes=90)) }}
actions:
  - action: media_player.volume_set
    metadata: {}
    data:
      volume_level: 0.45
    target:
      entity_id: media_player.kitchen_speaker
  - repeat:
      while:
        - condition: state
          entity_id: sensor.dishwasher_door
          state: open
      sequence:
        - action: tts.speak
          metadata: {}
          data:
            cache: true
            media_player_entity_id: media_player.kitchen_speaker
            message: Don't forget to close the dishwasher
          target:
            entity_id: tts.google_translate_en_com
        - delay:
            hours: 0
            minutes: 0
            seconds: 10
            milliseconds: 0
mode: single

Download and post the trace of a run of the automation that demonstrates the error.

And add the last changed state to the notification to be sure.

What I see is that last_changed is UTC and now() is local time. Maybe compare does not do timezone math? what if you do:

 {{ states.sensor.dishwasher_operation_state.last_changed | as_local > (now() -
      timedelta(minutes=90)) }}
1 Like

That should not be an issue.

1 Like

Go to Developer tools → Template and type in

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

{{ now() }}

What’s the output?

1 Like

Yes, that puts both in the same timezone. Thank you and thank you @Edwin_D . This seems to fix the problem.

The state being in UTC, is that something that can be changed or is that because of the API call? (Server being in a different timezone?)

Like Didgeridrew said, the time-zone mismatch probably isn’t the issue. I asked to see the output because I suspect the values are the problem.

Though if using as_local in the condition template solves your problem, great.

Yeah, you’re right. The time difference would only make a bigger difference between now and last changed.

This is the result in dev tools

2025-11-09 08:37:27.197501+11:00

2025-11-09 10:40:00.212106+11:00

And then, in the Template Editor, you still see that the following
renders true?

{{ states.sensor.dishwasher_operation_state.last_changed > (now() -
      timedelta(minutes=90)) }}

It’s crazy, I added the as_local to the condition, then it fixed the problem. Now I removed it but now it still doesn’t render true “did not pass”. It’s exactly as it was, I’m puzzled

It might be that there is a quirk with when and in what circumstances that timestamp is updated.

A trace will tell you why the condition passed or failed.

I will look into that when it happens again. Then I download the output (json) and post it here to unravel? (If I can’t figure it out)

Something struck my mind: I know it happened a long time ago so I assumed it was fixed by now, but there was a time when testing template conditions in the automation editor did not work properly. Is it only the test button in the automation editor giving crazy results or is it really going wrong on execution? The automation trace should be able to tell.

The actual execution gave a positive on the condition while the condition should not have been met. In de test it also said condition passed. Help me understand what I could get from the trace, especially if there’s no actual errors? I am not that familiar with home assistant yet and am trying to understand how to extract more information from the trace

If you can post the JSON, I think it will have the information in it to explain why the condition passed.