2026-04-26 10:09:26 -04:00
2026-04-25 11:06:10 -04:00
2026-04-25 11:06:10 -04:00
2026-04-25 11:06:10 -04:00
2026-04-25 11:06:10 -04:00
2026-04-25 11:06:10 -04:00
2026-04-25 11:06:10 -04:00
2026-04-25 11:06:10 -04:00

Home camera stack

Frigate NVR + Mosquitto MQTT + frigate-notify -> ntfy push notifications, with face recognition and license plate recognition on the Frigate side. Includes a planned Pi Zero W "doorbell speaker" stack (push-to-talk web page fronted by Caddy) that's wired but not yet deployed.

Architecture

   Cameras (RTSP)                   Phone / browser
        |                                |
        v                                v
  +------------+  MQTT events    +----------------+   +-------------+
  |  Frigate   | <-------------> |   Mosquitto    |   |     Pi      |
  |   (NVR)    |                 |    broker      |   |  (planned)  |
  +-----+------+                 +-------+--------+   |  speaker    |
        | WebRTC / MSE                   |            +------+------+
        v                                v                   ^
  +------------+                +------------------+         |
  |   Caddy    |<--HTTPS--------|  frigate-notify  |         |
  |   proxy    |                | (event consumer) |         |
  +------------+                +--------+---------+         |
        |                                |                   |
        | cam.yourdomain.com       ntfy push                 |
        | doorbell.yourdomain.com                            |
        +-------HTTPS---------------> PTT button ------------+

What's deployed vs planned

Component Status
Frigate 0.17 Deployed
Mosquitto MQTT broker Deployed
frigate-notify -> ntfy Deployed
Face recognition Configured, needs training
License plate recognition Configured
Caddy reverse proxy Whatever your existing Caddy does
Pi Zero W doorbell speaker Planned, not deployed yet

Repo layout

home-cameras/
|-- docker-compose.yml             # frigate + mosquitto + frigate-notify
|-- .env.example                   # template -- copy to .env, fill in
|-- .gitignore
|-- README.md                      # this file
|
|-- frigate_config/
|   |-- config.yml                 # production: main stream for detect
|   `-- alternatives/
|       `-- config-simple.yml      # lower-CPU fallback: sub-stream detect
|
|-- frigate-notify/
|   `-- config.yml                 # MQTT in, ntfy out, face-aware templates
|
|-- mosquitto/
|   |-- config/
|   |   `-- mosquitto.conf         # broker config (allow_anonymous false)
|   |-- data/.gitkeep
|   `-- log/.gitkeep
|
|-- caddy/
|   `-- Caddyfile                  # reverse proxy for both subdomains
|
`-- pi/                            # runs on the Pi, NOT on the Frigate host
    |-- README.md                  # Pi-specific setup
    |-- server.py                  # Flask + WebSocket PTT receiver
    |-- doorbell.service           # systemd unit
    `-- install.sh                 # one-shot installer

First-run on the Frigate host

Prerequisites:

  • Docker + docker compose v2
  • DNS records for any subdomains you intend to use, pointing at your Caddy host
  • An existing Caddy instance (separate from this stack) handling TLS at the edge, OR adapt for whatever reverse proxy you use
  • Coral USB stick plugged in (or adjust detectors: for a different accel)
  • A media disk mounted on the host; update the /media/frigate path in docker-compose.yml

Steps:

git clone https://github.com/YOU/home-cameras.git
cd home-cameras

# 1) Configure secrets
cp .env.example .env
$EDITOR .env

# 2) Make mosquitto dirs writable by the container's mosquitto user (UID 1883)
sudo chown -R 1883:1883 mosquitto/

# 3) Bootstrap mosquitto BEFORE applying the production config.
#    The committed mosquitto.conf has allow_anonymous false + password_file,
#    which means we need to create the password file first OR temporarily
#    flip to allow_anonymous true to start.
#
#    Easiest: temporarily edit mosquitto/config/mosquitto.conf:
#      allow_anonymous false  ->  allow_anonymous true
#      comment out:  password_file /mosquitto/config/passwd
#    Then start:
docker compose up -d mosquitto
docker compose logs mosquitto --tail 10        # expect "running"

# 4) Create the MQTT user (use the password from your .env)
docker compose exec mosquitto mosquitto_passwd -c -b \
    /mosquitto/config/passwd frigate \
    "$(grep ^FRIGATE_MQTT_PASSWORD .env | cut -d= -f2)"

sudo chown 1883:1883 mosquitto/config/passwd
sudo chmod 0640      mosquitto/config/passwd

# 5) Restore mosquitto.conf to its committed state:
#      allow_anonymous true   ->  allow_anonymous false
#      uncomment:  password_file /mosquitto/config/passwd
git checkout mosquitto/config/mosquitto.conf
docker compose restart mosquitto

# 6) Verify auth works
sudo apt install -y mosquitto-clients
mosquitto_sub -h 127.0.0.1 -u frigate \
    -P "$(grep ^FRIGATE_MQTT_PASSWORD .env | cut -d= -f2)" \
    -t 'test/#' -v &
mosquitto_pub -h 127.0.0.1 -u frigate \
    -P "$(grep ^FRIGATE_MQTT_PASSWORD .env | cut -d= -f2)" \
    -t 'test/hello' -m 'ok'
# expect: test/hello ok
kill %1

# 7) Bring up the rest
docker compose up -d
docker compose logs -f

Healthy startup looks like:

  • Frigate: frigate.comms.mqtt INFO : MQTT connected
  • frigate-notify: Successfully connected to http://frigate:5000 then Connected to MQTT. then Subscribed to MQTT topic: frigate/events
  • mosquitto: incoming client connections from both

Caddy

On whichever host runs Caddy, copy caddy/Caddyfile (or merge the relevant site blocks into your existing one), edit IPs and domains, then:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Until the Pi is deployed, comment out the doorbell.yourdomain.com block.

Train face recognition

  1. Let Frigate run with normal foot traffic for a day. Face crops are captured automatically and appear under Face Library -> Train in the Frigate UI.
  2. For each person, label 5-10 diverse clear crops -- different angles, lighting, times of day. Diversity beats quantity; 30 near-identical frames from one event hurts recognition.
  3. Walk past the camera again. Events should now show the person's name as the sub-label, and frigate-notify's ntfy push will say their name instead of "person".

Training images live on the Frigate host at /media/frigate/clips/faces/<n>/. Not version-controlled (privacy).

Switching config profiles

This repo ships with two Frigate configs:

  • frigate_config/config.yml -- active. Main 2688x1520 stream for both detect and record. Better face recognition at distance, higher CPU.
  • frigate_config/alternatives/config-simple.yml -- lower-CPU fallback. Sub-stream 640x480 for detect, main for record only.

To switch:

cp frigate_config/config.yml frigate_config/config.yml.bak
cp frigate_config/alternatives/config-simple.yml frigate_config/config.yml
docker compose restart frigate

Adding a camera with a mic

When adding a camera with a built-in microphone (e.g. an Anpviz with mic), see the comment block at the bottom of frigate_config/config.yml for the exact edits needed to enable live audio in the Frigate UI.

Pi doorbell speaker (when you're ready)

See pi/README.md. Summary:

  1. Flash Pi OS Lite, scp pi/ to the Pi, run install.sh.
  2. Add the doorbell.yourdomain.com site block in Caddy.
  3. Open the URL on your phone.

Security notes

  • .env has RTSP credentials, MQTT password, ntfy URL. Never commit it. This repo's .gitignore blocks it; review git status before committing.
  • The Pi's Flask server binds only to 127.0.0.1. Caddy is what exposes it. Do NOT bind server.py to 0.0.0.0 -- it has no auth of its own.
  • Mosquitto's port 1883 is LAN-only. Use a VPN for any remote MQTT clients.
  • For the doorbell page, optionally add basic auth in Caddy (caddy hash-password).

Troubleshooting

Frigate can't reach cameras

docker compose exec frigate ping -c 2 <camera_ip>

RTSP path varies by camera vendor:

  • Dahua / Amcrest: /cam/realmonitor?channel=1&subtype=0
  • Hikvision / Anpviz H-series: /Streaming/Channels/101

If your password contains %, @, /, ?, #, &, or +, either URL-encode it or change the password to avoid those characters.

Mosquitto restarts in a loop

Almost always permission on mosquitto/config/passwd:

sudo chown -R 1883:1883 mosquitto/
sudo chmod 0640 mosquitto/config/passwd
docker compose restart mosquitto

Or the config file or password file simply doesn't exist yet -- see the "First-run on the Frigate host" section above for the bootstrap flow.

frigate-notify connects to MQTT but doesn't send pings

docker compose logs frigate-notify --tail 30
  • "webapi" in logs but expecting MQTT? Check webapi.enabled: false and mqtt.enabled: true in frigate-notify/config.yml.
  • MQTT auth fails? Verify FN_FRIGATE__MQTT__PASSWORD (note DOUBLE underscores) matches what you set with mosquitto_passwd.
  • Confirm what reached the container: docker inspect frigate-notify --format '{{range .Config.Env}}{{println .}}{{end}}' | grep FN_

Always see "person" instead of trained name

  • Increase alerts.general.recheck_delay in frigate-notify/config.yml from 10 to 15 or 20 seconds.
  • Check the Frigate UI event timeline -- if the event itself doesn't show a sub_label, the face crop was too small / too blurry / too obscured for recognition.

Hardware reference

Current:

  • NVR host: x86_64 + Docker, USB Coral
  • Cameras: Amcrest (Dahua RTSP)
  • Notifier: self-hosted ntfy

Planned:

  • Anpviz 4K camera with built-in mic (front door audio)
  • Back door + squirrel feeder cameras
  • Pi Zero W + USB speaker at the door
S
Description
Mirror of outis1one/frigate_w_audio from GitHub
Readme
116 KiB
Languages
Markdown 100%