README.md

Pi

Rust service and NixOS config for the Raspberry Pi at Noisebridge. Reads a magnetic door sensor via GPIO, serves the current state over HTTP, and pushes changes to the cache service.

Runs NixOS with Tailscale for remote access and agenix for secrets.

How it works

The service watches a GPIO pin for rising/falling edges with a configurable debounce. When the door state changes, it:

  1. Updates in-memory state (atomics)
  2. POSTs {"status": "open", "timestamp": ...} to the cache service with a Bearer token
  3. Retries with exponential backoff on failure

On startup it also syncs the initial state.

Setup

1. Flash the SD card

sh
1nix build .#nixosConfigurations.bootstrap.config.system.build.sdImage
2dd if=result/sd-image/*.img of=/dev/sdX bs=4M status=progress

Boot the Pi. It connects to the Noisebridge WiFi automatically.

2. Find the Pi

sh
1nmap -sn 192.168.1.0/24
2# or
3arp -a

3. SSH host key

Grab the key and add it to secrets/secrets.nix:

sh
1ssh-keyscan <pi-ip> | grep ed25519
nix
1# secrets/secrets.nix
2let
3 pi = "ssh-ed25519 AAAA...";
4in
5{
6 "api-key.age".publicKeys = [ pi ];
7 "inbound-api-key.age".publicKeys = [ pi ];
8 "tailscale-auth-key.age".publicKeys = [ pi ];
9}

4. Create secrets

sh
1cd secrets
2agenix -e api-key.age # key for POSTing to the cache
3agenix -e inbound-api-key.age # key the cache uses to poll us
4agenix -e tailscale-auth-key.age # tailscale auth key

5. SSH access

Add your public key to configuration.nix:

nix
1users.users.root.openssh.authorizedKeys.keys = [
2 "ssh-ed25519 AAAA..."
3];

6. Deploy

sh
1nixos-rebuild switch --flake .#pi --target-host root@noisebell

Configuration

Options under services.noisebell in flake.nix:

OptionDefaultDescription
endpointUrlrequiredWebhook URL to POST state changes to
apiKeyFilerequiredOutbound API key file (agenix secret)
inboundApiKeyFilerequiredInbound API key file for GET auth
gpioPin17GPIO pin number
debounceSecs5Debounce delay in seconds
port8080HTTP server port
retryAttempts3Webhook retry count
retryBaseDelaySecs1Exponential backoff base delay
httpTimeoutSecs10Outbound request timeout
bindAddress0.0.0.0HTTP bind address
activeLowtrueLow GPIO = door open (depends on wiring)
restartDelaySecs5systemd restart delay on failure
watchdogSecs30systemd watchdog timeout

API

All endpoints require Authorization: Bearer <token>.

GET / — door state

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

GET /info — system health + GPIO config

json
1{
2 "uptime_secs": 3600,
3 "started_at": 1710000000,
4 "cpu_temp_celsius": 42.3,
5 "memory_available_kb": 350000,
6 "memory_total_kb": 512000,
7 "disk_total_bytes": 16000000000,
8 "disk_available_bytes": 12000000000,
9 "load_average": [0.01, 0.05, 0.10],
10 "nixos_version": "24.11.20240308.9dcb002",
11 "commit": "c6e726c",
12 "gpio": {
13 "pin": 17,
14 "active_low": true,
15 "pull": "up",
16 "open_level": "low",
17 "current_raw_level": "low"
18 }
19}