The situation:
- Your garbage collection company provides you with yearly electronic calendar data for the Garbage Days.
- You wish to use HA’s Google Calendar integration for this.
- You need early notifications (i.e., before midnight when Garbage Day begins), say at 5 p.m. the day before Garbage Day.
Unfortunately, this ain’t as easy as it sounds, because:
- You need to split up your Google Calendar(s).
- Google calendar search is too dumb to allow sophisticated searches (i.e. “give me only the events for residual waste and hazardous waste collection”).
- HA only sees one (the next) calendar event at a time.
- HA can’t handle overlapping events.
- You don’t (yet) know how to set all this up.
The solution
Well, here’s how I did it. YMMV, but at least you should get some ideas out of it!
My situation:
- My garbage collector delivers me a yearly
.ics
file with the dates (whole-day events) for residual waste, biodegradable waste, waste paper, and packaging waste. Also, every few months, there is a bring-in event for hazardous waste, which occurs at different times (so not a whole-day event). - I use a separate (newly created) Google calendar for this, and import the
.ics
file once a year manually. - I only wish to automate the events for residual waste (collected every 2 weeks) and hazardous waste (bring-in).
- Garbage Day shall be announced (and shown on a sensor) at 1700 hrs (5 p.m.) and 1900 hrs (7 p.m.) on the day before, so I have time to put out the rubbish bin (or trash can).
- Garbage Day sensors shall activate (
on
) as above, and de-activate (off
) on Garbage Day at 1700 hrs (5 p.m.), so that I can set up a “Did you haul the trash can in yet?” automation. - Bring-in events for hazardous waste shall be announced one hour before, so I have time to put it into the car and drive over.
The How-To
Prepare the Google Calendar stuff
-
Hop over to your online Google calendar and create a new calendar. I called mine “Abfuhrkalender” (waste disposal calendar) since I live in Germany and other people in the household might not be fluent in English.
-
Now import the
.ics
file you got from your garbage collection company into this new calendar, NOT into your normal calendar. (Remember what I said about splitting, and overlapping events.) -
Set up HA’s Google Calendar Integration, if you haven’t already.
-
Restart HA.
-
In your
config
folder, you will now have a filegoogle_calendars.yaml
. Open it in a text editor and look for your newly created waste disposal calendar item. This will usually have a longcal_id
and look somehow like this:- cal_id: [email protected] entities: - device_id: abfuhrkalender ignore_availability: true name: Abfuhrkalender track: true
-
Now go and split this into several “sub-calendars” for the different waste categories you are interested in, one for each category. Mine are
Restmüll
(residual waste) andProblemmüll
(hazardous waste).We “split” the main calendar into entities having different
device_id
s by setting up searches that fish out just the entries we’re interested in. My calender entries look like “Restmüll in Krumbach” and “Problemmüll in Krumbach”, so I set up searches for “Restmüll” and “Problemmüll” to get two new calendars in HA calledcalendar.restmuell
andcalendar.problemmuell
:- cal_id: [email protected] # Possible: 'Restmüll', 'Problemmüll', 'Bioabfall', 'Papiertonne', 'Gelbe Tonne' entities: - device_id: restmuell ignore_availability: true name: Restmüll track: true search: 'Restmüll' - device_id: problemmuell ignore_availability: true name: Problemmüll track: true search: 'Problemmüll'
Note that I deleted the original
abfuhrkalender
entry, to avoid UI clutter and because it could contain overlapping entries.Note also that Google’s calendar search is dumb and can’t search for parts of a word. I could otherwise have gotten both event types by searching for “müll” (contained in the words “Restmüll” and “Problemmüll”).
-
Restart HA.
-
Try out the new calendars “Restmüll” and “Problemmüll” shown in the UI and check if you can see the next upcoming event in these. You might want to set up a few dummy events in your Google calendar for testing.
Make intelligent sensors with pre-warning
-
Now it’s time to set up a few sensors, one for each new garbage sub-calendar. So you can see in the UI that Garbage Day (or a waste-bring-in event) is coming.
-
Open your
configuration.yaml
and add these two new binary sensors:binary_sensor: # Garbage Day sensors - platform: template sensors: restmuell: friendly_name: 'Restmüll' icon_template: > {% if is_state('binary_sensor.restmuell', 'on') %} mdi:delete-alert {% else %} mdi:delete-outline {% endif %} # sensors need their entities declared, so they can watch them # using sensor.date_time (or sensor.time) makes it update every minute entity_id: - sensor.date_time - calendar.restmuell # ON 7 hours (25200s) before all_day event = 17:00 the day before, and OFF at 17:00 on the day, # or 1 hour (3600s) before normal event (Problemmüll) # CAREFUL: Binary sensors need true/false as input, NOT UI niceties like on/off or the like! value_template: >- {% set calendar = 'calendar.restmuell' %} {# Adapt these for your needs #} {% set seconds_before_all_day = 25200 %} {% set seconds_before_end_all_day = 25200 %} {% set seconds_before_single = 3600 %} {% set start = state_attr(calendar,'start_time') %} {# Prevent error when no calendar event (we won't have a start_time then) #} {% if start != None %} {% set _now = now().timestamp() %} {% set start = as_timestamp(start) %} {% set end = as_timestamp(state_attr(calendar,'end_time')) %} {% if _now < end %} {% if state_attr(calendar,'all_day') %} {{ _now < end - seconds_before_end_all_day and start - _now < seconds_before_all_day }} {% else %} {{ start - _now < seconds_before_single }} {% endif %} {% else %} false {% endif %} {% else %} false {% endif %} problemmuell: friendly_name: 'Problemmüll' icon_template: > {% if is_state('binary_sensor.problemmuell', 'on') %} mdi:delete-alert {% else %} mdi:delete-outline {% endif %} # sensors need their entities declared, so they can watch them # using sensor.date_time (or sensor.time) makes it update every minute entity_id: - sensor.date_time - calendar.problemmuell # ON 7 hours (25200s) before all_day event = 17:00 the day before, and OFF at 17:00 on the day, # or 1 hour (3600s) before normal event (Problemmüll) # CAREFUL: Binary sensors need true/false as input, NOT UI niceties like on/off or the like! value_template: >- {% set calendar = 'calendar.problemmuell' %} {# Adapt these for your needs #} {% set seconds_before_all_day = 25200 %} {% set seconds_before_end_all_day = 25200 %} {% set seconds_before_single = 3600 %} {% set start = state_attr(calendar,'start_time') %} {# Prevent error when no calendar event (we won't have a start_time then) #} {% if start != None %} {% set _now = now().timestamp() %} {% set start = as_timestamp(start) %} {% set end = as_timestamp(state_attr(calendar,'end_time')) %} {% if _now < end %} {% if state_attr(calendar,'all_day') %} {{ _now < end - seconds_before_end_all_day and start - _now < seconds_before_all_day }} {% else %} {{ start - _now < seconds_before_single }} {% endif %} {% else %} false {% endif %} {% else %} false {% endif %}
EDIT:
value_template
modified as per a great simplification by @123—thank you!
EDIT 2: Changed icons frommdi:trash-can
/mdi:trash-can-outline
tomdi:delete-alert
/mdi:delete-outline
. I simply like these better. -
There are a few noteworthy pitfalls here:
- HA takes 15 minutes to update the calendar—important for testing.
- The sensor icon might take an extra minute to update in the UI, since we base it on the
sensor.date_time
entity. This sensor needs to be there already! If it is not, add it:
By modifying the code above, you could also use an existingsensor: - platform: time_date display_options: - 'date_time'
sensor.time
instead of thesensor.date_time
. - I recommend naming the binary sensors after your (sub-)calendar names, so nobody gets confused.
- I set the “pre-warning” time for all-day events to 7 hours (=25200 seconds), so the sensors would go to the “on” state 7 hours before midnight for an all-day event. You might want to change all values
25200
to something else for your case. - I set the “pre-warning” time for timed events to 1 hour (=3600 seconds), you also might want to change that.
- I set a local variable
calendar
within the value template. This is just to make it easier modifying the code, and avoid repetitions. - Whenever there is no new event coming up in your calendar, we don’t have attributes like
start_time
andend_time
, so there is additional logic to avoid this case. (No events = no Garbage Day.) - When experimenting yourself, remember that binary sensors need
true
/false
as input, not fancy UI niceties likeOn
/Off
,on
/off
or the like! Errors like these are hard to diagnose, since HA’s template tester will accept such values and show values that look ok but aren’t! - The code might seem blown in parts, but I knowingly let seemingly unneded stuff in—the garbage company might decide for different types of events in their next calendar, or Google’s calendar search might get cleverer, who knows?
-
Restart HA to activate the new sensors. You did perform a configuration check, right?
-
Make a few test entries in your Google waste calendar and try out if the sensors work.
-
You should see the calendar switch to
On
while the actual event is due. (Verify by clicking on the calendar name and check its event attributes.) -
You should see the corresponding sensors switch on/off (change their trash can symbol) at the specified pre-warning times.
Time for automations!
Our sensors are working now, so let’s make some great automations that use them!
- For my “Restmüll” calendar (or any garbage whole-day events), I wish to be reminded by audible (TTS) alerts at 1700 hrs (5 p.m.) and 1900 hrs (7 p.m.) the day before Garbage Day, so putting out the rubbish bin (or trash can) won’ŧ be forgotten. I’d also like a reminder on Garbage Day to bring the trash can back in.
- My “Problemmüll” calendar should remind me one hour before the bring-in event.
So let’s go and put these in:
-
Tomorrow is Garbage Day!
# Garbage Day coming up! # the sensor switches to "on" at 17:00 the day before # so we get an alert at 17:00 and 19:00 hrs - alias: 'Müllabfuhr Restmüll' trigger: - platform: state entity_id: binary_sensor.restmuell to: 'on' - platform: state entity_id: binary_sensor.restmuell to: 'on' for: '02:00:00' action: - service: script.say_next_calendar_event data_template: calendar: calendar.restmuell skip_duration: true language: 'de-DE' message: "Erinnerung!"
-
Did you haul the trash can back in yet?
# Did ya haul in the rubbish bin yet? # the sensor switches to "off" on garbage day at 17:00 # so we get an alert at 17:00 and 19:00 hrs - alias: 'Mülleimer reingeholt?' trigger: - platform: state entity_id: binary_sensor.restmuell to: 'off' - platform: state entity_id: binary_sensor.restmuell to: 'off' for: '02:00:00' condition: - condition: template value_template: "{{ state_attr('calendar.restmuell', 'all_day') == true }}" action: - service: script.say data_template: audiofile: 'picotts-alert.wav' language: 'de-DE' message: "Hast du den Müll-eimer schon rein-ge-holt?"
- You can probably skip the
condition
—it is just for unlikely case the garbage collectors ever switch to non-all-day events. - Don’t be surprised about the odd spelling of the
message
—it is just so to make PicoTTS better understandable.
- You can probably skip the
-
Hazardous waste (bring-in) events
# Special (bring-in) events for hazardous waste; time & location can change - alias: 'Müllabfuhr Problemmüll' trigger: - platform: state entity_id: binary_sensor.problemmuell to: 'on' action: - service: script.say_next_calendar_event data_template: calendar: calendar.problemmuell skip_duration: true language: 'de-DE' message: "Erinnerung!"
Conclusion
Phew. This has gotten lengthy, but I thought a newbie should be able to follow. Excuses to all the pro’s out there.
And I’m impressed you held out with me!
This post showed how to …
- integrate and cleverly split Google calendars for automation within HA.
- make binary sensors to “pre-alert” before an event actually takes place.
- use these sensors in automations.
Let me know …
- how I could possible improve this code without losing functionality.
- the errors I probably made.
- how you modified and used this kind of workaround!