Text to Speech Notification to Leave for Appointment

I got most of this project working. I’m sure there are a few bugs, but I’ll have to leave that for another time. In the meantime, a mostly working Travel Time with Google Maps and Street View:

First you’ll need to set up the Google Travel Time and Calendar components. In addition to the instructions on the component page, you should enable the Google Street View API.

The next part is to add some sensors:

 - platform: google_travel_time
   api_key: YOUR_GOOGLE_API_HERE
   origin: zone.home
   destination: sensor.new_cal_location        
   options: 
     arrival_time: sensor.cal_start_time
 - platform: template
   sensors:
     cal_title:
       value_template: '{{ states.calendar.jeremy.attributes.message }}'
       friendly_name: 'Title'
     cal_location:
       value_template: '{{ states.calendar.jeremy.attributes.location }}'
       friendly_name: 'Location'
     new_cal_location:
       value_template: '{% if is_state("sensor.cal_location", "None") %}{{ zone.work }}{% else %}{{ states.calendar.jeremy.attributes.location }}{% endif %}' 
       friendly_name: 'Location'
     cal_start_time:
       value_template: '{{ states.calendar.jeremy.attributes.start_time }}'
       friendly_name: 'Start Time'
     calc_leave_time:
       value_template: '{{ (as_timestamp(states.calendar.jeremy.attributes.start_time) - states.sensor.google_travel_time__driving.attributes.duration.split(" ")[0] | int *60 ) | timestamp_custom("%Y-%m-%d %H:%M") }}'
       friendly_name: 'Leave Time'
       unit_of_measurement: 'time'
     sys_time:
       value_template: '{{ (now().strftime("%s") | int | timestamp_custom("%Y-%m-%d %H:%M")) }}'
       unit_of_measurement: 'time'

I tried playing with the above to handle the errors when there is either no calendar item or no location in one to look up zone.work. I have to test this more, as it wasn’t quite functioning. Maybe someone can help there.

Next, add some input_boolean’s to toggle the notification options:

input_boolean:
  announce_time_to_leave:
    name: Announce over Living Room Sonos
    initial: on
    icon: mdi:speaker-wireless
  display_time_to_leave:
    name: Display with Persistent Notification
    initial: on
    icon: mdi:cards-variant

Now comes the automation part. I have one for the voice announcement to my Living Room Sonos and the other as a persistent notification:

  - alias: 'Announce Calendar Leave time'
    trigger:
      platform: time
      minutes: '/1'
      seconds: 0
    condition:
      condition: and
      conditions:
        - condition: template
          value_template: '{{ states.sensor.sys_time.state == states.sensor.calc_leave_time.state }}'
        - condition: state
          entity_id: input_boolean.announce_time_to_leave
          state: 'on'
    action:
      - service: media_player.sonos_snapshot
        data_template:
          entity_id: "media_player.living_room"
      - service: tts.google_say
        data_template:
          entity_id: "media_player.living_room"
          message: 'Excuse me. It is now time to leave for {{ states.calendar.jeremy.attributes.message }}  It will take you {{ states.sensor.google_travel_time__driving.attributes.duration }} travel time.'
      - delay: '00:00:{{ states.media_player.living_room.attributes.media_duration | int }}'
      - service: media_player.sonos_restore
        data_template:
          entity_id: "media_player.living_room"
  - alias: 'Display Calendar Leave time'
    trigger:
      platform: time
      minutes: '/1'
      seconds: 0
    condition:
      condition: and
      conditions:
        - condition: template
          value_template: '{{ states.sensor.sys_time.state == states.sensor.calc_leave_time.state }}'
        - condition: state
          entity_id: input_boolean.display_time_to_leave
          state: 'on'
    action:
      service: persistent_notification.create
      data:
        message: 'It is now time to leave for {{ states.calendar.jeremy.attributes.message }}  It will take you {{ states.sensor.google_travel_time__driving.attributes.duration }} travel time.'
        title: "Calendar Event"

Now add some cameras to display the google maps and street view. Don’t forget to add your API Key:

camera:
 - platform: generic
   name: Destination
   still_image_url: https://maps.googleapis.com/maps/api/staticmap?center={{states.calendar.jeremy.attributes.location}}&zoom=17&size=600x300&maptype=roadmap&markers=color:blue
   limit_refetch_to_url_change: true
 - platform: generic
   name: Street View
   still_image_url: https://maps.googleapis.com/maps/api/streetview?size=600x300&location={{states.calendar.jeremy.attributes.location}}&key=YOUR_API_KEY
   limit_refetch_to_url_change: true

Finally, add some groups. I used the customize section as well (optional):

 calendar_view:
  view: yes
  name: Calendar
  entities:
   - group.next_appointment
   - camera.street_view
   - camera.destination
   
 next_appointment:
  view: no
  name: Next Appointment
  entities:
   - sensor.cal_title
   - sensor.cal_location
   - sensor.cal_start_time
   - sensor.google_travel_time__driving
   - input_boolean.announce_time_to_leave
   - input_boolean.display_time_to_leave

And that’s it!