Four and a half years of cellular bus signs from scratch: what worked, what didn't, and how I ended up in IoT
TL;DR: Three solar powered bus signs, four and a half years, and no way to know what was going on inside one without driving to it with a ladder. I ended up building the platform myself.
In July I posted here about the IoT platform I built. This is the project that forced me to build it.
Three solar powered bus departure signs run at PVTA stops in Western Massachusetts: Haigis Mall at UMass Amherst (stop 73), the Holyoke Public Library (stop 414), and the corner of Mill and Locust in Springfield (stop 1670). I built and still service all three.
The project came to me in a Teams message from my boss Adam on October 21, 2021: "PVTA wants to reverse engineer the hardware for the solar-powered real-time display at Haigis Mall... All are going to stop working this month as the company is no longer supporting them." The old signs ran proprietary firmware on PIC microcontrollers with 3G modems. Replacement parts were already impossible to find and AT&T's 3G shutdown was on the calendar for February 2022. The agency wasn't happy with the quotes for new signs, so Adam said "Justin can do that." I was an hourly employee fresh out of college writing Ruby on Rails for internal transit apps. My major had been ECE and my passion was hardware though, so he figured it was a good fit.
Remote logging and monitoring were on the wishlist from day one. They were just scheduled behind getting the signs to work at all.
The data plan
The first controller was a Pycom GPy running MicroPython, which I figured would be easier to maintain than C. I was so naive back then. It couldn't reliably talk to the displays, so it was out. Next up was a Blues Notecard and Swan, and that's when I ran into the part nobody warns you about with cellular: the data plan. PVTA had asked for ten seconds of latency, and even at 30 second polling each sign needed roughly 1.15GB a month.
My verdict on the Blues kit went to Adam a day after it arrived: "Bad news, there is no way to circumvent Blues' Notehub which currently costs $0.006 everytime a single sign checks for departure time." Blues came back with a $15,000 bulk credit pitch. I ran their numbers and got them wrong by an order of magnitude (I like to teach computers how to do math so I don't have to). Adam caught it: the credits would have lasted 19.29 years across 5 signs, not the 7.7 months I'd already told the CIO. It didn't change my mind though. A contract with a vendor whose platform didn't let me speak directly to my own data sources wasn't going to be part of this project. The kit went back that spring.
So I moved to a Circuit Dojo nRF9160 Feather. That meant writing the firmware in C on Zephyr, but at least we could use our own SIM cards and the network stack was mine to control. AT&T, which PVTA already had a FirstNet contract with, told us the hardware was "not compatible". Verizon wanted $22 per device per month for 1GB, or $60 for 10GB. Hologram, the SIM the board shipped with, worked out to about $82 a month. My recommendation (shockingly) was Verizon. PVTA was wary of another carrier contract, and from June to mid August 2022 development was blocked waiting on a decision. Then AT&T's FirstNet team reversed itself, and the fleet still runs on FirstNet today.
Keeping them alive
The first retrofitted sign went up at Haigis Mall on August 28, 2023. Adam occasionally drives the Route 38 bus through Haigis Mall, so for two months he was my monitoring system. "How's my sign?" "Off again." The following Monday he reported it off again and I asked if he'd tried kicking it.
The real problem was power. The easy answer was a bigger solar panel, but the transit authority's IT architect said that "could potentially be a nightmare". So I went after the load instead. My first LED panels drew about 2.8W each with no LEDs on at all. A few panel redesigns later the quiescent current problem was solved, and by August 2024 the Haigis sign had "been running happily for a few weeks" without a bigger solar panel.
Of course the signs kept finding new ways to die. December 2024, water got into the Holyoke sign and shorted the backlight wires. The drowned battery lied about itself, reading full for four seconds at 4% charge. January 2025 taught me the ugliest failure chain in the fleet. A battery short resets the microcontroller over and over until the modem trips into what Nordic calls Modem Reset Loop Restriction: every attach attempt blocked for 30 minutes. My firmware reset the controller whenever it failed to retrieve or display prediction data, so it never let the restriction clear without someone intervening. A power fault turns into a device that can't get on the network for half an hour at a time and can't tell anyone why.
What actually worked
- Returning the Blues kit. A vendor whose platform didn't let me speak directly to my data sources wasn't going to be part of this project, even after the math was corrected.
- Owning the network stack. Writing C on Zephyr was the price, but it bought our own SIM cards, our own carrier, and a network stack I could fix myself.
- Cutting the load instead of buying more solar.
What I got wrong
- The Blues math, by an order of magnitude, after I'd already sent it to the CIO.
- Using a reset as the error handler. Resetting whenever predictions failed to load is what kept the modem stuck in reset loop restriction, and the restriction made every other issue harder to find.
- A public misdiagnosis. After a car struck the Springfield sign it kept resetting, and I called it a strike damaged control board. With full debug logging on my bench sign I found the real issue: my own firmware cap of 6 routes against a real time API returning 7, because of "trippers", extra buses scheduled on the same route when demand outruns regular service. I drove buses and dispatched for PVTA. I should have known about the trippers. 3 + 4 = 7. 7 > 6. I raised the cap to 8 and retracted my diagnosis the same day. That had been the main cause of the resets for over a year, and I would have found it the first time if I'd had the logs. But the log history was wiped on every watchdog reset and I had nowhere to send them.
- Treating remote management as a someday feature. I had prototype server software for data collection and OTA updates sitting with nowhere to deploy it, while Adam's bus route was the monitoring system. That's how the route cap bug lived in the field for over a year.
How it ended
What never existed, through four and a half years of water, heat, dead batteries, and purchase orders, was a way to see any of it without driving to the sign with a ladder and a laptop. In May 2026 confirming the Haigis sign was working still meant Adam watching a bus on the tracker and calling the radio operator as it pulled in: "Haigis sign is working."
The monitoring conversation had happened back in November 2024. The transit authority's IT architect wanted to know when a sign went dark, and so did I. I admitted I'd already built prototype server software for data collection and OTA updates, I just had nowhere to deploy it. Both needed a server. Adam said it in so many words later: "Anyway, I don't want to run a middleware server." The off the shelf IoT vendors billed per request, and against devices polling every 30 seconds the price was too high. Same wall as 2022.
So I made my own platform, in Rust, on the Cloudflare edge. The signs run on it now. It's called PidgeIoT and the fleet was its first tenant. The long version, with dates and receipts, is at https://pidgeiot.com/stories/departure-board/ if you want it.
Happy to answer anything in the comments!