Dynamic drive time reminders with Home Assistant

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:

  • Retrieve all events in the next 4 hours from my work and personal calendars
  • Eliminate all-day events, events with no location, or events I’ve already been reminded of (stored in a helper input sensor called last_notified_event_id)
  • For the remaining events, retrieve Waze travel time from my current location to the event location (using entity location versus a static address or lat/long is important because I might not be at home, affecting travel time)
  • Determine departure time (start time minus travel time minus 5 minutes of wiggle room)
  • Determine reminder time (30 minutes prior to departure time)
  • Send a notification to my phone alerting me to the upcoming event, estimated travel time, and the time I need to leave
  • Store a synthetic “event ID” (the start time and summary) in an input helper sensor, so we can make sure I’m not reminded again

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

Leave a Reply

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