noisebell/pi
2026-03-23 23:21:24 -07:00
..
pi-relay feat: add home assistant capability with pi-relay 2026-03-23 23:21:24 -07:00
pi-service feat: add basic rss feat support 2026-03-23 13:56:00 -07:00
.envrc feat: update readmes and keys and fixes 2026-03-17 02:57:47 -07:00
configuration.nix feat: update ot synchronous gpio and rotate keys 2026-03-23 01:49:01 -07:00
flake.lock feat: expose configurations, add retry, make stable 2026-03-09 17:11:22 -07:00
flake.nix feat: update age configuration to be inside 2026-03-17 03:51:09 -07:00
hardware-configuration.nix feat!: make declarative version 2026-03-22 17:40:48 -07:00
module.nix fix: active poll instead of wait for interupt 2026-03-23 13:22:55 -07:00
README.md feat: add home assistant capability with pi-relay 2026-03-23 23:21:24 -07:00

Pi

Rust service and deployment workflow for the Raspberry Pi at Noisebridge.

The current recommended setup is:

  1. run Raspberry Pi OS Lite on the Pi
  2. keep the Pi itself free of Nix
  3. build a static aarch64 Noisebell binary on your laptop with Nix
  4. copy the binary, secrets, and systemd service to the Pi over SSH

This avoids the Raspberry Pi Zero 2 W NixOS boot issues while still keeping the application build reproducible.

What stays on Raspberry Pi OS

  • bootloader
  • kernel
  • firmware
  • Wi-Fi and local networking
  • SSH base access
  • Tailscale package/runtime
  • Avahi package/runtime

What Nix manages

  • building a static noisebell binary for aarch64-linux
  • the exact app binary you deploy
  • encrypted secrets in the repo
  • repeatable deployment from your laptop

Initial Pi OS setup

1. Flash Raspberry Pi OS Lite

curl -L "https://downloads.raspberrypi.org/raspios_lite_arm64_latest" | xz -d -c | sudo dd of=/dev/sdb bs=16M conv=fsync status=progress && sync

2. Configure the flashed SD card

Configure it for:

  • Wi-Fi on Noisebridge
  • SSH enabled
  • serial enabled if you want a recovery console

The helper script is:

sudo scripts/configure-pios-sd.sh /run/media/jet/bootfs /run/media/jet/rootfs

This setup expects SSH key login for user pi; it does not configure a password.

3. Boot the Pi and verify SSH

After boot, verify SSH works:

ssh pi@noisebell-pi.local

Add the Pi host key to age recipients

The deploy flow decrypts secrets locally on your laptop, but the Pi host key should still be a recipient for the Pi-facing secrets so the repo stays accurate.

Grab the Pi host key:

ssh-keyscan noisebell-pi.local 2>/dev/null | grep ed25519

Add that key to secrets/secrets.nix for:

  • pi-to-cache-key.age
  • cache-to-pi-key.age
  • tailscale-auth-key.age

Then refresh recipients if needed:

cd secrets
agenix -r

Edit secrets

cd secrets
agenix -e pi-to-cache-key.age
agenix -e cache-to-pi-key.age
agenix -e tailscale-auth-key.age

These stay encrypted in git. The deploy script decrypts them locally on your laptop and copies the plaintext files to the Pi as root-only files.

Deploy to Raspberry Pi OS

From your laptop:

scripts/deploy-pios-pi.sh pi@noisebell-pi.local

If you only know the IP:

scripts/deploy-pios-pi.sh pi@10.21.x.x

That script:

  1. builds .#packages.aarch64-linux.noisebell-static locally
  2. builds .#packages.aarch64-linux.noisebell-relay-static locally
  3. decrypts the Pi-facing secrets locally with agenix
  4. uploads the binaries and secrets to the Pi
  5. installs Tailscale and Avahi if needed
  6. writes /etc/noisebell/noisebell.env
  7. writes /etc/noisebell/noisebell-relay.env
  8. installs noisebell.service and noisebell-relay.service
  9. enables and starts both services
  10. runs tailscale up with the decrypted auth key

Files written on the Pi

The deploy script creates:

  • /opt/noisebell/releases/<timestamp>/noisebell
  • /opt/noisebell/releases/<timestamp>/noisebell-relay
  • /opt/noisebell/current -> current release symlink
  • /etc/noisebell/pi-to-cache-key
  • /etc/noisebell/cache-to-pi-key
  • /etc/noisebell/relay-webhook-secret
  • /etc/noisebell/homeassistant-webhook-id
  • /etc/noisebell/tailscale-auth-key
  • /etc/noisebell/noisebell.env
  • /etc/noisebell/noisebell-relay.env
  • /etc/systemd/system/noisebell.service
  • /etc/systemd/system/noisebell-relay.service

All secret files are root-only.

Tailscale

Tailscale is kept on Raspberry Pi OS rather than NixOS.

The deploy script:

  • installs the Tailscale package if missing
  • enables tailscaled
  • runs tailscale up --auth-key=... --hostname=noisebell-pi

So Tailscale stays part of the base OS, while its auth key is still managed as an encrypted age secret in this repo.

Later updates

Normal iteration is just rerunning the deploy script:

scripts/deploy-pios-pi.sh pi@noisebell-pi.local

That rebuilds the binary locally, uploads a new release, refreshes secrets, and restarts the service.

Service configuration

The deployed service uses these environment variables:

Variable Default Description
NOISEBELL_GPIO_PIN 17 GPIO pin number
NOISEBELL_DEBOUNCE_MS 50 Debounce delay in milliseconds
NOISEBELL_PORT 80 HTTP server port
NOISEBELL_ENDPOINT_URL required Webhook URL to POST state changes to
NOISEBELL_RETRY_ATTEMPTS 3 Webhook retry count
NOISEBELL_RETRY_BASE_DELAY_SECS 1 Exponential backoff base delay
NOISEBELL_HTTP_TIMEOUT_SECS 10 Outbound request timeout
NOISEBELL_BIND_ADDRESS 0.0.0.0 HTTP bind address
NOISEBELL_ACTIVE_LOW true Low GPIO = door open

Relay service configuration

The optional relay service accepts authenticated webhooks from cache-service and forwards them to Home Assistant on the local network.

Variable Default Description
NOISEBELL_RELAY_PORT 8090 HTTP port for the relay webhook endpoint
NOISEBELL_RELAY_BIND_ADDRESS 0.0.0.0 HTTP bind address
NOISEBELL_RELAY_TARGET_BASE_URL http://homeassistant.local:8123 Base URL for Home Assistant
NOISEBELL_RELAY_TARGET_WEBHOOK_ID required Home Assistant webhook ID
NOISEBELL_RELAY_INBOUND_API_KEY required Bearer token expected from cache-service
NOISEBELL_RELAY_RETRY_ATTEMPTS 3 Forward retry count
NOISEBELL_RELAY_RETRY_BASE_DELAY_SECS 1 Exponential backoff base delay
NOISEBELL_RELAY_HTTP_TIMEOUT_SECS 10 Outbound request timeout

Example cache target for the relay:

{
  services.noisebell-cache.outboundWebhooks = [
    {
      url = "http://noisebell-pi.local:8090/webhook";
      secretFile = /run/agenix/noisebell-relay-webhook-secret;
    }
  ];
}

API

All endpoints require Authorization: Bearer <token>.

GET /

{"status": "open", "timestamp": 1710000000}