# noisebell Monitors a GPIO pin on a Raspberry Pi to detect door open/close events. State changes get POSTed to a webhook endpoint. Current state is available over HTTP. Runs on NixOS with Tailscale for networking and agenix for secrets. ## Setup ### 1. Bootstrap Build the SD image, flash it, and boot the Pi: ```sh nix build .#nixosConfigurations.bootstrap.config.system.build.sdImage dd if=result/sd-image/*.img of=/dev/sdX bs=4M status=progress ``` Insert the SD card into the Pi and power it on. It will connect to the Noisebridge WiFi network automatically. ### 2. Find the Pi Once booted, find the Pi on the network: ```sh # Scan the local subnet nmap -sn 192.168.1.0/24 # Or check ARP table arp -a # Or check your router's DHCP leases ``` ### 3. Get SSH host key Grab the Pi's ed25519 host key and put it in `secrets/secrets.nix`: ```sh ssh-keyscan | grep ed25519 ``` ```nix # secrets/secrets.nix let pi = "ssh-ed25519 AAAA..."; # paste the key here in { "api-key.age".publicKeys = [ pi ]; "inbound-api-key.age".publicKeys = [ pi ]; "tailscale-auth-key.age".publicKeys = [ pi ]; } ``` ### 4. Secrets Create the encrypted secret files: ```sh cd secrets agenix -e api-key.age # paste API key for the cache endpoint agenix -e inbound-api-key.age # paste API key that the cache uses to poll the Pi agenix -e tailscale-auth-key.age # paste Tailscale auth key ``` ### 5. Add SSH key Add your SSH public key to `configuration.nix`: ```nix users.users.root.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAA..." ]; ``` ### 6. Deploy ```sh nixos-rebuild switch --flake .#pi --target-host root@noisebell ``` ## Configuration Options under `services.noisebell` in `flake.nix`: | Option | Default | Description | |---|---|---| | `endpointUrl` | — | Webhook endpoint URL to POST state changes to | | `apiKeyFile` | — | Path to file containing outbound API key (agenix secret) | | `inboundApiKeyFile` | — | Path to file containing inbound API key for GET endpoint auth (agenix secret) | | `gpioPin` | 17 | GPIO pin to monitor | | `debounceSecs` | 5 | Debounce delay | | `port` | 8080 | HTTP status port | | `retryAttempts` | 3 | Webhook retry count | | `retryBaseDelaySecs` | 1 | Base delay for exponential backoff | | `httpTimeoutSecs` | 10 | Timeout for outbound webhook requests | | `bindAddress` | `0.0.0.0` | Address to bind the HTTP server to | | `activeLow` | `true` | Whether low GPIO level means open (depends on wiring) | | `restartDelaySecs` | 5 | Seconds before systemd restarts on failure | | `watchdogSecs` | 30 | Watchdog timeout — service is restarted if unresponsive | ## API `GET /` — current door state: ```json {"status": "open", "timestamp": 1710000000} ``` `GET /info` — system health and GPIO config: ```json { "uptime_secs": 3600, "started_at": 1710000000, "cpu_temp_celsius": 42.3, "memory_available_kb": 350000, "memory_total_kb": 512000, "disk_total_bytes": 16000000000, "disk_available_bytes": 12000000000, "load_average": [0.01, 0.05, 0.10], "nixos_version": "24.11.20240308.9dcb002", "commit": "c6e726c", "gpio": { "pin": 17, "active_low": true, "pull": "up", "open_level": "low", "current_raw_level": "low" } } ``` State changes (and initial state on startup) are POSTed to the configured endpoint in the same format as `GET /`, with an `Authorization: Bearer ` header.