bubblegum and duct tape
  • Python 82%
  • Shell 10.7%
  • Makefile 7.3%
Find a file
Vincent Batts 450d4b159d
All checks were successful
Build and publish Debian package / build-and-publish (push) Successful in 40s
web: add alerts on/off switch
A button on the page turns the audio alerts on and off. The state is
saved in the per-user alert.conf; while off, the audio watcher idles
instead of sampling the microphone.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 16:53:01 -04:00
.forgejo/workflows Audio-only stream, Debian packaging, Forgejo publish workflow 2026-10-16 15:06:41 -04:00
debian web: add alerts on/off switch 2026-10-22 16:53:01 -04:00
.gitignore web: show who is watching 2026-10-21 16:10:21 -04:00
diy-babycam-audio-watch.service more for the audio-watcher... 2026-05-01 23:31:34 -04:00
diy-babycam-audio-watch.sh web: add alerts on/off switch 2026-10-22 16:53:01 -04:00
diy-babycam-devices Replace VLC stream with ffmpeg web streaming, auto-detect devices 2026-10-21 15:05:51 -04:00
diy-babycam-web.py web: add alerts on/off switch 2026-10-22 16:53:01 -04:00
diy-babycam-web.service Replace VLC stream with ffmpeg web streaming, auto-detect devices 2026-10-21 15:05:51 -04:00
diy-babycam.default web: show hostname, add audio alert settings UI 2026-10-22 16:33:46 -04:00
LICENSE Initial commit 2026-05-01 13:48:47 +00:00
Makefile Replace VLC stream with ffmpeg web streaming, auto-detect devices 2026-10-21 15:05:51 -04:00
README.md web: add alerts on/off switch 2026-10-22 16:53:01 -04:00

diy-babycam

A minimal baby camera setup using a USB webcam and microphone on Linux. Two systemd user services:

  • diy-babycam-web — a web page (and stream) for your browser: listen to the microphone, watch the webcam, or both, picked with a button each. Uses ffmpeg.
  • diy-babycam-audio-watch — monitors mic volume and sends a push notification via ntfy.sh when the baby is loud

The microphone and webcam are found automatically.

Dependencies

The Debian package pulls these in. To run from a checkout instead:

# Debian/Ubuntu
sudo apt install ffmpeg python3 sox curl bc pipewire-bin pipewire-pulse

# Fedora
sudo dnf install ffmpeg-free python3 sox curl bc pipewire-utils pipewire-pulseaudio

ffmpeg serves the audio and video; pw-record (PipeWire) feeds the alert monitor.

Hardware

  • Any USB webcam that exposes a V4L2 device (e.g. /dev/video0)
  • Any USB microphone or webcam with a built-in mic visible as a PulseAudio/PipeWire source

Devices

The microphone (a PipeWire/PulseAudio source) and webcam (a V4L2 capture node) are detected each time they're needed, so a replugged device just works. USB devices are preferred. To see what was found, and which one is picked (*):

diy-babycam-devices list

If it picks the wrong one, pin it in the config below with BABYCAM_AUDIO_DEVICE / BABYCAM_VIDEO_DEVICE. Use the names list prints; the audio name is the PipeWire node name, e.g. alsa_input.usb-HK-5693-201123_HA501_01.00.00-02.analog-stereo. Ignore anything ending in .monitor — those are loopbacks of outputs, not microphones.

Configuration

All site-specific values are kept in /etc/default/diy-babycam. The package (or make install) creates it from a template only if it doesn't already exist, and never overwrites it afterwards. Only the ntfy URL is required:

sudo nano /etc/default/diy-babycam
Variable Required Description
BABYCAM_NTFY_URL no (alerts are off without it) Full ntfy.sh channel URL, e.g. https://ntfy.sh/my-channel
BABYCAM_WEB_PORT no Port of the web page and streams (default: 8081)
BABYCAM_AUDIO_DEVICE no PipeWire/PulseAudio source name; overrides auto-detection
BABYCAM_VIDEO_DEVICE no Webcam device node, e.g. /dev/video0; overrides auto-detection
BABYCAM_VIDEO_SIZE no Video size sent to the browser (default: 640x480)
BABYCAM_VIDEO_FPS no Video frame rate (default: 15)
BABYCAM_THRESHOLD no RMS amplitude trigger level, 0.0–1.0 (default: 0.015)
BABYCAM_COOLDOWN no Seconds between repeat alerts (default: 10)
BABYCAM_SAMPLE_SECONDS no Audio measurement window in seconds (default: 0.3)

The web page has an Alerts button that switches the audio alerts on and off (handy when the baby is awake and playing), and an Audio alert settings section for the threshold and ntfy URL. These are saved to ~/.config/diy-babycam/alert.conf for the user running the services, override the values above, and take effect immediately without a restart. The page has no authentication, so anyone who can reach it can change them; keep it on a trusted network.

Example /etc/default/diy-babycam:

BABYCAM_NTFY_URL="https://ntfy.sh/my-nursery-alerts"
BABYCAM_THRESHOLD="0.020"
BABYCAM_COOLDOWN="15"

Installation

Packages are published to this repo's Debian package registry on every push to main:

sudo curl https://git.batts.cloud/api/packages/vbatts/debian/repository.key -o /etc/apt/keyrings/forgejo-vbatts.asc
echo "deb [signed-by=/etc/apt/keyrings/forgejo-vbatts.asc] https://git.batts.cloud/api/packages/vbatts/debian trixie main" | sudo tee /etc/apt/sources.list.d/forgejo-vbatts.list
sudo apt update
sudo apt install diy-babycam

The package installs the scripts to /usr/bin and the user units to /usr/lib/systemd/user, and creates /etc/default/diy-babycam if it's missing. The services are not enabled automatically. Edit the config, then enable them as your normal user (they are user systemd services so they can reach PipeWire):

sudo nano /etc/default/diy-babycam
systemctl --user enable --now diy-babycam-audio-watch.service diy-babycam-web.service

To have the services start at boot even without an interactive login (headless/server use), enable lingering for your user:

sudo loginctl enable-linger $USER

If you previously used make install, run sudo make uninstall and remove /etc/systemd/user/diy-babycam-*.service first (and systemctl --user disable diy-babycam-stream, which no longer exists) so the old copies don't shadow the packaged ones.

Building from source

dpkg-buildpackage -us -uc -b   # produces ../diy-babycam_*_all.deb

sudo make install (to /usr/local) and make enable / make disable still work if you'd rather not use a package.

Watching

Open the page in any browser:

http://<hostname>:8081/

Press Audio to listen, Video to watch, or both. Only what's pressed is streamed, and the camera is only opened while someone is watching. A Watching now table below shows everyone currently connected — browser, address, which streams, how long, and how much data (one row per browser, merging its audio and video). The streams are also available directly, e.g. to open in VLC:

URL Content
/audio.mp3 microphone, MP3 (mono, 64 kbps)
/video.mjpg webcam, motion JPEG (all viewers share one camera capture)
/api/status JSON list of current viewers, as shown on the page
vlc http://babycam.local:8081/audio.mp3

There is no authentication — it is meant for a trusted network or a VPN such as Tailscale. Don't expose the port to the internet.

Viewing logs

Because these are user services, pass --user to journalctl:

journalctl --user -u diy-babycam-web -f
journalctl --user -u diy-babycam-audio-watch -f

Tuning the alert threshold

The BABYCAM_THRESHOLD value is an RMS amplitude from 0.0 to 1.0. Typical values:

  • 0.010 — very sensitive (picks up light sounds)
  • 0.015 — default, suitable for a quiet room
  • 0.030 — less sensitive, requires louder crying

To observe live amplitude values, run the script directly in a terminal and watch the output.

Why brief sounds may not trigger alerts

RMS amplitude averages energy over the measurement window (BABYCAM_SAMPLE_SECONDS). A snap or short cry lasting 50–100 ms gets diluted by the surrounding silence in a 1-second window, cutting the measured value by 3–4×. The default 0.3 s window is short enough to catch transients while still being stable for sustained sounds. If you are still missing brief sounds, lower BABYCAM_SAMPLE_SECONDS to 0.1 or 0.2.

A useful way to calibrate is to measure a few representative sounds manually:

# Single 0.3-second sample
pw-record --target "$(diy-babycam-devices audio)" --rate 48000 --channels 2 - 2>/dev/null | \
  sox -t raw -r 48000 -e signed -b 16 -c 2 - -n trim 0 0.3 stat 2>&1 | \
  grep "RMS amplitude"

Set BABYCAM_THRESHOLD to a value between your quiet-room baseline and the sound you want to detect.