As any masochistic logical person would do when we learned that our daughter would join us,
i thought that we would have the need to spy on monitor her while she rests on the other room.
So off i was, buying a raspberry pi 0 with a NoIR camera and a usb microphone! Like you, dear reader,
i did my preliminary search and found a multitude of reported setups (most running rasbian) so i thought
that this should be a project that would take max .. 3-4 days. Ha! Murphy was already laughing at me, from
dimensions beyond. I wanted to go off the beaten path a bit by using Alpine linux (because it still is Linux)
and putting the whole thing in a stuffed animal. After all my daughter will have all her future life to experience
tech dystopia by herself, no need to accelerate things by having her look at a camera looking back at her.
Here is a parts list i got with links if you decide to go down that road:
Parts
- rpi zero amazon
- usb mci amazon
- micro usb to usb adapter amazon
- pi NoIR camera 2 adafruit
- pi zero camera cable adafruit
- police dawg amazon
software
Installing alpine on your SD card
partitioning your microSD
You will need an msdos partition label (did not try GPT) and 2 primary partitions, one vfat for /boot and the other ext4.
alpine linux
Download the the current as of feb 2025 3.21.2 armhf tar image
mount your microSD in /mnt/flash, and untar it tar -xzpvf alpine-rpi-3.21.2-armhf.tar.gz -C /mnt/flash
Now you can edit the pi boot relevant file /boot/usercfg.txt
cat /boot/usercfg.txt
#camera
dtoverlay=imx219
camera_auto_detect=1
#audio for the microphone
dtparam=audio=on
#usb microphone and usb gadgets
dtoverlay=dwc_otg
#uncomment if you want to enable the serial console
#enable_uart=1
#you can also control how much memory you will give to the gpu via
#gpu_mem=32
If you want to enable the serial console you also need to edit /boot/cmdline.txt and add
console=serial0,115200.
headless install over wifi
In case you want to only install via wifi without using the serial over usb as described above you can
download the headless overlay from github
place it at the root of the boot media. There you can also provide a wpa_supplicant.conf with your wifi ssid and psk,
as well as an authorized_keys file with a pubkey to ssh in as the root user.
Then you can run setup-alpine to configure the system.
setting up video and audio
apk add libcamera-tools libcamera-raspberrypi libcamera-v4l will give us the cam package to test by grabbing a screenshot or listing the cameras via cam -l
however looking around we see that there are also the libcamera-* apps that can stream video directly to either stdout
or a socket and many many more. There is a package providing these but is currently (as of Feb 2025) in testing, so to
add them we need to edit /etc/apk/repositories to something like below (if we want to follow the latest release. Otherwise we
should stick to the version we have downloaded like 3.21.2)
http://mirrors.gigenet.com/alpinelinux/latest-stable/main
http://mirrors.gigenet.com/alpinelinux/latest-stable/community
@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing
Having done that, we can apk update and apk add rpicam-utils@testing
In order to also operate the usb microphone, we need to setup either alsa or pulseaudio. To do that
we add the alsa packages apk add alsa-utils alsaconf and then we add our user to the audio group
addgroup $USER audio (and even add the root user to the same group). Then running alsamixer should
show us the soundcard and its respective number and we can configure the input levels of the mic.
We also add alsa to the runlevel by rc-service alsa start and rc-update add alsa
a note on connections
The raspberry pi zero has 2 usb ports, but only one can also transfer data, the other is solely for charging. so the microphone needs to be plugged to the port that is farther away from the ribbon cable that goes to the camera. This was the source of much confusion during testing.
tuning the camera
Using libcamera-vid or libcamera-still (or cam) we can see that the pictures that we get using the default
tuning parameters are a bit overexposed. For our case that we use the imx219 NoIR camera, we can run libcamera-vid
with the following options
libcamera-vid -t 0 --libav-format h264 --width 640 --height 480 --framerate 15 --profile baseline --tuning-file /usr/share/libcamera/ipa/rpi/vc4/imx219_noir.json
also you will notice that without specifying a mode , the image appears cropped, or extremely zoomed in. In order to fix
that we need to find a mode that is supported from –list-cameras and pass that libcamera-vid. in our case ----mode 1640:1232:10 does the trick.. Finally the –inline parameter adds a SPS/PPS (sequence/picture parameter sets) header on
every frame so that the client can properly decode the data as the stream progresses.
so we end up with
libcamera-vid -t 0 --inline --codec h264 --mode 1640:1232:10 --framerate 5 --profile baseline --tuning-file /usr/share/libcamera/ipa/rpi/vc4/imx219_noir.json -o -
things head south
At this point according to various similar projects you might see people using the libcam-vid application to either stream video directly from it to clients, or have it write to stdout and then pipe to cvlc in order to create an rtsp stream, like this one liner or this forum post. However no such thing ever worked for my case. Also, trying to cram all that functionality of listening for network connections and doing all the possible encodings inside the libcamera programs is…. (i think) very misguided. UNIX is designed around program composition.
go2rtc
go2rtc is a small golang program, that bundles a webapp, and can consume various input streams, and combine them into outuput ones. It can use RTMP, RTSP, ffmpeg, homekit, gopro, webrtc and many more as input. Then it can present these on the webapp, and also run commands that produce new strems for output. It worked wonders for me and was able to compose the two streams (video and audio) into one, and do it within the CPU constrains of the raspberry pi. Below you can find the final config
api:
listen: ":1984"
ffmpeg:
bin: "ffmpeg"
log:
format: "color"
level: "info"
output: "stdout"
time: "UNIXMS"
rtsp:
listen: ":8554"
default_query: "video&audio"
srtp:
listen: ":8443"
webrtc:
listen: ":8555/tcp"
ice_servers:
- urls: [ "stun:stun.l.google.com:19302" ]
streams:
babycam:
- "exec:libcamera-vid -t 0 --inline --codec h264 --mode 1640:1232:10 --framerate 5 --profile baseline --tuning-file /usr/share/libcamera/ipa/rpi/vc4/imx219_noir.json -o -"
- "ffmpeg:device?audio=default&channels=1&sample_rate=16000&#audio=aac"
Here are some pictures of how the pi in police dog looks like img1: eye of the monitor img2: operating on the stuffed animal img3: cable management on the dog’s back img4: babymon with laptop