8 m
White Google Nest speaker on dekstopI like to keep my mind clear and lose myself completely in the things I am doing. For that reason, it happens sometimes that I almost miss an appointment and have to hurry to be on time. Fortunately, I have found a solution that always reminds me of what’s on my calendar. A spoken announcement on my Nest speakers! Here is how I made it.

There are a few things you should know before we start: The announcements will interrupt any music that is playing. I personally only use my Nest speakers to talk to and organise things, but that may be different for you. If that doesn’t bother you or, like me, you have a Nest speaker dedicated for this purpose, then there are no issues. Finally, every time a notification is sent, a sound is played to indicate that a cast session has started. This is relatively easy to fix, but it won’t work well together with the automations below. I did my best to work around this issue, but when you’re using your Nest speaker to listen to music a lot, your experience won’t be the same.

In this article, I will help you to make the following things:

  • A date and time sensor in iso format to easily calculate time
  • A sensor which turns on 15 minutes before the event starts
  • The script for the actual announcement
  • Automations to trigger the announcement based on time

I assuming that you have already set up a calendar within your Home Assistant. I connected my Google Calendar. Instructions how to connect this calendar can be found in the Home Assistant documentation.

Furthermore, I am using the Cloud TTS service by Nabu Casa for more natural sounding voices. You may prefer another TTS integration, or maybe you are using the default Google Translate TTS, which is activated by default. If so, you can change the service and parameters in the script below.

Date and time sensor

I use relative time in the announcement. For example, “Your event starts in 4 minutes.” To calculate this relative time easily, I use the date and time sensor in the ISO format. You can add this sensor to your configuration.yaml file. For details, see the Time and Date documentation . Below is an example with the minimum configuration needed for the announcements to work:

# Example date and time ISO sensor
sensor:
  - platform: time_date
    display_options:
      - 'date_time_iso'

After adding and saving, check your configuration and restart Home Assistant.

Offset sensor

There is an option for an offset in the attributes of the sensor for your calendar. However, my experience is that it often does not work as accurately as is desirable. This causes issues for the automation which triggers the announcement. That is why I made my own binary sensor that switches on fifteen minutes before the start of the appointment. You can copy and paste this into your configuration.yaml file. Don’t forget to change the entity ID of the calendar.

# Binary offset sensor for your calendar
binary_sensor:
  - platform: template
    sensors:
      calendar_event_offset:
        value_template: "{{ (float(state_attr('calendar.YOUR_CALENDAR', 'start_time') | as_timestamp()) - float(states.sensor.date_time_iso.state | as_timestamp())) | float > -59 and (float(state_attr('calendar.YOUR_CALENDAR', 'start_time') | as_timestamp()) - float(states.sensor.date_time_iso.state | as_timestamp())) | float 

This sensor converts the time from the ISO sensor above and the start time of the appointment in your calendar to Unix time. If this time is less than 900 and more than 59 seconds, the sensor will turn on.

Script for the announcement

Now it's time to paste the script that makes the actual announcement into your scripts.yaml file. Below I briefly explain what I have made and how the script responds to certain elements of your calendar events:

  • If the event has yet to start, it is referred to as 'your next event' and the relative time in minutes is stated.
  • If the event starts now or has already started, the word 'next' disappears from the announcement and tells you that the event 'starts now' or how long the event has been in progress in minutes.
  • If the location of the appointment contains the term FaceTime, Google Duo, Online, Teams, WhatsApp or Zoom, it will say, for example, 'your next Zoom meeting. If the location contains the word 'Phone', it will be referred to as 'Your call'.
  • If one of the terms in the point above is not in the location field, the location will be announced after the relative start time. If nothing is entered for the location, this will be skipped.
  • If anything is entered in the event notes, it will be read at the very end.

The script for the actual announcement can be found below. After changing the entity ID for your own calendar and media player, you can paste it directly into your script.yaml file.

announce_next_calendar_event:
  alias: Announce next calendar event
  sequence:
  - service: tts.cloud_say
    data_template:
      entity_id: media_player.YOUR_MEDIA_PLAYER_ENTITY_ID
      message: "{% set event_name = state_attr('calendar.YOUR_CALENDAR', 'message') %}{% set event_location = state_attr('calendar.YOUR_CALENDAR', 'location') %}{% set event_start = ((float(state_attr('calendar.YOUR_CALENDAR', 'start_time') | as_timestamp()) - float(states('sensor.date_time_iso') | as_timestamp())) / 60) %}{% set event_started = ((float(states('sensor.date_time_iso') | as_timestamp()) - float(state_attr('calendar.YOUR_CALENDAR', 'start_time') | as_timestamp())) / 60) | round(0) %}{% set event_description = state_attr('calendar.YOUR_CALENDAR', 'description') %}Your {% if event_start | float > 0 %}next {% endif %}{% if 'Teams' in event_location or 'Online' in event_location or 'FaceTime' in event_location or 'Zoom' in event_location or 'WhatsApp' in event_location or 'Google Duo' in event_location %}{{ event_location }} meeting{% elif 'Phone' in event_location %}call {% else %}event{% endif %}, {{ event_name }}, {% if event_start | float 

Automations

Before we start with the automations, don't forget to reload your template entities and your scripts. You can do this at Configuration> Restart. If the log does not contain any errors, you can copy the two automations below to your automations.yaml or paste them into a new automation via the yaml mode in the interface.

When the next event almost starts

The first automation starts when the sensor with the offset turns on; 15 minutes before your appointment starts. This checks whether another appointment is already in progress. A verbal reminder for your next appointment is not desired in such a case.

- alias: Announcement - Next calendar event
  description: ''
  trigger:
  - platform: state
    entity_id: binary_sensor.calendar_event_offset
    from: 'off'
    to: 'on'
  condition:
  - condition: state
    entity_id: calendar.YOUR_CALENDAR
    state: 'off'
  action:
  - service: script.announce_next_calendar_event
    data: {}
  mode: single

When the next event starts now or has already started

Unfortunately, the integration for the Google Calendar is not as precise as I would have liked. As a result, it can happen that two events that are scheduled against each other are not immediately loaded or the sensor with the offset does not turn on. To start an announcement anyway in these situations, I created the automation below that starts when the name of an event is updated while that event is already in progress.

- alias: Announcement - Next calendar event starts
  description: ''
  trigger:
  - platform: state
    entity_id: calendar.YOUR_CALENDAR
    attribute: message
  - platform: state
    entity_id: calendar.YOUR_CALENDAR
    from: 'off'
    to: 'on'
  condition:
  - condition: state
    entity_id: binary_sensor.calendar_event_offset
    state: 'off'
  - condition: state
    entity_id: calendar.YOUR_CALENDAR
    state: 'on'
  action:
  - service: script.announce_next_calendar_event
    data: {}
  mode: single

If you have paste both of these automations in your Home Assistant, you can run them to test whether it works. If you added them to your automations.yaml file, don't forget to reload your automations first.

Getting rid of the cast chime

If, like me, you are thinking about more announcements, then the sound you hear when starting a cast session on a Google Nest speaker is very annoying. Fortunately, with Home Assistant there is an easy way to get rid of that sound. I found the solution in this topic from the Home Assistant forum . After five minutes of inactivity, the cast session will end. So the trick is to have a silent file playing every few minutes to keep the casting session active. That way no more start sounds when casting a sound file. This only will work if your Home Assistant is reachable from the internet through a secure connection.

There are a small number of snags to this automation, such as interrupting music or announcements. I have taken this into account in the automation below. The silent sound file is below.

# Automation to keep cast session active
-  alias: Keep cast active
  description: ''
  trigger:
  - platform: time_pattern
    hours: '0'
    minutes: '2'
    seconds: '20'
  - platform: state
    entity_id: media_player.YOUR_MEDIA_PLAYER
    from: playing
    for: 00:04:30
  - platform: state
    entity_id: media_player.YOUR_MEDIA_PLAYER
    from: unavailable
  - platform: state
    entity_id: media_player.YOUR_MEDIA_PLAYER
    to: 'off'
    for: 00:00:30
  condition:
  - condition: template
    value_template: "{{ not is_state('media_player.YOUR_MEDIA_PLAYER', 'playing' }}"
  action:
  - service: media_player.play_media
    data:
      entity_id: media_player.YOUR_MEDIA_PLAYER
      media_content_id: https://YOUR_HA.ADDRESS/local/silence.mp3
      media_content_type: audio/mp3
  mode: single

You can download the file with silence below. You need to place this file in the folder 'www' inside the folder where your configuration.yaml is located. The most easy way to do this is through Samba. This video from Smart Home Junkie explains how to set it up.

Download silence.zip (2 KB)

Announcement chime

The announcement chime that can be heard in the video at the top of the page is worth a whole article by itself. If you still would like to use this bell, you can add the following lines at the top of the 'actions' section of both automations:

  - service: media_player.play_media
    data:
      entity_id: media_player.JOUW_MEDIASPELER
      media_content_id: https://YOUR_HA.ADDRESS/local/chime.mp3
      media_content_type: audio/mp3
  - wait_template: '{{ is_state(''media_player.JOUW_MEDIASPELER'', ''playing'') }}'
  - wait_template: '{{ is_state(''media_player.JOUW_MEDIASPELER'', ''idle'') }}'

You can download the chime below and also place it in the 'www' folder.

Download chime.zip (41 KB)

No announcements when something is already playing

When you don't want to hear your calendar events announced when something is already playing on your Nest speaker, just add the following condition to your automations:

  - condition: template
    value_template: "{{ not is_state('media_player.YOUR_MEDIA_PLAYER', 'playing') }}"

Things to keep in mind

When you use the goals functionality of Google Calendar, a text will be read at the end of the announcement with a warning about changing the event. This notes can be found in the notes of the event and can easily be avoided by adding it as a condition to the announcement.

{% if not 'function Goals' in state_attr('calendar.YOUR_CALENDAR', 'description' %}

You can do the same with many other things, such as travel advice or exclude certain events from these announcements.

Finally, it can be useful to put the automations of the announcements on your dashboard or to make it possible to switch them both off simultaneously with an input boolean. I imagine there are times when you don't want to hear your calendar announcements.

This is all! You should now have your own spoken calendar announcements on your Google Nest speaker. Are you struggling, do you have questions or improvements or do you have a different purpose for your announcements? I'd love to hear them in the comments! 😄