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.

Body contains an array of all calendar entries easily parsable.

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!

Nice! that's way to easy - why even make a blog post?!

Until you realize, that the file sometimes comes with illegal content...

'Central Europe Standard Time' obviously isn't real

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 ...

... and it lags out the whole server

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