Skip to content

Flash and first run

This is the user-facing path from "I have a downloaded SD-card image" to "I've signed my first transaction." It describes the flow that ships without compiling anything yourself, using the prebuilt PiWalletSV image distributed from the Download page.

If you'd rather build the image yourself from source, see Build & deploy. Both paths produce a sealed appliance that boots straight into the bonnet UI; this page is shorter because the prebuilt image has already done the provisioning step for you — including the USB backup mount daemon, FAT/exFAT tools, and bonnet ReadWritePaths for /mnt/piwallet-usb (Operate § USB vault backup).

Beta software

PiWalletSV is beta. Use TESTNET and small amounts only. The image artifact described here is published as a community beta — there is no commercial support behind it, and you remain responsible for verifying signatures and reading the Disclaimer.

What you need

  • A downloaded image (.img.xz) and its .asc signature, both from the official Download page.
  • A microSD card, 8 GB or larger.
  • A Raspberry Pi Zero W or Zero WH with the Adafruit 1.3" 240×240 TFT bonnet (product 4506) and an ArduCam OV5647 camera module (32-bit Raspberry Pi OS Lite image).
  • A 5 V power supply with a micro-USB plug for the bonnet's PWR-IN port.
  • A computer with gpg, xz, and either Raspberry Pi Imager or the ability to run dd (Linux/macOS) or balenaEtcher (cross-platform).

Step 1 — Verify the download

This is the single most important step. The whole point of an air-gapped signer is that you trust the firmware running on it; if you flash a tampered image you've defeated the security model yourself. Skipping this step makes everything else meaningless.

# In the directory where you downloaded the files:

# 1. Import the PiWalletSV release key (one-time).
gpg --keyserver hkps://keys.openpgp.org --recv-keys 9E048B6E7F54C49DE2D5AEB5DA261F4F2B0CA281

# 2. Verify the signature on the image.
gpg --verify piwalletsv-<VERSION>-<BOARD>[-maturity].img.xz.asc \
    piwalletsv-<VERSION>-<BOARD>[-maturity].img.xz

# 3. Cross-check the SHA-256 against the published value.
shasum -a 256 piwalletsv-<VERSION>-<BOARD>[-maturity].img.xz

The Download page lists the expected fingerprint and the SHA-256. A successful signature check ends with “Good signature” and the release key fingerprint — nothing else counts. If the verification fails, stop: do not flash. Mismatched signatures are how supply-chain attacks reach end-user devices.

Step 2 — Flash the image

Pick the tab for your operating system. All recommended tools are free and open source; they handle decompression of the .img.xz file automatically so you don't need to unzip first.

Recommended: Raspberry Pi Imager (official, open source, easiest option on any platform)

  1. Download and install Raspberry Pi Imager from raspberrypi.com/software.
  2. Launch Imager. Under Raspberry Pi Device choose No filtering (or pick Raspberry Pi Zero 2 W).
  3. Under Operating System click “Use custom” and select the verified .img.xz file. Imager decompresses it for you — you do not need 7-Zip or any other tool.
  4. Under Storage pick your microSD card. Double-check the drive letter — Imager will erase it entirely.
  5. Click Next. When prompted about OS customisation, choose “No” — PiWalletSV is a sealed appliance and does not use SSH, Wi-Fi credentials, or any custom hostname.
  6. Click Yes to confirm the write, then wait. Imager verifies the written data automatically; let it finish before ejecting the card.

Alternative: balenaEtcher (also open source; slightly simpler UI, no device-filter step)

  1. Download and install balenaEtcher.
  2. Click Flash from file and select the verified .img.xz.
  3. Click Select target and pick your SD card.
  4. Click Flash! and wait for the verification pass to complete.

Recommended: Raspberry Pi Imager

Install via the download page or with Homebrew:

brew install --cask raspberry-pi-imager

Then follow the same steps as the Windows tab above. Imager on macOS requests administrator permission to write to the SD card via a standard system prompt — grant it.

Alternative: balenaEtcher

brew install --cask balenaetcher
  1. Click Flash from file → select the .img.xz.
  2. Click Select target → pick the SD card disk (e.g. disk4, not a partition like disk4s1).
  3. Click Flash!

Prerequisites

xz is needed to decompress .img.xz. It is pre-installed on most Linux distros. On macOS, install it with Homebrew:

brew install xz

Identify your SD card

diskutil list   # macOS — look for a disk whose size matches the card
lsblk           # Linux  — same idea

Note the device path: on macOS it will be something like /dev/disk4 (use the raw variant /dev/rdisk4 for dd); on Linux something like /dev/sdb.

Unmount (macOS only) — do this before writing

diskutil unmountDisk /dev/diskN   # replace diskN with your disk, e.g. disk4

Write the image

The pipe form decompresses on the fly, so you don't need free disk space for the uncompressed .img:

# macOS — /dev/rdiskN is the raw (fast) device
xz -dc piwalletsv-<VERSION>.img.xz | sudo dd of=/dev/rdiskN bs=4m

# Linux
xz -dc piwalletsv-<VERSION>.img.xz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync

Or decompress first if you prefer two separate steps:

unxz piwalletsv-<VERSION>.img.xz          # produces .img alongside .img.xz
sudo dd if=piwalletsv-<VERSION>.img of=/dev/rdiskN bs=4m   # macOS
sudo dd if=piwalletsv-<VERSION>.img of=/dev/sdX bs=4M status=progress conv=fsync  # Linux
sync

Eject (macOS)

diskutil eject /dev/diskN

Triple-check the device path

dd has no undo. Writing to the wrong device will silently overwrite your system disk or another drive. Verify diskutil list / lsblk output carefully before running the write command.

Received a pre-flashed kit?

You should re-flash from a verified download (recommended) before you create a wallet. Optional: compare Image ID on kit paperwork, or hash the SD in a computer reader without booting the Pi. See User manual § Verify your SD card on arrival.

Step 3 — Assemble the hardware

  1. Insert the flashed SD card into the Pi Zero 2 W.
  2. Plug the bonnet onto the Pi's GPIO header. The bonnet's PWR-IN micro-USB port is the one farther from the SD slot; that's where you'll connect power.
  3. Connect the Pi Camera ribbon to the Pi's CSI port (small flex cable connector under the bonnet, near the SD slot edge).
  4. Plug the 5 V power supply into the bonnet's PWR-IN.

The first boot after flashing takes longer than normal because the image expands the root partition to your SD card size, then reboots once. Expect roughly 2–3 minutes total on a Pi Zero W before the disclaimer (about 1–2 minutes longer than everyday boots).

Phase What you see
Power on → ~60–90 s Panel may stay dark while the Pi boots
First boot Automatic reboot when SD expansion finishes
Second boot Logo splash → disclaimer (~1 minute after power-on)

Every boot after that is a single boot (~1 minute to splash). The panel may stay dark until the logo appears — that is normal on Pi Zero W.

If the panel stays blank for more than 3–5 minutes after the second boot, check HDMI tty2 or re-flash.

Step 4 — Accept the disclaimer

The bonnet will show the legal disclaimer the very first time it boots. Read it; the alpha-software language is not boilerplate. Use the joystick to scroll, and press A to accept.

The acceptance is recorded in ~/.piwallet/terms.json and you won't see this screen again unless the disclaimer version changes.

Step 5 — First setup (vault)

You'll see First setup with two choices:

  • New vault (set PIN) — choose and confirm a vault PIN. Use the joystick to scroll digits, A to confirm each digit, B to delete. The PIN protects the encrypted vault on disk; use a long PIN (12+ digits) for cold storage.
  • Restore from USB — import a backup stick if you're replacing the SD card or upgrading firmware (User manual § USB backup).

If you chose New vault, the bonnet drops you on an empty wallet list after PIN setup.

Step 6 — Create or restore your first wallet

From the wallet list, choose:

  • + New wallet — the bonnet generates a fresh BIP39 mnemonic on device. The mnemonic is shown to you a few words at a time so you can write it down on paper. Write it down: this is the only way to recover the wallet if the SD card is damaged or wiped.
  • + Restore wallet — you enter an existing 12- or 24-word BIP39 mnemonic via the on-screen word-entry keyboard. The bonnet validates the checksum word so a typo is caught before the wallet is created.

In either case you'll be asked for a short label (so you can tell multiple wallets apart later) and the BIP-44 derivation path. The bonnet defaults to the BSV mainnet path (m/44'/236'/0'); change this only if you know exactly why.

When this step completes, the bonnet drops you onto the wallet list screen. The wallet you just created is the one row.

Step 7 — Verify the air-gap

Before you trust this device with anything sensitive, prove to yourself that it's actually quiet on the airwaves. From the wallet list:

  1. Press B to open Settings.
  2. Joystick down to “Airgap status”.
  3. Press A.

You should see a green “Air-gapped” header and three summary rows (Wi-Fi, Bluetooth, Network) reading OK. The full reference for the header, status glyphs (OK / !! / --), and each check row lives in the User manual § Airgap status; it is included here for convenience:

The title band at the top is the overall verdict:

Header Meaning
Air-gapped (green) Every check that could run passed. Safe to proceed.
BREACH (red) At least one check failed conclusively. Do not sign until the leak is understood and fixed.

Status column (bonnet)

Each row shows a friendly label on the left and a plain-English status on the right:

Status Meaning
Disabled (green) That radio or network path looks off — no leak found.
Active (red) Something is live — treat as BREACH.
Unknown (grey) Could not verify from the bonnet app alone. Re-flash or run the shell diagnostic below.

On a healthy sealed device you should see Disabled on all three rows and a green Air-gapped header.

The CLI still uses compact glyphs (OK, !!, --) in piwallet diag airgap output.

Check rows (bonnet UI)

The Settings screen shows three summary rows. Each rolls up several technical checks so you do not need to read kernel module names:

Row What it covers
Wi-Fi No Wi-Fi driver loaded; radios blocked; Wi-Fi services off; firmware disables Wi-Fi at boot; modules blacklisted.
Bluetooth Same checks for Bluetooth (hciuart, bluetooth, etc.).
Network Only the loopback interface is present inside the bonnet app's network sandbox (PrivateNetwork=yes).

A green Network row confirms the bonnet sandbox is intact. It does not by itself prove the host Pi has no other interfaces — for that, run the full six-check report from a shell (below).

On some older images, Wi-Fi and Bluetooth could show Unknown when rfkill sysfs was unreadable inside the bonnet sandbox even though radios were actually disabled. Current firmware shows Disabled when every conclusive sub-check passes.

Full report from a shell

piwallet diag airgap lists six technical rows (modules, rfkill, interfaces, services, boot_config, blacklist) and sees the host directly. Use it periodically and whenever the on-screen result looks wrong:

piwallet diag airgap              # table; exit 1 on BREACH
piwallet diag airgap --json       # machine-readable

See Operate § Airgap diagnostic and CLI § piwallet diag airgap.

Controls

Button Action
A Refresh — re-run all checks.
B Back to Maintenance.

If you see BREACH

  1. Stop. Do not sign transactions on this device until the report is all-green.
  2. Note which rows show ActiveWi-Fi or Bluetooth failures map to drivers, radios, services, boot overlays, or blacklists; Network failures usually mean the bonnet sandbox is broken.
  3. If you flashed a prebuilt image, re-verify the download signature and re-flash. If the second flash still fails, contact @PiWalletSV on X or file an issue on GitHub with the failing rows (or piwallet diag airgap --json output).
  4. Re-check after any SD-card reflash, config edit, or software update, and before signing anything you would regret.

If any row shows !!, stop and follow the BREACH steps above. For a prebuilt image, re-do Step 1 (signature verification) and re-flash before contacting support.

Step 8 — Pair with the companion PWA

The PiWalletSV companion is a Progressive Web App that handles the online half of the wallet (UTXO discovery, watch-only balances, broadcast). It never sees your private keys.

  1. On a separate device with a camera, open the companion in a modern browser.

Add the companion to your Home Screen

  1. Open the companion in Safari.
  2. Tap Share (square with ↑).
  3. Scroll and tap Add to Home Screen.
  4. Confirm the name PiWalletSVAdd.

Opens full-screen without the browser chrome — handy for camera pairing and sends.

  1. Open the companion in Chrome.
  2. Tap the menu → Install app or Add to Home screen (wording varies by version). Or accept the in-app Install banner on the Wallets page if shown.
  3. Confirm Install.

Optional — mainly for development. Use the install icon in the address bar (⊕ or computer icon) after visiting the companion over HTTPS.

  1. The companion's first-run flow walks you through pairing: it shows a button to start a pairing handshake.
  2. On the bonnet, scroll to the wallet on the wallet list and press A to open it. From the wallet detail screen, choose “Pair with companion”.
  3. The bonnet shows an animated QR sequence containing your wallet's public extended key (xpub). The companion captures the frames with its camera and reconstructs the pairing payload.

The pairing handshake transmits only the xpub, never private material. Once it completes, the companion can derive addresses, scan the chain for your UTXOs, and prepare unsigned transaction proposals — but it cannot move funds without sending those proposals back to the bonnet for an explicit human-confirmed signature.

Step 9 — Sign your first transaction

To round-trip the full flow with no risk:

  1. In the companion, switch to TESTNET mode (Settings → Network).
  2. Send a small TESTNET amount to one of your wallet's receive addresses (use a faucet such as satoshisvision.network).
  3. Once the UTXO is visible in the companion, draft an outgoing TESTNET transaction (back to the faucet, or to any TESTNET address you control).
  4. The companion produces an unsigned proposal as an animated QR sequence. Point the bonnet's camera at the screen.
  5. The bonnet reconstructs the proposal, displays the human-readable summary (output addresses, amounts, fee), and asks for the PIN.
  6. Approve. The bonnet signs and produces an animated QR of the signed transaction for the companion to capture.
  7. The companion broadcasts the signed transaction to the BSV testnet via WhatsOnChain.

If steps 1–7 round-trip cleanly on TESTNET, the device is fully operational.

Routine use

Day-to-day, you only do steps 5–7 from above:

  • Power on; enter PIN.
  • Select wallet from the list.
  • Camera in, scan unsigned proposal.
  • Approve and PIN.
  • Camera out, show signed QR back to the companion.

When you're done, you can simply unplug the device. There's no “safe shutdown” ritual: the bonnet's filesystem is read-only except for the small .piwallet/ state directory, and write operations there are deliberately atomic.

Updating

There is no in-place update mechanism, by design: an air-gapped device that can pull updates is not air-gapped. The full end-user workflow — backup, re-flash, restore mnemonic or vault file, and post-upgrade verification — is documented in User manual § Upgrade your device.

Brief summary:

  1. Back up your mnemonic and/or run Settings → Maintenance → USB backup → Backup to USB (or copy vault.bin off the SD card) before flashing.
  2. Download and verify a new image from Download (Step 1 above).
  3. Re-flash the microSD (Step 2 above).
  4. Restore from your written-down mnemonic, or copy vault.bin back onto the new image — see the user manual for step-by-step detail.
  5. Re-run Airgap status and a TESTNET smoke test.

Troubleshooting

Panel stays dark after 60 seconds. Most often the bonnet isn't fully seated on the GPIO header, or the camera ribbon is loose. Power off, re-seat both, and try again. If the bonnet's tiny green LED never lights, you have a power-supply problem (5 V/2.5 A or better is the minimum).

Joystick or buttons unresponsive. A bonnet revision difference: some early Adafruit batches mount the joystick chip on a different I2C address. Contact @PiWalletSV on X or open an issue on GitHub with your bonnet's silkscreen revision string.

Camera doesn't detect QR codes. The kit ArduCam OV5647 is fixed-focus around 30 cm (~1 ft). If your companion device is closer or farther, the QR sequence will be blurry. Hold the bonnet at about that distance while scanning.

“Airgap status” shows BREACH. This is the diagnostic working as designed: it found a leak. See User manual § Airgap status for what each indicator means. Don't sign anything until the report is all-green. The fastest fix is to re-verify the image signature (Step 1) and re-flash.

For everything else, see Operate or Help & support.

Help & support

General questions and usage help: @PiWalletSV on X.

Bug reports and feature requests: GitHub Issues.

Security vulnerabilities: use the private channel in Security briefing — not X or public issues.