Sam Broner

Sam Broner

Software in NYC & Online

Building an E-Ink Train & Weather Tracker

Projects, Physical, Software

I finally built a Raspberry Pi project my wife loves: an e-ink train and weather tracker! If you want to build one yourself, the Github & instructions are here.

Kira will be jogging to the night shift!

Over the past few years, I've been on something of an e-ink journey. I started with a weather and news display (still the only post on my website that regularly gets organic traffic.) While I loved it and it looked great, a phone is a better way to check the news, and the weather only gets checked once a day. Then in 2022 while at MIT I built Jarvis, the e-ink voice-to-image display. Jarvis was a great party trick — say, "Hey Jarvis, paint me an elephant on a bowling ball in Times Square" and watch as the image gradually appeared. Notably, this was before ChatGPT, when people were still impressed by AI!

Jarvis live demo is better!

Then over Thanksgiving, I had some free time, a basket of spare parts, and the itch to code and build something physical. So here we are with the e-ink train and weather tracker.

The idea is simple: Every morning, my wife and I take the inbound F or G subway lines to work from a stop that's a 2-minute jog or a 6-minute walk from our house. I love the NYC subway and it works incredibly well, but the trains come often and predictably, not on-a-schedule. So every morning we're calling out, when's the next G, when's the next F — and one of us pulls out a phone for the MTA app or Google Maps and yells back the upcoming train times. Then we time our morning routines to either stretch for a train in three minutes or slow down for a train in ten.

The subway and weather tracker makes checking train times much faster and calmer than pulling out a phone. Since it's centrally located in our home, someone is always close enough to glance at it.

The subway times reported by the MTA API are reliable once the train is within a few stops or 15 minutes away, with precision increasing as the trains get closer. Having the train times on the wall lets you check how your morning routine is developing against the train schedule as the departure time gets closer.

Best of all, Kira loves it! This goes on my DIY pantheon along with adding legs to her dresser to make it a better height and fixing a towel rack right before she hosted her colleagues for a book club.

If you want to build one yourself or better understand the project, I'll dive into some editorial and gotchas below. The practical instructions, parts, and code live in this GitHub Repo.

Description & Features

The train & weather tracker is built on a 9.7" 1200x825 E-Ink display attached to a Raspberry Pi 4b. The display is split into four parts: a header, with date, time, and a live second hand to indicate liveness; a train tracker; the commute weather; and a "weather bar" displaying the next 12 hours of weather. The main focus of the layout is the train tracker, which shows the upcoming 30 minutes of inbound F & G trains.

The display sits in a laser cut mat board with black ridges sized to hide the black border of the e-ink display. The mat board sits in a 8.5" x 11" cherry frame that is 1.5" deep to allow the raspberry pi to be backmounted while the frame is still flush to the wall. We hang the display next to the door above a key holder, which is generally the right place for it, but also helps hide the power cord.

Not pretty, but it works

Project Details

The software portion of the project is manageable although there are some gotchas when programming against the Waveshare e-ink hat in particular. We have a modular architecture with a clear separation of concerns:

  1. Display Engine: Renders the layout to the display, supporting communication with the physical e-ink display or rendering a png for non-raspberry pi development

  2. Layout System: A pretty hacky visual arrangement of the elements. It'd be fun to do something more sophisticated here (e.g. a html renderer), but 🤷‍♂️. This will likely require the most work if you want to modify the project

  3. Data Services: Fetch & process (this is important!) train arrival from NYC Transit GTFS feeds + get the weather forecasts

  4. Application Controller: Orchestrate the event loop and subscription model to drive updates to the display

The biggest technical constraint is the update rate to the e-ink display. The display supports multiple update modes with different tradeoffs and can manage sub 500 ms updates, especially for partial updates, but a faster refresh results in fuzzy characters and substantial ghosting that looks pretty bad. The bigger issue is that overloading the display causes it to crash, which requires a full reset.

After some testing, I chose a hybrid display update strategy.

Every second, the pixels around the seconds & minutes digits of the time are rerendered with the display's fastest partial update mode to make it clear that the display is functioning as expected.

When there is an update to one of the next two train times (these matter more than trains 30 minutes away), there is a fast-full display render — all data is updated at this point, but only new arrival times for one of the next two trains will drive the update.

On the hour, the display does a deep full-screen render to sharpen the characters and remove ghosting.

Honestly, you gotta experiment to understand how these will look

Doing deep full screen renders can be jarring — it results in a black and white flash that attracts too much attention to the screen — but once an hour is a fine cadence. For the train times, a fast-full display render works better than a partial refresh because of the layout. The fast partial render cuts across elements, drawing more attention to the refresh than a full refresh. This could maybe be improved through more purposeful partial refresh rectangle selection, but the current solution works well.

The framing was tricky because I wanted something nice, but without breaking the bank. I'm not great at woodworking and I also didn’t want to spend $300-$500, which was the range of quotes (FWIW, I have been trying to find a low cost framing solution for these broken glass pieces for years — let me know if you have any ideas). The e-ink display is awkwardly sized due to the connection cables and drivers. The display surface also has a fine looking, but inelegant border that should be covered. After talking to a few framers, one of them suggested I buy just a custom mat. The mat hides the display, Raspberry Pi, and cabling, but more importantly the outside of the mat is right sized to fit into a standard-sized frame.

The finished product sits neatly beside our door, providing the exact information we need at just the right time each morning. I've written before about the "agency gap" — the gap between what people do and what would be easy, but useful to do. This project is a bit more involved than that, but at ~20 hours of work, it was worth it to me. I built something that solves a daily need, we actually use it, guests talk about it, and it looks great.

Next →587 Miles, 803 Meetings, and 14 Dates: My completely sane system for personal analytics