3.3 KiB
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:
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:
# 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:
ssh-keyscan <pi-ip> | grep ed25519
# 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:
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:
users.users.root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAA..."
];
6. Deploy
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:
{"status": "open", "timestamp": 1710000000}
GET /info — system health and GPIO config:
{
"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 <api-key> header.