Getting started¶
This chapter walks you from "the parts arrived" to "I can sign a transaction in a CLI smoke test." For the user-facing journey (pairing, sending, receiving) see the User manual.
What you need¶
- A Raspberry Pi Zero 2 WH (the W has a wireless module the enclosure design assumes; the H has the pre-soldered header the bonnet plugs into).
- An Adafruit 1.3" 240×240 TFT bonnet (product 4506) — ST7789-class panel with a joystick and A/B buttons.
- A Pi Camera Module 3 plus the ribbon cable adapter for the Pi Zero CSI connector. The original Camera Module v2 also works but autofocus is much nicer for scanning animated QRs on a phone screen.
- A microSD card (8 GB is enough; 16 GB is more comfortable).
- A 5 V power supply with a micro-USB connector that plugs into the bonnet's PWR IN port (the one farthest from the SD slot).
- A phone, tablet, or laptop with a camera, to run the companion web app. Any modern browser (Chrome/Safari/Firefox) works.
Bring up the bonnet¶
The bonnet hardware setup is its own multi-step process — SPI
buffer tuning, the dual-stack Adafruit driver situation, and so on.
Rather than duplicate it here, read the canonical guide in
GETTING_STARTED.md
at the project root, which walks through:
- Flashing Raspberry Pi OS Lite (Bookworm) with
raspi-imager. - Enabling SPI, installing PIL / NumPy, raising the
spidevkernel buffer to 131072 (the default 4096 is the cause of the classic "good half / garbage half" symptom). - Setting up a Python virtualenv with Blinka and the CircuitPython RGB display driver.
- Re-assigning the SPI chip-select pins via
raspi-spi-reassign.py --ce0 disabled --ce1 disabled. - Running the
scripts/rgb_display_pillow_bonnet_buttons.pydemo to confirm the panel and joystick work.
When the bonnet shows the demo's "Hello World" frame and the buttons cycle the picture, the hardware side is ready.
Wire up the camera¶
sudo apt install -y python3-picamera2 libzbar0t64
source ~/.venvs/piwallet/bin/activate
pip install pyzbar
Smoke test:
rpicam-hello -t 2000 # confirms the CSI cable is seated
python scripts/camera_qr_test.py /tmp/cap.jpg
The script grabs a frame, runs pyzbar against it, and prints the
decoded text. If rpicam-hello shows live preview and
camera_qr_test.py decodes a real QR code from your phone, the
camera is ready.
Install the offline core¶
On the Pi (or, for offline development, on your laptop — PiWalletSV's core has no Pi-specific dependencies):
git clone https://github.com/example/piwallet.git
cd piwallet
python3.13 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
You should see 150-ish tests pass. The [dev] extra pulls in
pytest, pytest-cov, and ruff. The optional Pi-side display
dependencies live behind [display] and only install cleanly on
Linux/Pi.
The CLI is installed as piwallet. Run piwallet --help to see
the top-level commands: mnemonic, vault, xpub-export,
decode, sign, qr.
Install the companion PWA¶
The companion is a Vite + vanilla-TypeScript PWA in companion/.
Any device with a modern browser can run it; for development it
hosts on https://localhost:5173/.
cd companion
npm install
npm test # 80-ish Vitest tests
npm run dev # serves on https://localhost:5173/ AND https://<lan-ip>:5173/
When you visit the URL, the first-load disclaimer modal pops up.
Tick the box and click Continue. The state machine is described
in the Architecture
chapter; localStorage keeps the acknowledgement until the version
bumps.
The PWA serves over HTTPS by default with a throwaway self-signed
certificate (see @vitejs/plugin-basic-ssl)
because getUserMedia (camera access) requires a secure origin.
On iOS Safari you'll see a "This Connection Is Not Private" warning
the first time — click Show Details → visit this website.
After that the camera permission can be requested. To skip the
warning entirely, use mkcert
to generate a trusted certificate and wire it into vite.config.ts.
PIWALLET_HTTP=1 npm run dev disables HTTPS for plain
localhost work.
Sanity-check end to end¶
The fastest way to confirm both halves agree is the round-trip page:
- Open
https://localhost:5173/#/loopin your browser. - Wait a second. The page builds one of each envelope kind, encodes it through CBOR + gzip + PW1 multipart, then assembles it back and asserts byte-equality.
Every row should be green. If any row is red, the wire stack has
drifted; check the version of the companion/ build matches the
Python repo and rerun the test suites.
For an actual end-to-end signing demo (without the bonnet UI), follow the User manual. For the deepest test of the SPV stack, run the canonical fixture through the CLI:
The first command rebuilds the fixture; the second prints a
human-readable summary of its contents (inputs, outputs, fees,
anchors). The Python suite already exercises a full verify +
sign round-trip against it.
Next steps¶
- User manual — pairing, send, receive, broadcast.
- Architecture — what the two halves actually do, what they trust, and what they verify.
- Develop — repo layout, testing matrix, fixture tools, release checklist.