← Owner's Log
AstonPi
Raspberry Pi 5 CarPlay Head Unit · Project Build Log
Live in car: 29 April 2026
Base: react-carplay v4.0.5
github.com/zoobuv101/AstonPi

01 / The Idea

A polished, ignition-controlled wireless CarPlay head unit for the DB9, built on a Raspberry Pi 5 and a custom dark theme over react-carplay. The design goal was a seamless single-logo experience: from the moment the ignition goes live to the live CarPlay session, the screen shows one continuous Aston Martin logo — no black frames, no white flashes, no console text, no "No Signal" OSD. The same discipline applies at shutdown: the AM splash returns and holds until power is cut.

Live in car ✓  Installed and running in the car since 29 April 2026 — ignition boot/shutdown, breathing splash chain, per-stream volume mixer, knob control, wireless CarPlay and DAC audio all confirmed working in-car.

02 / Hardware

ItemRole / notes
Raspberry Pi 5 + NVMe SSDNVMe boot via CarPiHat slot; RP1 GPIO needs lgpio/rpi-lgpio
CarPiHat Pro v1.1 (Pi 5 variant)Ignition-controlled power latch, Burr-Brown DAC, NVMe slot, switched 12 V outputs
Carlinkit CPC200-AutokitUSB dongle — wireless CarPlay bridge to the iPhone
1024×600 HDMI displayVehicle-installed panel; 5 V power switched via CarPiHat OUT_0 + buck converter
Programmable rotary knobCheap "MINI_KEYBOARD" rotary, USB-C wired, mapped to react-carplay's default key bindings
USB microphoneIn-car Siri input; phone calls stay on the car's factory Bluetooth kit
WiringPermanent 12 V → BAT · switched 12 V (ignition) → IGN · GND → chassis

Key CarPiHat GPIO assignments (BCM)

BCMDirectionFunction
25OUTPower latch — held HIGH from firmware stage (gpio=25=op,dh)
12INIgnition sense (opto-isolated 12 V)
27OUTOUT_0 — delayed monitor power (OUT_1/BCM22 didn't switch in testing; BCM27 did)

03 / The Boot Story

What the car experience looks like, power-on to CarPlay:

Shutdown mirrors it: ignition off starts a 10 s grace timer, then the shutdown daemon signals the app over socket.io — the AM splash returns, holds for 5 s (during which turning the ignition back on aborts the shutdown and CarPlay resumes), then a clean systemctl poweroff runs with the splash held until the CarPiHat cuts 5 V. Boot is fully automatic on ignition — no power button anywhere.

04 / Audio — Per-Stream Volume Mixer

The CarPiHat's Burr-Brown DAC runs as ALSA card 0 (HDMI audio disabled via vc4-kms-v3d,noaudio), streaming 48 kHz / S32_LE during CarPlay. On top of that sits a custom per-stream volume mixer matching commercial head units: adjusting volume during navigation speech changes nav volume, not music.

⚠ Bug worth remembering: PcmPlayer.volume(v, duration) takes duration in seconds (it forwards to WebAudio's setTargetAtTime). Passing 200 (intending ms) schedules the volume ramp 200 seconds into the future — which presents as "volume control does nothing".

05 / Hard-Won Lessons

The Pi 5 firmware rainbow cannot be replaced Boot research
On the Pi 5 the VideoCore boot firmware lives in write-protected SPI EEPROM as a closed Broadcom blob — the rainbow splash is generated algorithmically, not stored as an image. No tool or fork can swap it. The real fix for the "No Signal" OSD was the opposite of intuition: re-enable the rainbow (disable_splash=0) so the panel gets a valid HDMI signal from ~1 s, then hide the early boot entirely by delaying the monitor's own power rail.
Wayland, not X11 — and sway, not cage Compositor
X11's root-window stipple caused a visible white flash on every boot; Wayland has no equivalent. cage was then swapped for sway because sway's seat * hide_cursor 1 kills the 1–2 s default mouse pointer cage showed at startup. Electron runs with --in-process-gpu, which dodges a dma-buf crash the separate GPU sandbox process hits on Pi 5 + Bookworm Wayland.
EEPROM BOOT_ORDER=0xf6, not 0x1 Fast boot
NVMe-with-restart-loop skips USB/SD probing and saves ~1 s pre-kernel. 0x1 looks like "first boot device" but actually means SD card — an easy footgun. Combined with initial_turbo=60, a pre-extracted AppImage, direct systemd kiosk service and a tmpfs Electron profile, measured kernel+userspace is ~3 s.
Wired beats wireless for the control knob Inputs
The rotary knob advertises a fake Apple vendor ID (05AC:022C) over Bluetooth, which trips the hid-apple driver and needs experimental bluez flags, udev seat tags and hotplug handling — too brittle for a car. USB-C wired is rock solid, with the cable routed inside the dash.
Keep the customisation footprint tiny Maintainability
A previous theming attempt destabilised the upstream app because edits spread through the codebase. The rebuild keeps all customisation to three new files plus three small wiring edits, applied by a single overlay script — so rebasing onto new upstream react-carplay releases stays painless.
No reliable "first frame" signal? Make one Polish
Originally the boot splash faded on a hard-coded timer after the phone connected — safe but imprecise. The proper fix was instrumenting the render worker to post a firstFrame message on its first successful draw, so the splash disappears exactly when CarPlay's first real pixel lands.

06 / In-Car Status & Known Issues

Everything bench-tested was confirmed working in the car: ignition boot and shutdown, the continuous splash chain, per-stream mixer, knob control, wireless CarPlay and DAC audio, delayed monitor power.

⚠ Known issue: an occasional BAT-rail power glitch (mechanical connection, not software) can brownout-latch the Pi 5 SoC — solid red LED, needing a BAT power cycle to recover. Planned fix: a hidden normally-closed pushbutton inline with the BAT feed as a recovery mechanism.

Parked / future ideas

AstonPi · Raspberry Pi 5 CarPlay head unit · live in car 29-04-2026 Owner's log