- Python 82%
- Shell 10.7%
- Makefile 7.3%
|
All checks were successful
Build and publish Debian package / build-and-publish (push) Successful in 40s
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> |
||
|---|---|---|
| .forgejo/workflows | ||
| debian | ||
| .gitignore | ||
| diy-babycam-audio-watch.service | ||
| diy-babycam-audio-watch.sh | ||
| diy-babycam-devices | ||
| diy-babycam-web.py | ||
| diy-babycam-web.service | ||
| diy-babycam.default | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
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 room0.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.