In this article I show how to import a list of appointments, process them and then save them in ICS format.
Background
Bremer Stadtreinigung offers the waste collection dates for download as ICS file and as CSV file. Unfortunately there are two separate dates for residual waste and organic waste although both are collected on the same day.
Since I also integrate the dates into my Smarthome to receive notifications about them, I also want them to be in a certain format in the calendar. Details about the integration will follow in a later article.
The Python script
The finished script can be found here on Github. You need at least Python 3.6 because I use f-strings.
Imports
First the required modules are imported. ics
and arrow
can be installed via pip
, the other modules are included in the standard library.
|
|
csv
: Read and write CSV filesics
: Read and write ICS filesarrow
: extended functions for time objectsdateutil.tz
: Time zone definitionsdatetime
: Standard functions for time objects
Configuration
To make my script also interesting for others, I tried to program different possibilities to create the dates and make them configurable.
|
|
It can be set whether the appointment is to be created for a whole day or for a specific hour with a configurable duration. You can create the appointment on the day before the collection or on the correct day. You can have the type of collection written in the title or just “Müllabfuhr”. For the integration in Home Assistant you can enter an offset.
Helper Variables
Before we start reading the CSV file, I create some helper variables.
|
|
The offset_string
is required for the Home Assistant integration already mentioned. I use an f-string here to insert the content of the variable into the string. The expression offset_hours:02d
ensures that one-digit numbers are inserted with leading zero.
For the following code I additionally need an empty Dictionary d
and an empty Calendar object c
.
Import CSV file
The entries in the CSV file look like this:
|
|
The CSV file is read in line by line and the entries are pre-processed.
|
|
The csv.reader
requires the separator and the quote-character to read the file correctly.
In the for loop, the heading is skipped first. Next, if-row[1] in d
is used to check whether the date is already entered in my dictionary. If this is the case, the two collection types are combined via an f-string and the entry in the dictionary is updated.
Otherwise, a new entry is added to the dictionary.
Now I have a dictionary with the date string as key and the collection type as value.
Create Events
The next step is to iterate over the dictionary and fill the Calendar object created above with events. d.items()
returns Key and Value as a tuple.
|
|
For the title of the event I use an f-string again to put several strings together.
The expression (' ' + abfuhr) if descriptive_title else ''
is a so-called ternary operator.
If descriptive_title
is set to True
, the part before the if
is used, otherwise the part after the else
will be used.
The start time is first read from the key as datetime object with strptime
.
At the same time, the hour is set to the value defined above with replace
and the time zone is set.
The datetime object is then converted to arrow object because this is expected by the ICS module.
The ICS module has a bug in the used version, which causes the time zone to be ignored for all-day appointments, so that the appointment appears one day too early.
As a workaround I therefore move the appointment one day forward with shift
so that it is created by ICS on the right day.
If it is configured above that the appointment is to be created on the day before the collection, the same command is used to move the appointment back again.
Now the duration set above is entered into the appointment and then, if necessary, the appointment is converted into an all-day appointment.
Finally, the collection type is entered in the event description and the event is added to the calendar object.
Writing the ICS file
The last step is to write the Calendar object to a file.
|
|
The resulting file can now be imported into Google, for example.