Files
Claude 09d5b28e3d Revert camera dropdown; add PEER_LINKS for sibling Pis
The dropdown allowed switching the video feed but PTT always pointed at
this Pi's local speaker, so picking a non-co-located camera could have
let a user talk into the wrong room. Each Pi is now hardcoded to the
camera at its own location via CAMERA_NAME, with optional PEER_LINKS to
render quick-jump buttons to sibling doorbell Pis at other URLs.

https://claude.ai/code/session_013XZ1vmgk78k2PEQ5DmJhF3
2026-04-25 21:23:17 +00:00

127 lines
3.8 KiB
Markdown

# Pi doorbell PTT
Turns a Raspberry Pi into a network speaker so a phone hitting
`https://doorbell.yourdomain.com` can see/hear the front-door Frigate feed
and hold a button to talk through a speaker mounted at the door.
## Hardware
- Any Raspberry Pi (Zero W 1st gen is enough; Zero 2 W is better for live
two-way; Pi 3A+ has a 3.5mm jack onboard and skips the OTG adapter)
- Audio output, one of:
- USB speaker + micro-USB-to-USB-A OTG adapter (simplest)
- 3.5mm powered speaker (Pi 3A+ has the jack; Zero W does not)
- I2S DAC HAT (best quality, requires GPIO header)
- microSD card, power supply, WiFi or USB ethernet
## Install on the Pi
```bash
# From your laptop/desktop:
scp -r pi/ pi@PI_LAN_IP:~/doorbell-src
# SSH to the Pi:
ssh pi@PI_LAN_IP
cd ~/doorbell-src
chmod +x install.sh
./install.sh
```
The installer apt-installs ffmpeg + alsa-utils + Python deps, creates a
virtualenv, drops `server.py` into `~/doorbell/`, installs and enables the
systemd service, runs `speaker-test` to confirm ALSA output works, and
starts the service.
## Verify
```bash
curl http://127.0.0.1:5555/healthz # -> ok
sudo journalctl -u doorbell -f # live logs
```
## Wire it up
1. On the Caddy host, add the `doorbell.yourdomain.com` block from
`../caddy/Caddyfile` and reload Caddy.
2. DNS: point `doorbell.yourdomain.com` at the Caddy host's public IP.
3. Open `https://doorbell.yourdomain.com` on an Android phone.
4. Grant the one-time microphone permission.
5. Tap **Unmute camera** if browser autoplay swallowed the audio.
6. Hold the big green button to talk.
Add to home screen (Chrome menu -> Add to home screen) for an app-like
experience.
## Choosing the camera
Each Pi is hardcoded to one camera -- the one whose mic and speaker are
physically co-located with this Pi. The PTT button on this page only
talks to *this* Pi's speaker, so mixing cameras here would let a misclick
talk into the wrong room.
`server.py` near the top:
```python
CAMERA_NAME = "front_door"
```
The name must match a `go2rtc.streams` entry in
`frigate_config/config.yml` and the camera must be `enabled: true` in
Frigate. After editing:
```bash
sudo systemctl restart doorbell
```
## Multiple doorbell Pis
Run one copy of this app per Pi, each on its own subdomain (e.g.
`frontdoor.yourdomain.com`, `backdoor.yourdomain.com`). Add a Caddy
block per subdomain pointing at that Pi's LAN IP -- same shape as the
existing `doorbell.yourdomain.com` block in `../caddy/Caddyfile`.
To render quick-jump buttons to the other Pis at the top of the page,
fill in `PEER_LINKS` near the top of `server.py`:
```python
PEER_LINKS = [
{"label": "Back door", "url": "https://backdoor.yourdomain.com"},
{"label": "Squirrel", "url": "https://squirrel.yourdomain.com"},
]
```
Leave it as `[]` (the default) and the row is hidden. Restart with
`sudo systemctl restart doorbell` after editing.
## Audio stack
ALSA-only -- no PipeWire/PulseAudio. Lighter on the Pi Zero. If you ever
need PipeWire (e.g., to share the speaker with another app), change
`'-f', 'alsa'` to `'-f', 'pulse'` in `server.py` and install the
PipeWire/Pulse compatibility shim.
## Troubleshooting
### speaker-test fails
USB/3.5mm output isn't the default ALSA card. Check:
```bash
aplay -l
```
If your speaker isn't card 0, create `/etc/asound.conf`:
```
defaults.pcm.card 1
defaults.ctl.card 1
```
(Replace `1` with whatever card your speaker is.)
### Video plays but talk button stuck on "Disconnected"
The WebSocket isn't reaching the Pi. Most common: Caddy not proxying
`doorbell.yourdomain.com` -> Pi correctly. From the Caddy host:
```bash
curl -i http://PI_LAN_IP:5555/healthz # should return 200 ok
```
### Feedback loop when talking
The page auto-mutes the camera while the PTT button is held, so this
should not happen. If it does, increase distance between Pi speaker and
camera mic, or turn the speaker volume down.