Skip to content

About

Live Auckland Transport bus times + post-CRL train map on an ESP32 with a 2" ST7789. Everything runs on the ESP32; my 2.4 GHz WiFi doesn't reach it, so the PC just relays internet over USB.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

AT Departure Board

Live Auckland Transport bus times and a live map of the post-CRL train network on an ESP32 with a 2.0" ST7789 colour display (GMT020-02, 320x240).

The ESP32 does all the work: it fetches from the AT API, parses the responses, works out countdowns, snaps every train's GPS position onto the map, and draws both screens.

Why USB instead of WiFi: the ESP32 only has 2.4 GHz WiFi, and the 2.4 GHz WiFi in my house doesn't reach where the board sits. So I used USB: the PC acts as the board's internet connection and nothing more. netproxy.py relays HTTP requests over the USB cable. All the logic and drawing stays on the ESP32.

Bus stop (day) Live train map
bus screen, daytime live post-CRL train map
Dusk Night
bus screen at dusk bus screen at night
  • Bus: one card per stop. The bus slides toward the stop as its arrival time counts down, clouds drift, and the sky follows the real time of day (dawn, day, dusk, night with stars and lit windows). The Britomart lane shows the city skyline with the Sky Tower. Default: the 27H both ways at Aldersgate Rd, Hillsborough (stops 8669 and 8664). The bus pixel art comes from MSMGreen/at-departure-board (MIT).
  • Rail: drawn after AT's official "Ngā Tereina" map. It has the red City Rail Link loop (Waitematā, Te Waihorotiu, Karanga-a-Hape, Grafton, Newmarket, Parnell) and E-W/O-W side by side out west. Every train is a bold marker (line colour, white ring, dark rim) that glides between GPS fixes. The lines are toned down so the markers stand out.

Press BOOT on the ESP32 to switch screens, or set AUTO_SWITCH in config.py.

How it works

AT API  <--HTTPS-->  PC: netproxy.py  <--USB serial 115200-->  ESP32: everything else

The board sends GET <id> <url>. The PC fetches it and replies <id> <status> <length>. The board then pulls the body in 1 KB pieces (READ <id> <n>), so the PC never sends anything unasked. The ESP32's serial input buffer is tiny, and between pieces the board keeps animating. Replies carry the request id, so stray lines are skipped safely.

On the board:

File What
main.py start-up, main loop, BOOT button, sleep when the PC is off
net.py the USB link to netproxy.py
atdata.py bus timetable + live delays, train positions (stream-parsed), NZ time
busscreen.py, railscreen.py the two screens
gfx.py RAM canvas, anti-aliased text, soft-edged markers (viper code)
railgeo.py, busart.py, assets/ generated by tools/build_assets.py

The ESP32 can't rasterise fonts or anti-aliased map lines in real time, so tools/build_assets.py bakes those once on the PC: fonts (2-bit anti-aliased), the map background, the bus page background, and the train markers. Everything live is drawn on the board. The assets are built from your own Windows fonts, so they aren't committed.

Wiring

Display ESP32
VCC 3V3
GND GND
SCL GPIO 18
SDA GPIO 23
CS GPIO 5
DC GPIO 16
RST GPIO 17

Setup

  1. Flash MicroPython (ESP32_GENERIC, v1.29) at 0x1000.
  2. cp config.example.py config.py, then add your AT API key (dev-portal.at.govt.nz, "GTFS" product) and your stops.
  3. pip install pyserial pillow numpy mpremote
  4. python tools/build_assets.py
  5. python tools/upload.py (about 5 minutes the first time; --code afterwards uploads just the .py files)
  6. python netproxy.py, and leave it running.

Start with Windows

Put a shortcut in your Startup folder (Win+R → shell:startup) that runs pythonw.exe netproxy.py, with the project folder as "Start in". It runs with no window, logs to netproxy.log, and only one copy runs at a time.

Notes

  • When the PC turns off, the board notices no answers and, after SLEEP_AFTER_MIN minutes (default 5), blanks the panel and deep-sleeps. netproxy.py pulses the reset line when it starts, which wakes it. BOOT wakes it too. The GMT020-02 has no backlight pin, so the backlight stays lit unless the PC cuts USB power.
  • The link runs at 115200 both ways: the ESP32's TX corrupts bytes at higher rates. It's enough; the train feed (~12 KB) takes about 2 s.
  • RAM (~160 KB) is the tight resource. Fonts are read from flash a glyph at a time, the bus art is packed bytes, and train positions are parsed from the stream with a regex rather than loaded as JSON. Train IDs are discovered in batches of 200, because a single 1000-id URL is a 6 KB string the fragmented heap can't hold.
  • SPI runs at 20 MHz. At 40 MHz, breadboard jumper wires corrupt long fills.
  • The screenshots in docs/ come from tools/emulate.py, which runs the board's own drawing code on the PC with live AT data. The panel is write-only, so it can't be read back. They show exactly what the ESP32 draws. Run it to preview changes without the hardware.

Licence

MIT; see LICENSE. The bus sprites (atboard/) are from MSMGreen/at-departure-board under its own MIT licence. Data comes from the Auckland Transport developer API. This is an independent hobby project, not affiliated with Auckland Transport.

About

Live Auckland Transport bus times + post-CRL train map on an ESP32 with a 2" ST7789. Everything runs on the ESP32; my 2.4 GHz WiFi doesn't reach it, so the PC just relays internet over USB.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages