This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Nix 54.9%
Rust 38.4%
Just 6.7%
5 1 0

Clone this repository

https://tangled.org/brongan.com/pi-ambilight-receiver https://tangled.org/did:plc:tyhdodug4rseniodmun5ucjw
git@tangled.org:brongan.com/pi-ambilight-receiver git@tangled.org:did:plc:tyhdodug4rseniodmun5ucjw

For self-hosted knots, clone URLs may differ based on your setup.



README.md

pi-ambilight-receiver — Install Guide#

NixOS on Raspberry Pi 3 (B/B+/A+/Zero 2 W) running a WS2812B LED strip receiver over SPI. Receives Hyperion UDP packets on port 19446.

Prerequisites#

On your build host (x86_64 Linux):

  • Nix with flakes enabled (experimental-features = nix-command flakes in ~/.config/nix/nix.conf)
  • QEMU binfmt registered for aarch64 (check: ls /proc/sys/fs/binfmt_misc/qemu-aarch64)
  • Nix knows about aarch64: /etc/nix/nix.conf must contain extra-platforms = aarch64-linux (restart nix-daemon after adding)
  • just (cargo install just or nix shell nixpkgs#just)
  • A microSD card (8 GB minimum, 16+ GB recommended)

Quick Start#

# 1. Build the SD image (~5-15 min first time)
just build-image

# 2. Flash to SD card (find your device with lsblk)
just flash /dev/sdX



# 4. Insert SD card into Pi, connect ethernet, power on
# 5. SSH in (wait ~60s for first boot)
ssh pi@pi    # or ssh pi@<IP from your router>

What's on the Image#

Component Details
OS NixOS 25.05 (aarch64), minimal profile
Network systemd-networkd, DHCP on all ethernet interfaces
SSH Enabled, key-only auth for pi and root
Tailscale Enabled, auto-joins if /var/lib/tailscale/authkey exists
Firewall UDP 19446 open, tailscale0 trusted
Service pi-ambilight-receiver — starts on boot, restarts on failure
SPI Enabled via device tree overlay, udev rule sets group spi
Swap zRAM swap (safety net for the Pi's limited RAM without burning the SD card)

Updating the Pi#

To apply system updates or push changes over SSH:

just deploy          # build on your machine, push result to Pi
just dry-run         # preview changes without applying

Hardware Wiring#

The receiver uses SPI0 MOSI (GPIO 10, physical pin 19) to drive WS2812B LEDs. No level shifter is needed for short runs — the Pi's 3.3V output is within the WS2812B's logic threshold when powered at 5V.

Pi GPIO 10 (pin 19) ──────── DIN on LED strip
Pi GND     (pin 6)  ──────── GND on LED strip
5V supply           ──────── VCC on LED strip
5V supply GND       ──────── GND on LED strip (and Pi GND)

Do not power the LED strip from the Pi's 5V pin unless you have fewer than ~10 LEDs. Use a separate 5V supply and share a common ground.

Reinstalling from Scratch#

If the SD card corrupts or you want a clean start:

just build-image
just flash /dev/sdX

The Pi's state (Tailscale identity, any local files) will be lost. Tailscale will re-register with a new node if using an ephemeral key.


Troubleshooting#

Pi doesn't boot / no HDMI output#

  • Wrong Pi model? This image targets aarch64 (Pi 3, Pi Zero 2 W, Pi 4, Pi 5). It will not boot on Pi Zero (original), Pi 1, or Pi 2 — those are armv6/armv7.
  • SD card not flashed correctly. Re-flash with just flash. Make sure you're writing to the whole device (/dev/sda) not a partition (/dev/sda1).
  • SD card too slow or failing. NixOS boot takes longer than Raspbian. Wait at least 2 minutes. Try a different SD card if it never comes up.

Can't SSH in#

  • Pi hasn't finished booting yet. First boot takes 60-120s. Check your router's DHCP leases for hostname pi.
  • Wrong SSH key. The image only accepts the ed25519 keys hardcoded in nixos/configuration.nix. If you regenerated your SSH keys, rebuild the image.
  • No network. If using Wi-Fi, ensure it was properly configured before building. There's no fallback if it fails to connect.
  • Firewall on your network. SSH (port 22) must be reachable. If on a restrictive network, use Tailscale (pre-provision the auth key).

Service crashes on start#

Check logs: ssh pi@pi journalctl -u pi-ambilight-receiver

"Failed to open SPI device"

  • /dev/spidev0.0 doesn't exist. The device tree overlay may not have applied. SSH in and check: ls /dev/spidev*. If missing:
    • Verify the DTB overlay built correctly: ls /run/current-system/dtbs/
    • Check kernel messages: dmesg | grep -i spi
    • Try loading the module manually: sudo modprobe spidev

"Permission denied" on SPI

  • The udev rule may not have fired. Check device permissions: ls -l /dev/spidev0.0 — it should be crw-rw---- root spi.
  • Verify the ambilight user is in the spi group: id ambilight
  • Reboot to re-trigger udev rules.

"SPI Write Failed"

  • Wiring issue. Check GPIO 10 is connected to the LED strip DIN.
  • Power issue. The LED strip needs its own 5V supply.

"Kernel buffer limit hit"

  • Too many LEDs for the default spidev buffer. The config sets spidev.bufsiz=65536 which supports ~7000 LEDs. If you somehow exceed this, increase the value in nixos/service.nix.

LEDs flicker or show wrong colors#

  • Wrong SPI clock speed. The WS2812B driver uses 2.4 MHz to encode 3 SPI bits per data bit. If the kernel adjusts the clock to a different value, timing breaks. Check: cat /sys/class/spi_master/spi0/spi0.0/statistics/
  • Long wire run. Signal degrades over distance. Keep the wire between GPIO 10 and the first LED under 1 meter. Use a logic level shifter (3.3V→5V) for longer runs.
  • Insufficient power. Each WS2812B LED draws up to 60mA at full white. 150 LEDs = 9A peak. If your supply can't keep up, colors go wrong. Inject power at multiple points on long strips.

Tailscale doesn't connect#

  • No auth key provisioned. The file /var/lib/tailscale/authkey must exist on the SD card before first boot.
  • Auth key expired or single-use. Generate a new reusable key at https://login.tailscale.com/admin/settings/keys
  • Check status: ssh pi@pi tailscale status
  • Check service: ssh pi@pi systemctl status tailscaled

Out of disk space#

NixOS keeps old system generations. The config runs weekly GC, but you can trigger it manually:

ssh pi@pi sudo nix-collect-garbage -d

OOM / Pi freezes during deploy#

The Pi 3 has 1 GB RAM (Zero 2 W has 512 MB). Building NixOS on-device can OOM. just deploy will build on your machine and only copy the result to the Pi. zRAM swap is configured as a safety net.

Need to recover a bricked Pi#

If the Pi won't boot and you need data off the SD card:

# Mount root partition on your build host
sudo mount /dev/sdX2 /mnt
# Copy what you need, then reflash
sudo umount /mnt
just flash /dev/sdX

File Layout#

pi-ambilight-receiver/
├── flake.nix                  # Build + NixOS system definitions
├── flake.lock                 # Pinned dependency versions
├── justfile                   # Task runner recipes
├── Cargo.toml                 # Rust project
├── Cargo.lock
├── src/
│   ├── main.rs                # UDP receiver → SPI writer
│   ├── lib.rs                 # WS2812B SPI driver
│   └── bin/rainbow.rs         # Test pattern binary
└── nixos/
    ├── configuration.nix      # System config (users, network, SSH, etc.)
    ├── service.nix            # systemd service + SPI setup
    └── disk-config.nix        # Partition layout (for nixos-anywhere path)