Text to Speech Notification to Leave for Appointment

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

I have a calendar specifically for all day events and avoid putting anything on my other calendar for this very reason.

That sucks. I dislike when you have to change your behaviors to suit an automation. It should really be the other way around. I think there should just be an “all_day_events” attribute on the calendar sensor that has a delimited list of the all-day events, or alternatively, two sensors: one specifically for all-day events, so you can still get ‘off’ to ‘on’ triggers. But honestly, what good is a calendar trigger that fires at midnight? I can just as easily have a daily trigger that checks the calendar.

I am a software developer, though not a Python expert by any stretch, but I couldn’t figure out what was going on in there. If somebody can get me up to speed, I’d happily work on this.

I was about to log a bug for this issue, when I found this old bug about the same thing:
https://github.com/home-assistant/home-assistant/issues/6076

The fix was to ignore events that have their availability set to “free”, which is all “all day” events by default. You can set this option per-calendar by setting “ignore_availability” to false in google_calendars.yaml. It isn’t how I would have chosen to fix this issue, but my automation now works as I intended.

I guess that works. Thanks for pointing it out. I do agree, it’s not the way I’d do it either. I was getting annoyed anytime my wife put an all day event on our calendar and the announcement would go off around midnight. I finally got her into the habit of just putting it on a “family” calendar to keep them separate.

I think my automation would still have a problem if there were ever appointments on the same calendar closer together than the 30-minutes in advance that I announce the reminder. It would only announce the reminder at exactly 30 minutes prior to the event (so I don’t announce the same event multiple times), so an event that only shows up in the sensor less than 30 minutes before its start_time would not be announced. I would prefer to keep track of each event that a reminder is announced for, but I haven’t figured out how to do that yet.