At the heart of this build is an ESP32 MCU board with 8MB additional PSRAM to ease handling large image buffers. In optimizing the build for low power and maximum battery life I wound up bypassing the voltage converter and BMS on the MCU breakout board and using different parts (e.g. an MT3608 DC-DC converter) between the 1100 mAh LiPo cell and the MCU board.

The ESP32 is woken up daily by a RV-3028-C7 Real Time Clock, on a free sample dev breakout board by the manufacturer Micro Crystal. This RTC is far lower power than the DS* modules common in DIY projects and extremely accurate due to the built-in oscillator, allowing for calibration at the factory.

Further hooked up to the MCU is an E-Ink driving board featuring the ITE IT8951 EPD controller. As E-ink display panels (more on the panel chosen below) are bistable and don't need to be powered between refreshs, the driving board is gated behind a 5V relay to avoid idle power draw (e.g. from the included power indicator LED).

Overall, the frontend spends most of its time in deep sleep. In the early morning it wakes up, connects to WLAN, fetches a new newspaper image from a Raspberry Pi 4B on my home network (which runs most of my home IT), powers up the controller board, updates the display with the image, and then goes back to sleep.

Aside from wanting a nice deco piece for my living room wall, one of my purposes with this project was to try out Rust on a microcontroller. I wrote all of the onboard business logic for the ESP32 in Rust, including a custom driver for the IT8951 EPD controller.

The backend running on the Pi is written in Python. It includes lxml-based article scrapers for some websites my wife and I like, and then runs the content through OpenAI's ChatGPT API to trim articles for size, perform light style transfer and generate suitably short headlines for the layout. It also fetches a weather forecast from the OpenWeatherMap API, which goes into the top-right corner of the header - the layout is of course heavily inspired by the frontpage of the New York Times. With the content in hand it then generates a LuaTeX input file using the Jinja2 template library.

LuaTeX generates a PDF from this input file, which is then rasterized to PNG using Ghostscript. ImageMagick is used to perform several post-processing steps on the image, including adding in paper specs from a texture, a coffee stain for effect at a randomly chosen location (within some bounds for readability), colorspace conversion and finally generating a raw bitmap that can go directly to the IT8951's framebuffer memory.

The file is served via HTTP to the embedded frontend, using Python's built-in HTTP server library. Both the newspaper generator job and the server are installed on Raspbian OS using systemd user service units.

This was a lot of fun to build! As with my other projects, I plan to open source all of the source code and document it extensively. Unfortunately, a busy life has been getting in the way so far, but stay tuned for updates!
In the meantime, check the linked Imgur picture album for a build log of sorts with additional photos.