Text to Speech Notification to Leave for Appointment

Hi… it is certainly a creative work and very much functionally useful going beyond the technical interest.

I shall try it out during this week and get back.

Appreciate your thoughfulness and initial effort put to get this working.

@Jer78 Thanks for posting your config. I’ve been trying to do the same thing, but I wanted to try and use at from the time trigger. So, instead of the following (I’m using your config here as an example):

- 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 }}'

I would rather like to do the following:

- alias: 'Announce Calendar Leave time'
  trigger:
    platform: time
    at: states.sensor.calc_leave_time.state

That doesn’t seem to work though.

In my own configuration I have the following sensor which is using the google_travel_time sensor called ‘sensor.my_sensor’:

- platform: template
  sensors:
    leave_for_my_sensor:
      value_template: "{{ strptime(states.sensor.my_sensor.attributes.arrival_time, '%H:%M:%S') - strptime(states.sensor.my_sensor.state, '%M') }}"
      friendly_name: My sensor
      unit_of_measurement: time

Its state is e.g. 9 and its attributes.arrival_time is set to '08:10:00', so as a result I would like to get '08:01:00', which is working and I do get that as a result. The problem I’m having is using this value in an automation.

In my automation I’m trying to use it like the following:

trigger:
  - platform: time
    at: sensor.leave_for_my_sensor

That results in the following error:

Invalid config for [automation]: Invalid time specified: sensor.leave_for_my_sensor for dictionary value @ data['trigger'][0]['at']. Got None

I’ve also tried to use it like this (doesn’t work either):

trigger:
  - platform: time
    at: '{{ sensor.leave_for_my_sensor }}'

So, I was wondering why you’re using it like this instead of using at for instance and also if someone here could point me in the right direction to use it in combination with at.

That would not work as you set the platform as time but you use a state for your at trigger.
I would probably change this into a sensors that tracks the minutes before you need to leave. When this drops below a set number (e.g. 5 min) then your automation would trigger

I’m using unit_of_measurement: time in the sensor, so shouldn’t the state be a time object? I’ve only been using Home Assistant for a couple of weeks, so I’m not completely sure if thats correct (probably not, since it’s not working).

Anyway, like I said… I’m new to Home Assistant, so which platform sensor would that be? I’m guessing you would use numeric_state since you mentioned below. Is that correct?

correct, numeric_state is what you would need to use

HI,

because Google is soon to limit its api call further, I’ve tried to rewrite my sensors into a package, enabling some dynamic sensor api calling vs the fixed and permanent sensor settings.

Ive run into some surprises (can have the destination and origin in a sensor, and select these via input_select), cant have that with the Mode…
zones won’t be accepted, same with device_trackers. While they are accepted in the regular Google Traveltime format… Strange it is.

Also, I’d like to have several preset options, but also have the input_select select the state of an input_text, for those destinations not prescribed, Could this be made possible?

For the input_select.text’s id like it to show some preformatted pattern, like [City, Country]. Right now my settings are not working, so how could i change that please?

Please have a look with me below:

##########################################################################################
# Package Google Traveltime
# only feed api with calls while necessary/desired to mitigate api call restrictions
# MtHvdB 07072018
##########################################################################################

homeassistant:
  customize:
    sensor.travel_destination:
      templates:
        icon: >
          if (entities['input_select.travel_mode'].state === 'bicycling') return 'mdi:bike';
          if (entities['input_select.travel_mode'].state === 'driving') return 'mdi:car';
          if (entities['input_select.travel_mode'].state === 'walking') return 'mdi:transit-transfer';
          if (entities['input_select.travel_mode'].state === 'transit') return 'mdi:train';
          return 'mdi:bus';
    sensor.select_travel_destination:
      icon: mdi:login
    sensor.select_travel_origin:
      icon: mdi:logout
    sensor.select_travel_mode:
      icon: mdi:transit-transfer
    input_select.travel_mode:
      templates:
        icon: >
          if (state === 'bicycling') return 'mdi:bike';
          if (state === 'driving') return 'mdi:car';
          if (state === 'walking') return 'mdi:transit-transfer';
          if (state === 'transit') return 'mdi:train';
          return 'mdi:bus';
    sensor.distance_selected_destination:
      icon: mdi:map-marker-distance
      friendly_name: Distance
    sensor.duration_selected_destination:
      icon: mdi:timer
      friendly_name: Duration
    sensor.duration_in_traffic_selected_destination:
      icon: mdi:traffic-light
      friendly_name: In traffic

sensor:
  - platform: google_travel_time
    api_key: !secret google_travel
    mode: sensor.select_travel_mode
    departure_time: now
    name: Travel destination
    origin: sensor.select_travel_origin
    destination: sensor.select_travel_destination

  - platform: template
    sensors:
      select_travel_destination:
        value_template: '{{states.input_select.travel_destination.state}}'
      select_travel_origin:
        value_template: '{{states.input_select.travel_origin.state}}'
      select_travel_mode:
        value_template: '{{states.input_select.travel_mode.state}}'
      distance_selected_destination:
        value_template: '{{states.sensor.travel_destination.attributes.distance}}'
      duration_selected_destination:
        value_template: '{{states.sensor.travel_destination.attributes.duration}}'
      duration_in_traffic_selected_destination:
        value_template: '{{states.sensor.travel_destination.attributes.duration_in_traffic}}'

input_text:
  travel_destination:
    icon: mdi:login
    name: Travel destination
    pattern: [City, Country]
  
  travel_origin:
    icon: mdi:logout
    name: Travel origin
    pattern: [City, Country]
    
input_select:
  travel_destination:
    icon: mdi:login
    name: Travel destination
    options:
      - Select
      - Paris, France
      - Amsterdam, Netherlands
      - Eindhoven, Netherlands
      - Utrecht, Netherlands
      - Brussels, Belgium
      - Berlin, Germany
      - Bayreuth, Germany
      - '{{states.input_text.travel_destination.state}}'
      - zone.home
      - device.tracker.iphone
      - device.tracker.telefoon
    initial: Select

  travel_origin:
    icon: mdi:logout
    name: Travel origin
    options:
      - Select
      - Paris, France
      - Amsterdam, Netherlands
      - Eindhoven, Netherlands
      - Utrecht, Netherlands
      - Brussels, Belgium
      - Berlin, Germany
      - Bayreuth, Germany
      - '{{states.input_text.travel_origin.state}}'
      - zone.home
      - device_tracker.iphone
      - device_tracker.telefoon
    initial: Select

  travel_mode:
    icon: mdi:bike
    name: Travel mode
    options:
      - driving
      - bicycling
      - walking
      - transit
    initial: bicycling

group:
  travel_destination:
    name: Travel destination
    icon: mdi:transit-transfer
    entities:
      - input_select.travel_origin
      - input_text.travel_origin
      - input_select.travel_destination
      - input_text.travel_destination
      - input_select.travel_mode
      - sensor.travel_destination
      - sensor.distance_selected_destination
      - sensor.duration_selected_destination
      - sensor.duration_in_traffic_selected_destination


thanks,
Marius

2 Likes

sorry, @Jer78 but your picture is deleted. can you post it again?

Hello I was happy to find this thread when I came up with the exact same idea.
I especially liked the camera section for displaying nice images.

Hower they don’t appear in the frontend at all. When I click on them on the /dev-state page I don’t see a image either. The state is “idle”.
The log file is empty, I don’t see any errors.

For reference, here is my config: https://github.com/eifinger/homeassistant-config

Does anybody know what is going on?

@eifinger

Google recently has changed the requirement for API keys. Either the static map or the street view didn’t require it before but now they both do. So youd have to create one and add it to your URL.

Check out the references from Google how to format the maps and street views

I have both APIs activated in my API key and I can see that they were never called.
It seems something is wrong with the template part in my sensor definition because:

https://maps.googleapis.com/maps/api/staticmap?center={{sensor.cal_next_appointment_location_google_prepared}}&zoom=17&size=600x300&maptype=roadmap&markers=color:blue
does not work but
https://maps.googleapis.com/maps/api/staticmap?center=München&zoom=17&size=600x300&maptype=roadmap&markers=color:blue
Does work.

What is your sensor.cal_next_appointment_location_google_prepared returning?

Also “München”. At least that’s what the frontend is showing and that’s what I get when I test the template.

I just saw the problem. Sorry I didn’t look hard enough the first time. Change this

{{sensor.cal_next_appointment_location_google_prepared}}

To this

{{states.sensor.cal_next_appointment_location_google_prepared.state}}

1 Like

Thank you!
This works.

My sensor.sys_time is showing the time with 3 hours delay, how can I fix?

@SouzaaThales Do you have the time_zone correctly setup in your config file?

Yep. As you can see, the time_date sensor works very well

image

but sys_time not

image

A quick fix you can do is just add 3 hours to the template sensor so it would look like this:

  sys_time:
    value_template: '{{ (now().strftime("%s") | int + (60*60*3) | timestamp_custom("%Y-%m-%d %H:%M")) }}'

But there’s something with your setup that is not getting local time when calling the now function in the template or the conversion when doing the timestamp_custom. I’d check the jinja docs and see what it suggests for a long term fix.

1 Like

Thank you!

You guys all seem pretty knowledgeable in the Google Calendar component. I have a question for you.

I’ve written an automation which can look at all my calendars, and announce events 30 minutes prior to their start_time on my Google Homes (via TTS). I wish I’d seen this thread before having to work all that out :slight_smile:

My problem is with “all day” events. If I have an all day event scheduled (which I often use for reminders, garbage days, etc), but also have “normal” events on that day, the state of my calendar will remain ‘on’, and focussed on the “all day” event right up until the start time of the “normal” event. I don’t get the chance to see the “normal” event beforehand. On top of this, the state of the calendar remains ‘on’ right through this transition, so I can’t detect a state change “from off to on” for the calendar.

Has anyone else run into this issue?

Here’s my automation if anybody’s interested. It works…with the “all day” event caveat:

- id: CalendarReminders
  alias: Calendar reminders
  trigger:
    # should update every 5 minutes
    - platform: time
      minutes: '/5'
      seconds: '00'
  condition:
    # only announce during waking hours
    - condition: time
      after: '07:00:00'
      before: '22:00:00'
    # only announce when somebody is home
    - condition: state
      entity_id: group.device_trackers
      state: 'home'
  action:
    # First, gather a list of the calendars that have upcoming events close to
    # the allowed delta period, but within the automation interval so we don't
    # announce the same event more than once. The template will look for events
    # that are 1/2 the automation interval on either side of the current time.
    #
    # I couldn't rely on "loop.last" because I don't know which calendar(s) in
    # the list will actually have events that I care about. So they all end
    # with a ','. Then save it to an input_text, the only way I could see to 
    # carry it over to the next action.
    - service: input_text.set_value
      data_template:
        entity_id: input_text.calendars_with_events
        value: >
          {%- set allowed_delta = 30 * 60 -%}
          {%- set automation_interval = 5 * 60 -%}
          {%- set current_time = as_timestamp(strptime(states('sensor.date__time'), '%Y-%m-%d, %H:%M')) |int -%}
          {%- for state in states.calendar -%}
            {%- set event_time = as_timestamp(strptime(state.attributes.start_time, '%Y-%m-%d %H:%M')) |int -%}
            {%- set actual_delta = event_time - current_time -%}
            {%- if (state.attributes.start_time != None) and
                   (state.attributes.all_day == false) and
                   (actual_delta > 0) and
                   (actual_delta <= (allowed_delta + (automation_interval / 2))) and
                   (actual_delta >= (allowed_delta - (automation_interval / 2))) -%}
              {{ state.entity_id }},
            {%- endif -%}
          {%- endfor -%}
    - condition: template
      # If the input_text has no calendars, we don't need to continue.
      value_template: >
        {{ states('input_text.calendars_with_events') != ''}}
    - service: input_text.set_value
      # I know that if we have any calendars, the input_text will end with
      # a blank entry after the last ',' so remove the last field.
      data_template:
        entity_id: input_text.calendars_with_events
        value: >
          {%- for entity_id in states('input_text.calendars_with_events').split(',') -%}
            {%- if entity_id != '' -%}{{ entity_id }}{%- endif -%}
            {%- if loop.revindex0 > 1 -%},{%- endif -%}
          {%- endfor -%}
    - service: script.play_announcement
      # Now that we have a list of calendars, we can finally announce the event(s)
      data_template:
        entities: media_player.kitchen_home, media_player.livingroom_home, media_player.recroom_home
        media: 'http://192.168.2.4:8123/local/calendar-reminder.mp3'
        delay: '00:00:03'
        message: >
          Just a reminder that
          {% for entity_id in states('input_text.calendars_with_events').split(',') %}
            {% if (loop.last) and (not loop.first) %}
              and
            {% endif %}
            {{ state_attr(entity_id, 'friendly_name') }} 
            has {{state_attr(entity_id, 'message') }}
            from {{ strptime(state_attr(entity_id, "start_time"), '%Y-%m-%d %H:%M:%S').strftime('%-I:%M') }}
            until {{ strptime(state_attr(entity_id, "end_time"), '%Y-%m-%d %H:%M:%S').strftime('%-I:%M') }}
            {% if (state_attr(entity_id, 'location') != '') %}
              at {{ state_attr(entity_id, 'location') }}
            {% endif %}
          {% endfor %}

1 Like