lumos/Build guide
A weekend hardware build

Build Your Own Tidbyt

A complete buyer's and build guide for a Raspberry Pi-powered Tidbyt clone running the community Tronbyt software stack — fully local, no cloud subscription, endlessly hackable.

Twenty Past4:20
Total cost
~$120–140
Difficulty
Beginner+
Soldering
1 joint
Build time
~2–3 hrs
TL;DR — the recommended build
  • A Raspberry Pi Zero 2 W (with headers) + Adafruit RGB Matrix Bonnet + 64×32 3mm-pitch HUB75 panel + a 5V 4A supply, running the Tronbyt Server (Docker) and the tronberry client daemon — all on the same Pi.
  • Stay on a Pi Zero 2 W / Pi 3 / Pi 4. Not a Pi 5— the matrix driver library doesn't support its RP1 GPIO architecture yet.
  • The 3mm-pitch panel (191×96 mm)is the right call for the Tidbyt desktop look. Pitch is purely a viewing-distance & case-fit decision — the software renders the same 64×32 frame either way.
  • Roughly 1.5× the cost of a bare ESP32 build — well inside budget, and you get a real Linux box that hosts the whole stack itself.
01

The Shopping List

Everything you need, buyable from Adafruit and Amazon. Core build (the required items): ~$105 + tax/shipping. Add an SD card & cord for ~$120–140 all-in. Optional items are dimmed.

Raspberry Pi Zero 2 W — with header
Get the pre-soldered "WH" version so you don't hand-solder 40 pins. A Pi 3B+ or Pi 4 works too. The tronberry client is officially tested on the Zero 2 W.
RequiredAdafruit #6008View ↗
~$22.50
Adafruit
Adafruit RGB Matrix Bonnet
Ships fully assembled — no header to solder. Onboard level shifters, power protection, and a 2.1mm barrel jack. Skip the older HAT (#2345); the Bonnet is the right board here.
RequiredAdafruit #3211View ↗
$14.95
Adafruit
64×32 RGB LED Matrix — 3mm pitch
191 × 96 × 15 mm. Closest to real Tidbyt proportions. Prefer a bigger display or want easy case-fit? Swap to the 4mm pitch #2278 ($39.95, 256×128mm). See the panel section below.
RequiredAdafruit #2279View ↗
$44.95
Adafruit
5V 4A switching power supply
Plugs straight into the Bonnet's barrel jack; the Bonnet then back-powers the Pi over the header — so you only need one supply. A 64-wide panel can pull ~3.85A, so size for 4A.
RequiredAdafruit #1466View ↗
$14.95
Adafruit
microSD card — 32 GB, Class 10 / A1
16 GB minimum; 32 GB gives Docker images room to breathe. Use a name brand (SanDisk Ultra, Samsung EVO) — cheap cards corrupt under Pi I/O.
~$8
Amazon
Hookup wire for the jumper mod
~2 cm of 22–24 AWG solid-core. One short wire between the GPIO4 and GPIO18 pads on the Bonnet — your one and only solder joint. Almost certainly already in your parts bin.
Requiredfrom your bin
~$0
Figure-8 / IEC power cord
Only if you don't already have one — the Adafruit supply's plug is US 2-prong. Grab a "figure-8" cord for your region if needed.
~$2–5
Amazon
Inline power switch (2.1mm barrel)
A real on/off switch so you're not yanking the barrel plug. Solderless — it plugs inline between the 5V supply and the Bonnet's jack, and needs no case change. Two good options: Adafruit #1125(~$2.50; switch rated 2A but informally "probably up to 5A at 12V" — fine at 5V), or a push-button inline switch 3-pack on Amazon. See the shutdown note in Step 6 before you flip it freely.
~$3–7
Either
M3 brass heatset inserts
Only needed if your chosen 3D case uses them (e.g. Scott W's clock case). A 50-pack of 5×4 mm inserts is plenty.
~$8
Amazon
Mini-HDMI cable + USB-OTG adapter
A safety net for first-boot troubleshooting if headless SSH/WiFi misbehaves. Not needed if your headless flash is configured correctly.
Optionalif you have them
Cost vs. the ESP32 route
A MatrixPortal S3 build runs roughly $90 all-in; this Pi build is ~$120–140, about 1.4–1.6×. The premium buys a full Linux box that also hosts the Tronbyt Server on the same device, far more headroom for future apps, and zero microcontroller flashing or PlatformIO work.
02

3mm vs 4mm: Which Panel?

Both are 64×32 HUB75 panels and render identically in software. The only real differences are physical size, viewing distance, and how easily existing 3D-printed cases will fit.

Recommended

3mm pitch — #2279

191 × 96 × 15 mm · 189 g
$44.95
  • Closest to the real Tidbyt's desktop proportions
  • Sharper, denser text up close
  • The classic "little glowing display on the shelf" look
  • Trade-off: fewer ready-made cases fit it exactly

4mm pitch — #2278

256 × 128 × 15 mm · 253 g
$39.95
  • Larger; readable across a room
  • Most existing Makerworld HUB75 + Pi cases target this size
  • Slightly cheaper
  • Trade-off: bigger footprint, less "Tidbyt-ish"
The verdict
Stick with 3mm (#2279) for the Tidbyt aesthetic. The case story is solvable — scale a 4mm enclosure to ~75% in your slicer, or remix a clock case (see below). Only switch to 4mm if you want plug-and-play case compatibility or a display readable from across the room.
03

Pick a Case to Print

There's no Makerworld case sized exactly for the 3mm Pi+Bonnet stack with a Tidbyt-style kickstand — so the honest move is: print one of these, and scale or remix as needed. Order parts first, dry-fit with a tape measure, then commit to a print.

32×64 LED Matrix Enclosure for Pi Zero 2W top pick
Designed for exactly this stack: HUB75 panel + Pi Zero 2W + Adafruit Bonnet (#3211), assembled with 3× M3×14 screws, no supports. Front bezel, rear barrel-jack + power-switch + vent cutouts. Built for the 4mm panel — scale the bezel if you go 3mm.
by yashmulgaonkar4mmMakerworld ↗
64×32 HUB75 Matrix Display Clock
Clock-style case that holds the panel, Pi, and up to three optional sensors (mmWave presence, PIR, lux). Two bottom-cover variants for Pi Zero W and Pi 4. Uses heatset inserts. Pitch isn't stated — measure before printing.
by Scott Wverify pitchMakerworld ↗
Tracker Clock Case RGB Matrix
Simple case for a Raspberry Pi + 64×32 4mm RGB matrix. Designer notes it's a work-in-progress; Bonnet clearance isn't explicitly confirmed.
by Trouble_Man4mmMakerworld ↗
Don't print these for this build
Several gorgeous Makerworld enclosures are built for the ESP32 / Matrix Portal, not a Pi+Bonnet — they have no clearance for the ~25 mm Pi+Bonnet stack behind the panel. Avoid the "ESP32 M4 Matrix Portal Housing" and "Frame for 4mm pitch … Matrix Portal" models. Check Printables / Thingiverse as backups.
04

Software Setup

Two pieces of software, both living on the same Pi: the Tronbyt Server (a Dockerized Go web app that hosts apps and renders frames) and tronberry (a tiny daemon that pulls those frames and lights up the panel). Click any step to expand it.

How it fits together
Tronbyt Server renders each app to a 64×32 WebP and serves it at http://<pi>:8000/<device-id>/nexttronberry polls that endpoint, reads the Tronbyt-Dwell-Secs & Tronbyt-Brightness headers, and draws to the HUB75 panel via the hzeller rpi-rgb-led-matrix library.
1Assemble the hardware (incl. the one solder joint)
  1. Solder the GPIO4 ↔ GPIO18 jumper on the back of the Bonnet — a single ~2 cm wire between the two labeled pads. The Adafruit Bonnet guide shows the exact pads. This unlocks the adafruit-hat-pwm mode for far less flicker and better color depth.
  2. Seat the Bonnetonto the Pi's 40-pin header — push all the way down.
  3. Plug the panel's HUB75 ribboninto the Bonnet's keyed connector, and wire the panel's 5V power pigtail into the Bonnet's screw terminal (red = +, black = −).
  4. Plug the 5V/4A barrel plug into the Bonnet. Do not power the Pi separately — the Bonnet feeds it over the header.
Soldering-shy?
Skip the jumper and use --led-gpio-mapping=adafruit-hat (no -pwm). You'll accept a bit more flicker and slightly weaker color, and you can add the mod later. Do the joint before final assembly though — once the Bonnet is sandwiched, those pads are hard to reach.
2Flash Raspberry Pi OS, headless
  1. Install Raspberry Pi Imager.
  2. Choose Raspberry Pi OS Lite (64-bit) — no desktop. A GUI just wastes resources on an embedded device like this.
  3. Click the gear / Edit settings before writing. Set: hostname tronbyt, a username + password, your WiFi SSID/password/country, timezone, and enable SSH.
  4. Write the card, insert it, power on, wait ~60 s, then SSH in:
ssh <username>@tronbyt.local
3Install the Tronbyt Server (Docker)

a. Run the setup script. This single command does almost everything: it installs Docker and Git, clones the server into ~/tronbyt-server, and starts it for you. When it finishes, your server is already running on port 8000.

curl -fsSL https://raw.githubusercontent.com/tronbyt/server-docker-compose/main/rpi_setup.sh | bash
Don't deploy it a second time
The script already created the ~/tronbyt-server project and ran docker compose up -d. Do not separately mkdiranother folder and run compose again — you'll create a duplicate project that fights over port 8000 and fails with "port is already allocated." From here on, manage the server only from ~/tronbyt-server.

b. Give your user permission to talk to Docker. The script adds you to the docker group, but that only takes effect in a newlogin session. Confirm you're in the group, adding yourself if not:

groups                          # look for "docker" in the list
sudo usermod -aG docker $USER    # run this if "docker" is missing

Then activate the group — either log out and SSH back in, or apply it to the current shell:

newgrp docker     # or: exit, then ssh back in
docker ps         # should run with NO sudo and NO error
If you hit permission denied … /var/run/docker.sock
That's this exact group issue. Run sudo usermod -aG docker $USER, then newgrp docker (or fully log out and back in), and confirm docker ps works. Resist just prefixing everything with sudo — running Compose as root makes your data root-owned and causes permission tangles later. (Because the script itself runs sudo docker compose up -d, the very first container comes up under root; once your group access works you can cd ~/tronbyt-server and run docker compose down && docker compose up -d once, without sudo, to re-own it cleanly.)

c. Confirm it's up. From the project directory the script created:

cd ~/tronbyt-server
docker compose ps     # should show one container, healthy, 0.0.0.0:8000->8000

Open http://tronbyt.local:8000in your laptop browser (or use your Pi's IP). Default login is admin / passwordchange it immediately. (There's a built-in reset-password admin command if you ever lock yourself out.)

Optional: tweak settings via .env
You don't need to touch any config — the defaults (including port 8000) are correct, and the current Go server has no SERVER_HOSTNAME_OR_IP setting (it was required in the old Python version and has since been removed). If you want the server to auto-log-you-in on your home network, create ~/tronbyt-server/.env with the line SINGLE_USER_AUTO_LOGIN=true, then run docker compose up -d from that folder. It only applies from private IP ranges like 192.168.x.
Updating & memory notes
To update later: cd ~/tronbyt-server && docker compose pull && docker compose up -d. The Go rewrite (v2.0.0) cut memory use ~90%, so 512 MB on the Zero 2 W is comfortably viable. A 64-bit OS is strongly recommended.
If data apps (weather, stocks, transit…) never render
Apps that fetch a public API can fail to render even though plain apps (clock, text) work fine. Check the server log — cd ~/tronbyt-server && docker compose logs --tail=100 — and look for a line like lookup api.weather.gov on 127.0.0.11:53: server misbehaving. That's Docker's container DNS failing to resolve external hostnames. Give the container reliable upstream DNS by adding a dns: block to the web service in ~/tronbyt-server/docker-compose.yaml:
services:
  web:
    # …existing config (image, ports, volumes)…
    dns:
      - 1.1.1.1
      - 8.8.8.8
Recreate the container, then confirm it can resolve a name:
cd ~/tronbyt-server
docker compose up -d
docker compose exec web sh -c "nslookup api.weather.gov"   # should return an IP
No need to reinstall the app — it'll render on its next refresh. (Daemon-wide alternative: put {"dns":["1.1.1.1","8.8.8.8"]} in /etc/docker/daemon.json and sudo systemctl restart docker.)
4Register the Pi as a device
  1. On the Home page, click New Tronbyt.
  2. Give it a name (e.g. "Living Room") and choose device type "Raspberry Pi" from the dropdown — the plain one, not"Raspberry Pi Wide" (that's for a 128×64 setup). Your single 64×32 panel uses plain "Raspberry Pi."
  3. Save. The server assigns an 8-character hex device-id (e.g. d8e59932) shown on the Home screen.
  4. Your endpoint URL is: http://<pi-host-or-ip>:8000/<device-id>/next— you'll paste this into the tronberry installer next.
5Install the tronberry daemon

On the same Pi, run the installer. It applies the flicker fixes, installs packages, downloads the prebuilt binary, and sets up a systemd service:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/tronbyt/tronberry/HEAD/install.sh)"

It will prompt you to:

  • Apply flicker-fix optimizationssay yes. It disables onboard audio & Bluetooth, isolates CPU core 3, and blacklists the audio module. These only take effect after a reboot.
  • Paste your Tronbyt URL. Because the server runs on this same Pi, use localhost, not the .local hostname (see the warning below): http://localhost:8000/<device-id>/next.
  • Provide extra rpi-rgb-led-matrix flags. For a 64×32 Adafruit panel on a Zero 2 W with the jumper mod:
--led-rows=32 --led-cols=64 --led-chain=1 --led-gpio-mapping=adafruit-hat-pwm --led-slowdown-gpio=2
Use localhost, not tronbyt.local, for the all-in-one build
When the server and the daemon live on the same Pi, pointing tronberry at http://tronbyt.local:8000/… makes the Pi resolve its own mDNS name — which is unreliable on Linux and shows up as repeated "Failed to fetch image from URL" in the logs even though the panel is lit. Use http://localhost:8000/<device-id>/next instead. (Reserve the .local name for a separate display client that fetches from a server on another machine.)
If the installer dies with "jq: Cannot iterate over null"
The script fetches the latest GitHub release and occasionally gets a transient API response jqcan't parse. The flicker fixes already applied successfully before the crash — you just need to place the binary and create the service by hand. Download and verify the release binary:
mkdir -p ~/tronberry
curl -fL -o ~/tronberry/tronberry \
  https://github.com/tronbyt/tronberry/releases/latest/download/tronberry
chmod +x ~/tronberry/tronberry
Then create the service — edit the URL and flags first:
TRONBYT_URL="http://localhost:8000/<your-device-id>/next"
FLAGS="--led-rows=32 --led-cols=64 --led-chain=1 --led-gpio-mapping=adafruit-hat-pwm --led-slowdown-gpio=2"

sudo tee /etc/systemd/system/tronberry.service > /dev/null <<EOL
[Unit]
Description=Tronberry LED Matrix Service
After=network-online.target

[Service]
ExecStart=\$HOME/tronberry/tronberry \$TRONBYT_URL \$FLAGS
WorkingDirectory=\$HOME/tronberry
StandardOutput=inherit
StandardError=inherit
Restart=always
Nice=-10

[Install]
WantedBy=multi-user.target
EOL

Enable, start, and reboot. The reboot is what activates the flicker fixes — without it, tronberry will start and immediately exit with "snd_bcm2835 … Exiting; fix the above first," because the sound module is still loaded in the running kernel:

sudo systemctl daemon-reload
sudo systemctl enable tronberry
sudo systemctl restart tronberry
sudo reboot

After it comes back, verify:

sudo systemctl status tronberry

You want active (running) with an uptime that keeps climbing(not resetting every few seconds) and no "Failed to fetch" lines — at which point the panel shows your real app rotation. Tweak --led-slowdown-gpio (try 1 first, raise to 3–4 only if you see glitches). No jumper? Drop -pwm to adafruit-hat. To change flags later, edit the ExecStart line in /etc/systemd/system/tronberry.service, then sudo systemctl daemon-reload && sudo systemctl restart tronberry.

Quick troubleshooting check
If you see "Failed to fetch" but the panel is lit, test the server from the Pi: curl -so /dev/null -w "%{http_code}\n" http://localhost:8000/<device-id>/next. A 200 means the server's fine and it's a URL/hostname issue (switch to localhost); a 404 means the device-id in the URL is wrong.
05

Install Your First Apps

Tronbyt runs the Tidbyt community apps (a hard fork), written in Starlark and rendered to 64×32 WebP by the built-in Pixlet engine. Adding one takes seconds.

Good starters to add first:

Clock
Basic digital clock; configurable timezone & format.
Fuzzy Clock
The iconic "twenty past four" word clock — Tidbyt's signature look.
Weather
Current conditions by city, or via a Tempest API key.
Transit Tracker
NYC Subway, BART, Caltrain, CTA, MBTA & dozens more.
NES Clock
Low-config retro visual starter.
Pollen Count
Simple, glanceable, zero-fuss config.

Worked example — Fuzzy Clock

  1. Add App on your device page → search "Fuzzy Clock" → Add.
  2. Set the timezone (e.g. America/New_York); optionally pick a color scheme and 12/24-hour.
  3. Save. Pixlet renders an inline preview within ~1 second so you can confirm before deploying.
  4. Set the dwell time (seconds on screen) and toggle it enabled. On the device page you can drag to reorder, pin apps, or schedule them to time windows (e.g. transit only 7–9am).
  5. Within ~10 s, the next time tronberry hits /next, your new app joins the rotation on the panel.
One limitation to know
Apps that rely on Tidbyt's cloud to store OAuth secrets (e.g. Spotify Now-Playing) aren't supported yet. Clocks, weather, transit, and sports scores via public APIs all work fine.

Powering off safely

If you added the inline power switch, here's the one thing to know: the LED panel and the Pi's processor don't care about abrupt power loss — but the SD card does. Cutting power at the exact moment Linux is mid-write can corrupt a file or the filesystem. This build is low-risk because the card sits mostly idle once tronberry is running (frames are served from memory, not disk), so flipping the switch is usually fine — but over months of daily cycles the odds of catching a bad moment slowly add up.

Pick your spot on the spectrum:

The no-risk way
Shut down gracefully first, then cut power: sudo shutdown -h now, wait ~10 s until the Pi's green activity LED stops blinking, then flip the switch. Flipping it back on boots the Pi (there's no separate power button). Safe every time, but it means reaching for a terminal.
The pragmatic way (recommended)
Flip the switch freely, but cap the downside first: back up your SD card image once everything's configured (clone it with Raspberry Pi Imager or dd). Then a corrupted card is a 10-minute re-flash, not a rebuild. For true yank-proofing once your setup is final, enable the overlay filesystem (sudo raspi-config → Performance → Overlay File System) so the OS runs from RAM and never writes to the card in normal use — just remember to toggle it off when you want config changes to persist.
06

Caveats & Gotchas

The honest fine print — read these before you buy or upgrade. Severity is color-coded: blocker  worth knowing   minor.

Pi 5 support is currently broken
The Pi 5's GPIO is handled through the RP1 chip via a different memory-mapped interface, so the rpi-rgb-led-matrix library can't drive the panels on it. Adafruit's separate PioMatter library doeswork with the same Bonnet on a Pi 5, but tronberry hasn't been ported to it — you'd have to write a small client yourself. If you already own a Pi 5, that's doable but not turnkey. Stay on Zero 2 W / Pi 3 / Pi 4.
The "quality" mod disables onboard audio
The flicker-fix mod blacklists the Pi's audio module. The real Tidbyt Gen 2 has a mono alert speaker; this DIY won't, unless you add a USB DAC + speaker or skip the mod.
Some apps need Tidbyt's cloud secrets
Apps depending on Tidbyt-hosted OAuth credentials (Spotify, etc.) aren't supported yet. The vast majority — anything using public APIs — work fine.
Container DNS can silently break API-driven apps
If weather/stocks/transit apps fail to render while plain apps work, the server's Docker container probably can't resolve external hostnames — look for lookup … on 127.0.0.11:53: server misbehaving in docker compose logs. Fix it by giving the web service explicit DNS (dns: [1.1.1.1, 8.8.8.8]) in docker-compose.yaml, then docker compose up -d. Full snippet and a resolution test are in the Software Setup section (Step 3).
Tronbyt is community-maintained
It's an active project (the v2.0.0 Go rewrite shrank the image ~85% and memory ~90%), but breaking changes happen. Pin to a specific Docker image tag if you want stability, and read the CHANGELOG before upgrading. There's also no mobile app yet — all config is via the web UI.
Panels are factory-remainder stock
Adafruit's 64×32 panels are remainder stock, so bezel color and exact size can vary slightly batch to batch. Cosmetic only.
The in-UI label for the /next URL wasn't directly verifiable
In practice it's always http://<server>:8000/<device-id>/next, and the tronberry installer prompts for it. Find the 8-char device-id on the Home screen or in the URL bar when editing the device. If unsure, just construct it by hand.