CodeHome Assistant

Dynamic drive time reminders with Home Assistant

· 3 min read

Tired of manually checking Google Maps and your calendar to figure out when to leave for your next meeting?

I recently realized that Home Assistant already has all the necessary pieces – my current geolocation, calendar events, and Waze travel time – so I put together an automation to provide real-time notifications telling me exactly when I need to head out the door.

It’s pretty simple, following these steps every five minutes:

Note: I’m pretty new to Home Assistant templating (though a past life as a Perl dev has hammered YAML syntax into my head irreversably) so there may be stupidity in this automation. But, it works for me (so far!)

alias: Drive time alert
description: ""
# fire every five minutes
triggers:
  - trigger: time_pattern
    minutes: /5
conditions: []
actions:
  - action: calendar.get_events
    metadata: {}
    data:
      duration:
        hours: 4
        minutes: 0
        seconds: 0
    target:
      entity_id:
        - calendar.personal_calendar
        - calendar.work_calendar
    response_variable: cal_events
  - repeat:
      for_each: "{{ cal_events.values() | map(attribute='events') | sum(start=[]) }}"
      sequence:
        - variables:
            thisEventId: "{{ repeat.item.start }} {{ repeat.item.summary }}"
        - condition: template
          value_template: |
            {{ repeat.item.location is not none and
               (repeat.item.location | string | trim != "") and
               'T' in (repeat.item.start | string) and
               states('input_text.last_notified_event_id') and
               thisEventId != states('input_text.last_notified_event_id') }}
        - data:
            origin: person.mike
            destination: "{{ repeat.item.location }}"
            region: us
          response_variable: waze_eta_result
          continue_on_error: false
          action: waze_travel_time.get_travel_times
        - variables:
            wiggle_room: "{{ 5 }}"
            waze_duration: "{{ waze_eta_result['routes'][0].duration | round(0) }}"
            start_time: "{{ repeat.item.start }}"
            start_time_friendly: "{{ as_datetime(start_time).strftime('%I:%M %p') }}"
            location: "{{ repeat.item.location }}"
            summary: "{{ repeat.item.summary }}"
            departure_time: >-
              {{ as_datetime(start_time) - timedelta(minutes=waze_duration) -
              timedelta(minutes=wiggle_room) }}
            departure_time_friendly: "{{ as_datetime(departure_time).strftime('%I:%M %p') }}"
            reminder_time: "{{ as_datetime(departure_time) - timedelta(minutes=30) }}"
        - condition: template
          value_template: |
            {{ as_datetime(reminder_time) <= now() }}
        - action: notify.mobile_app_pixel_6_mike
          metadata: {}
          data:
            data:
              ttl: 0
              priority: high
            message: >-
              Drive time to your next appointment ({{summary}}) is 
              {{waze_duration}} minutes. Depart by {{departure_time_friendly}}
              for arrival by {{start_time_friendly}}.
            title: Drive Time Alert - {{ repeat.item.summary }}
        - action: input_text.set_value
          metadata: {}
          data:
            value: "{{ thisEventId }}"
          target:
            entity_id: input_text.last_notified_event_id
mode: single

9 Comments

      1. No, se nelle 4 ore hai più di un appuntamento, ogni 5 minuti continua a notificare perchè hai messo un solo last_notified_event_id che sarà impostato sull’ultimo appuntamento notificato. Come si può risolvere?

          1. Questa modifica dovrebbe risolvere il bug. Dopo aver effettuato ulteriori testing, aggiornerò il post. Grazie!


            --- origAutomation 2025-12-10 14:29:45
            +++ origAutomation 2025-12-12 13:11:32
            @@ -23,12 +23,16 @@
            - variables:
            thisEventId: "{{ repeat.item.start }} {{ repeat.item.summary }}"
            - condition: template
            - value_template: |
            + value_template: >
            + {% set notified = states('input_text.notified_events') %}
            +
            + {% set notified_list = notified.split(',') if (notified not in
            + ['unknown', 'unavailable', '']) else [] %}
            +
            {{ repeat.item.location is not none and
            (repeat.item.location | string | trim != "") and
            'T' in (repeat.item.start | string) and
            - states('input_text.last_notified_event_id') and
            - thisEventId != states('input_text.last_notified_event_id') }}
            + thisEventId not in notified_list }}
            - data:
            origin: person.mike
            destination: "{{ repeat.item.location }}"
            @@ -65,8 +69,20 @@
            - action: input_text.set_value
            metadata: {}
            data:
            - value: "{{ thisEventId }}"
            + value: >-
            + {% set current = states('input_text.notified_events') %} {% set
            + current_list = current.split(',') if (current not in
            + ['unknown', 'unavailable', '']) else [] %}
            + {% set cutoff = now() - timedelta(hours=24) %} {% set ns =
            + namespace(valid_events=[]) %} {% set ns.valid_events = [] %} {%
            + for event_id in current_list %}
            + {% set event_time = event_id.split(' ')[0] %}
            + {% set parsed_time = as_datetime(event_time) %}
            + {% if parsed_time is not none and parsed_time > cutoff %}
            + {% set ns.valid_events = ns.valid_events + [event_id] %}
            + {% endif %}
            + {% endfor %} {{ (ns.valid_events + [thisEventId]) | join(',') }}
            target:
            - entity_id: input_text.last_notified_event_id
            + entity_id: input_text.notified_events
            mode: single

  1. Purtroppo non funziona, la nuova variabile notified_events continua ad accodarsi ogni volta che viene attivata l’automazione. Ci sto provando da giorni ma non sembra essere la soluzione! Help

Leave a comment

Your email address will not be published. Required fields are marked *