Files
frigate_w_audio/pi
Claude b3940685c4 Add camera selector dropdown to doorbell page
Replaces the hardcoded CAMERA_NAME with a CAMERAS list. The page renders
a dropdown when more than one camera is configured and remembers the
choice in localStorage; switching tears down and reopens the WebRTC
connection.

https://claude.ai/code/session_013XZ1vmgk78k2PEQ5DmJhF3
2026-04-25 19:10:37 +00:00
..
2026-04-25 11:06:10 -04:00
2026-04-25 11:06:10 -04:00

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

# 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

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

server.py near the top has the list of cameras the page offers:

CAMERAS = ["front_door"]

Each name must match a go2rtc.streams entry in frigate_config/config.yml and the camera must be enabled: true in Frigate. With more than one entry the page shows a dropdown above the talk button; the choice is remembered per-browser in localStorage. The first entry is the default for new visitors.

After editing:

sudo systemctl restart doorbell

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:

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:

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.