Import Outlook calendar into HomeAssistant
TLDR: Skip to "The solution"
That's easy, right?
Well how do you even get your outlook calendar? You could for example try to parse the json api, which is used by the outlook web app to display your calendar.
Or you ultimately try to share a calender by sending it to your other email address and find out, that it's just a link to an ical file. Well ...DUH!
Until you realize, that the file sometimes comes with illegal content...
So you take some time and prepare a simple python script to import and fix the broken ical file and pass it on to your homeassistant instance, which stores local calendars in an ics-file inside its config folder:
/config/.storage/local_calendar.<calendar_name>.ics
You will find this file in the config folder after creating a local calendar in your instance and adding at least one entry manually. This by itself i just the storage for the plugin, but by repeatedly reloading the calendar via an automation, you can make it into a data source.
That seems like an easy solution ...
Well yeah... even after manually sed- and awk-ing through the whole file and removing all offending modifiers that cause exceptions for the homeassistant parser, it seems to work... until you realize, that the whole interface is frozen and every control knob is rendered useless.
I went back to figuring out how to extend the web session without having to continiously reauthenticate with a 2FA, in order to repeatedly poll the json api, until I tried one last thing.
The solution
Turns out you the easiest way is to parse the file and generate a completely new one without RRULE entries, which seem to cause homeassistant to crash. The following generates single VEVENT entries for the duration of the next four weeks:
import icalendar
import os
import recurring_ical_events
from datetime import datetime, timezone, timedelta
start_date = datetime.now()
end_date = datetime.now() + timedelta(weeks=4)
with open("./calendar.ics") as fh:
c = icalendar.Calendar.from_ical(fh.read())
events = recurring_ical_events.of(c).between(start_date, end_date)
cal = icalendar.Calendar()
for event in events:
if event["SUMMARY"].find("bgesagt") > 0 or event["SUMMARY"].find("anceled") > 0:
continue
ev = icalendar.Event()
ev.add('summary', event["SUMMARY"])
ev.add('dtstart', event["DTSTART"].dt)
ev.add('dtend', event["DTEND"].dt)
cal.add_component(ev)
out = open('rnew.ics','wb')
out.write(cal.to_ical())
out.close()
#!/bin/sh
#
wget https://outlook.office365.com/owa/calendar/<CALENDAR-ID>/<UUID>/reachcalendar.ics -O calendar.ics
python3 ./new.py # script above
# Main folder for HA config
cp rnew.ics ../config/.storage/local_calendar.work.ics
rm calendar.ics