Hardware test checkpoint #1: bonnet boot path¶
Goal. Verify the disclaimer -> PIN unlock -> wallet list -> wallet detail loop on the real Pi Zero 2 WH + 1.3" 240x240 TFT bonnet (Adafruit 4506).
This is the first end-to-end hardware test of the bonnet UI stack. Everything below is exercised by 258 host-side tests, but only the Pi can prove that:
- the ST7789 driver actually paints the framebuffer,
- the joystick and A/B buttons map to the expected logical buttons,
- the long-press LONG event fires at the right point,
- segno renders a scannable QR for a real address.
SSH target placeholders
Replace <user>@<host> and <repo-path> below with the SSH
target and remote checkout path for your device. The runbook
doesn't depend on any specific hostname.
1. Prep the Pi¶
A working Raspberry Pi OS Lite (Bookworm or later, 64-bit) on an SD
card, with SSH + the standard Bookworm Python 3.11+ stack. SPI must
be enabled (sudo raspi-config nonint do_spi 0).
ssh <user>@<host>
sudo apt update
sudo apt install -y python3-venv python3-dev \
rpicam-apps python3-picamera2 python3-libcamera \
libzbar0t64
# Enable SPI (bonnet) and reboot.
sudo raspi-config nonint do_spi 0
sudo reboot
After it comes back, sanity-check that the kernel sees both peripherals:
ls /dev/spidev0.* # expect /dev/spidev0.0 and /dev/spidev0.1
rpicam-hello --list-cameras # expect e.g. "imx708" listed
libcamera tool rename on Trixie
On Pi OS Trixie the libcamera CLI tools were renamed:
libcamera-hello -> rpicam-hello, libcamera-still ->
rpicam-still, etc. The Python picamera2 API is unchanged.
2. Push the code¶
From your workstation:
rsync -av --delete \
--exclude .venv --exclude node_modules --exclude '__pycache__' \
--exclude companion --exclude site --exclude _site \
./ <user>@<host>:<repo-path>/
The companion/ PWA isn't needed for the bonnet test, so it's
excluded to keep the transfer small.
3. Install on the Pi¶
ssh <user>@<host>
cd <repo-path>
python3 -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -e '.[display,camera]'
The [display] extra pulls in adafruit-blinka and
adafruit-circuitpython-rgb-display, which are the ST7789 driver
plus the GPIO HAL.
4. Seed a vault (one-time)¶
The bonnet boot loop expects a vault to already exist. From the SSH session, create one with a known PIN and add a single wallet:
.venv/bin/piwallet vault init
# enter PIN (e.g. 123456) twice
.venv/bin/piwallet mnemonic new --words 12 > /tmp/m.txt
.venv/bin/piwallet wallet add --label daily < /tmp/m.txt
shred -u /tmp/m.txt
(Or use an existing vault you've already set up.)
The vault lives at ~/.piwallet-dev/vault.bin by default; the
disclaimer state lives at ~/.piwallet-dev/terms.json. Wiping
that directory resets the device to a "first boot" state.
5. Run the bonnet¶
The display should:
- Show the alpha-software disclaimer page 1, with a blue accent border and a single highlighted page-indicator dot.
- Advance to pages 2 and 3 when you push the joystick right.
- Show a red-bordered "No liability" final page, with a "HOLD A to accept" footer.
- When you hold A for ~700 ms, fill a small red bar at the
bottom of the modal; on release-after-completion the disclaimer
exits with
accepted v1recorded in~/.piwallet-dev/terms.json. - Show the Enter PIN screen with 6 empty cells.
- UP/DOWN cycles the active cell digit; LEFT/RIGHT moves between cells; A confirms.
- After confirming the correct PIN, show the Wallets list with the wallet you added in step 4. UP/DOWN navigates; A drills in.
- The wallet detail screen shows a crisp QR code for the m/0/0 receive address plus the address text in two lines. LEFT/RIGHT step the receive index; A advances.
- Single-press B returns to the wallet list. Long-press B from either screen exits the bonnet app (back to the shell).
6. Things to write down¶
- Are colors correct? (Disclaimer accent should be blue; danger / final page should be red; wallet list cursor highlight should be a muted blue.)
- Does the QR scan with a phone camera from ~10 cm away?
- Any visible tearing or flicker? (If yes, tune SPI baudrate
in
piwallet/ui/display.py::ST7789Display.) - Joystick / buttons all register? (If a direction never
fires, double-check the BCM pin map in
piwallet/ui/input.py::BonnetInputBackend._PINS.) - LONG-press timing comfortable? (Bumpable via
piwallet/ui/app.py::make_input_manager(long_ms=...).) - Top third random noise while the bottom looks fine?
Wrong ST7789 row offset. Adafruit bonnet 4506
needs
y_offset=80— that is now the default inpiwallet/ui/display.py::ST7789Display. Sanity script tunable viascripts/bonnet_sanity.py --y-offset.
7. Known gaps surfaced here¶
The screens below are explicit TODOs:
- Word entry (BIP39 mnemonic create / restore on the bonnet).
- Two-tier vault format upgrade.
- Scan-proposal / display-signed-tx flow on the bonnet (currently CLI-only).
If anything in the checklist above misbehaves, the per-screen fixes live next to the screen code:
- Disclaimer:
piwallet/firstboot/disclaimer.py - PIN entry:
piwallet/ui/pin_entry.py - Unlock screen:
piwallet/bonnet/unlock.py - Wallet list:
piwallet/bonnet/wallet_list.py - Wallet detail:
piwallet/bonnet/wallet_detail.py - Boot loop:
piwallet/bonnet/app.py - Display driver:
piwallet/ui/display.py - Input backend:
piwallet/ui/input.py