In diesem Beitrag zeige ich, wie ich eine Liste mit Terminen einlese, verarbeite und dann im ICS Format abspeichere.
Hintergrund
Die Bremer Stadtreinigung bietet die Müllabfuhrtermine zum Download als ICS Datei und als CSV Datei an. Leider sind dabei für Restmüll und Biomüll jeweils zwei einzelne Termine eingetragen obwohl beides am gleichen Tag abgeholt wird.
Da ich die Termine ausserdem in mein Smarthome einbinde, um darüber Benachrichtungen zu erhalten, möchte ich sie ausserdem im einem bestimmten Format im Kalender stehen haben. Details zur Einbindung folgen in einem späteren Artikel.
Das Python-Skript
Zu finden ist das fertige Skript hier auf Github. Man braucht mindestens Python 3.6, da ich f-Strings verwende.
Imports
Zuerst werden die benötigte Module importiert. ics
und arrow
können über pip
installiert werden, die anderen Module sind in der Standardlibrary enthalten.
|
|
csv
: Lesen und Schreiben von CSV Dateienics
: Lesen und Schreiben von ICS Dateienarrow
: erweiterte Funktionen für Zeitobjektedateutil.tz
: Zeitzonen-Definitionendatetime
: Standardfunktionen für Zeitobjekte
Einstellungen
Damit mein Skript auch für andere interessant ist, habe ich versucht, verschiedene Möglichkeiten die Termine zu erstellen zu programmieren und parametrierbar zu machen.
|
|
Eingestellt werden kann, ob der Termin ganztägig oder zu einer bestimmten Stunde mit einer einstellbaren Dauer erzeugt werden soll. Dabei kann man den Termin am Vortag der Abfuhr erzeugen oder am richtigen Tag. Man kann die Art der Abfuhr mit in den Titel schreiben lassen oder nur „Müllabfuhr“. Für die Einbindung in Home Assistant kann man einen Offset eintragen lassen.
Hilfsvariablen
Bevor es an das Einlesen der CSV Datei geht, erzeuge ich einige Hilfsvariablen.
|
|
Der offset_string
wird für die schon angesprochene Home Assistant Einbindung benötigt. Ich benutze hier einen f-String, um den Inhalt der Variablen in den String einzufügen. Der Ausdruck offset_hours:02d
sorgt dafür, dass einstellige Zahlen mit führender Null eingefügt werden.
Für den folgenden Code brauche ich dann noch ein leeres Dictionary d
und ein leeres Calendar-Objekt c
.
CSV Datei einlesen
Die Einträge in der CSV-Datei sehen folgendermaßen aus:
|
|
Die CSV-Datei wird zeilenweise eingelesen und die Einträge vorverarbeitet.
|
|
Dem csv.reader
muss man dabei das Trennzeichen und den Quotechar mitgeben, damit die Datei korrekt eingelesen wird.
In der for-Schleife wird zuerst die Überschrift übersprungen. Als nächstes wird mit if row[1] in d
geprüft, ob das Datum schon in meinem Dictionary eingetragen ist. Wenn das der Fall ist, werden die beiden Abfuhrarten über einen f-String zusammengefasst und der Eintrag im Dictionary aktualisiert.
Ansonsten wird einfach ein neuer Eintrag zum Dictionary hinzugefügt.
Damit habe ich nun ein Dictionary mit dem Datums-String als key und der Abfuhrart als value.
Events anlegen
Im nächsten Schritt wird jetzt über das Dictionary iteriert und das oben angelegte Calendar-Objekt mit Events befüllt. d.items()
gibt dabei jeweils Key und Value als Tuple zurück.
|
|
Für den Titel des Events benutze ich wieder einen f-String, um mehrere Strings zusammenzusetzen.
Der Ausdruck (' ' + abfuhr) if descriptive_title else ''
ist ein sogennater ternärer Operator.
Wenn descriptive_title
auf True
gesetzt ist, wird der Teil vor dem if
benutzt, ansonsten der Teil hinter dem else
.
Der Startzeitpunkt wird zunächst als datetime Objekt mit strptime
aus dem Key gelesen.
Gleichzeitig wird mit .replace
die Stunde auf den oben definierten Wert gesetzt und die Zeitzone eingestellt.
Das datetime Objekt wird anschließend in arrow Objekt umgewandelt, weil das vom ICS Modul erwartet wird.
Das ICS Modul hat in der verwendeten Version den Bug, dass bei ganztägigen Terminen die Zeitzone nicht berücksichtigt wird und so der Termin einen Tag zu früh erscheint.
Als Workaround schiebe ich daher den Termin mit .shift
einen Tag nach vorne, so dass er von ICS am richtigen Tag erzeugt wird.
Wenn oben konfiguriert ist, dass der Termin am Tag vor der Abfuhr erzeugt werden soll, wird mit dem gleichen Befehl der Zeitpunkt wieder nach hinten geschoben.
Nun wird die oben eingestellte Dauer in den Termin eingetragen und anschließend gegebenenfalls der Termin in einen ganztägigen Termin umgewandelt.
Zu guter Letzt wird die Abfuhrart in die Terminbeschreibung eingetragen und das Event zum Calender Objekt hinzugefügt.
ICS Datei schreiben
Der letzte Schritt ist dann das Calendar Objekt in eine Datei zu schreiben.
|
|
Die entstandene Datei kann man nun zum Beispiel in Google importieren.