
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
Fantastico!!!! Grazie mille ho preso spunto per replicare con qualche mio accorgimento questa funzione!!!
Prego, buon divertimento!
Però funziona solo se hai un appuntamento, se ne hai più di uno continua ogni 5 minuti a notificarlo
Hai più calendari? Mi sembra di aver già visto questo bug.
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?
Hmm, ci darò un’occhiata quando potrò. Credo che ci sia una soluzione semplice.
Grazie aspetto
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
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