Calendar event announcements on Nest speakers
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())) | floatThis 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 | floatAutomations
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: singleWhen 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: singleIf 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: singleYou 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.
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.
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! 😄
Questions? Or how did you do it?