At the time of writing, February 2021, the display is up and running since 2019. It served me well so far.
I wanted a calendar and weather information display in my hallway to quickly get the information for the day while putting on my shoes before leaving for the day. There are products, but nothing really fit the bill for me. So it goes..
- Display current date, with ISO calendar week
- Current weather and forecast for the day in intervals of a couple of hours. I want to use this to decide if I should take an umbrella and when a good time (sunny) for a walk would be.
- Calendar events for today. All day events and appointments.
- Sunrise and sunset times.
- Don't draw power when not in view
- No soldering.
- Tools should run on a low power Linux machine and nothing smaller. Software should be as simple as possible and not low-level (no Arduino, ESP, etc.)
Originally I also had a day countdown towards certain bigger events like vacations or birthdays on the list. While it was nice, the screen space was to limited to have a decent number of calendar events and count down events.
To cover all the requirements, you pretty soon end up with ePaper and a raspberry pi. Instead of ePaper, an active display with a motion sensor would probably also do the job, but I did not like the idea of a display turning on when I enter the hallway.
Nothing fancy, a Raspberry Pi 3 with a Waveshare 7.5" monochrome ePaper display. All tugged away behind a picture frame.
Python and LaTeX glued together by Bash drives the display. Comporellon is a rather cold planet in the book im currently reading. It's also quite cold and dark right now where I live. I tend to plan my Corona walks by looking at the ePaper display. Somehow I found that a fitting name. Find the code on Github: https://github.com/irq0/comporellon
The flow of information is as follows:
- Gather scripts fetch weather, CalDav events and iCal file events
- This is fed into a Jinja2 template tool that generates a LaTeX file
- LaTeX renders the file to PDF
- The PDF is converted to a black and white PNG
- A vendor tool refreshes the display
Gather: Calendar, Weather
I originally wanted to source weather data from DWD, but the python library I found was a bit hard to use for my taste
Looking around for something simpler, I found and settled on PyOWM for the OpenWeather API. The API requires a free API key. Their free tier offers enough weather data access and the limits are high enough for my script running hourly. Perfect.
When I first wrote the code, my CalDav server was an aging version of
Radicale, that did not have proper data search support; Searching for
today's events returned all events. This is the reason for the
event_is_today filter function in
calendar_tools.py. It filters the
supposed to be filtered events. It is not 100% perfect, since there
are many ways to specify a VEVENT that has an instance on the
requested day. Event things like all day events differ depending on
the calendar application that created them. Fun.
Unfortunately, filtering used to be the step taking longest on the pi. Yes, more than the LaTeX process. AFAIR about 5 minutes from a reasonably sized calendar file with about 10 years of worth of data. Did I say reasonably sized?
I now host my calendars on Nextcloud. Their date search function works. The function turned out to be useful later, when I added support for solo iCal files, though.
LaTeX Renderer & Jinja2 Template
Why LaTeX you might ask. It was not an obvious choice for me either. My first approach used the Python Imaging Library. I quickly became annoyed with pixel positioning. I rather wanted the machine do that for me. Minimum requirement was a layout engine and nice anti-aliased fonts. The latter turned out to be 🤦-worthy idea, since the display is black and white.
Layouting and nice fonts lead me to consider either HTML+CSS with something like pdfkit or LaTeX. LaTeX clearly won for me. Text rendering is really nice, The Comprehensive LaTeX Symbol List has good weather icons and it is actually tailored to creating physical documents. Refreshing an ePaper display is kind of like printing isn't it?
Going with LaTeX immediately raises the question of the document class. The usual, article, journal, etc. did not make any sense. What made sense was LaTeX Beamer with beamerposter. The template treats the display as a small poster or flyer, which I found to be a good model. The search for good looking font ended in IBM Plex Sans. Other fonts that look nice: Fira Sans Book, Fira Mono, Visitor TT1 BRK:style=Regular, Apple ][, Palm OS, Alto Mono, Fira Sans Medium. Not every font, especially the Pixel fonts did not look good on ePaper.
The LaTeX template LaTeX Template Source is pretty straight forward. The display is just a single frame with the content arranged in columns. The calendar items are arranged into a table.
People knowing Jinja2 will probably find the template sections a bit odd. Unfortunately the default Jinja2 syntax clashes with LaTeX, so some renaming was necessary. I followed a recipe, that I can't find anymore.
Getting the PDF to image conversion right took way more time than I like to admit. As mentioned earlier I wanted nice anti-aliased fonts. Well, my first shot at PDF to PNG resulted in horrific looking fonts and images with weird dithering patterns when ePapered. It then dawned to me, the display is black and white, probably the first real black and white display I ever wrote software for. In my childhood we had grayscale TVs and monitors but somehow called them black and white. Confusing. Antialias needs grays to smooth edges. No grays meant for pdfcairo and ImageMagick to dither.
What worked was carefully adjusting pdfcairo conversion DPI and the LaTeX document size. The fonts don't look perfect on the ePaper, but nice enaugh if you are a meter away from it.
pdftocairo -png -mono -singlefile -antialias none display.pdf display
Here the rendered templates in black and white without antialias and grayscale. Looking at it from a monitor, It is hard to believe that the horrid pixely image will look nicer on the ePaper than the smoothed one, but it does.