In the great tradition of the Trojan Room coffee pot
I like to watch machines doing their work in another room using a webcam.
In particular, I watch my 3d printer using my connected OctoPrint setup.
It gets the webcam stream from a mjpeg-streamer
service.
Most of the time nobody is watching, but the service is still running and powering the webcam unnecessarily.
Here I show how this problem can be solved using systemd socket activation. This is a feature, where systemd, the init system and daemon running on most contemporary Linux distributions, opens a socket itself and only starts a connecting system service when remote connection is established.
The service program needs to specifically designed to be able to accept this connection from systemd.
But mjpeg-streamer
is not.
This is why we need an additional helper program called systemd-socket-proxyd
.
As the name suggests, this helper proxies the data on the systemd provided socket to a different socket.
In total, we need these three unit files, which can be put in the user systemd directory ~/.config/systemd/user/
:
mjpeg-streamer.service
1
[Unit]
StopWhenUnneeded=true
[Service]
Type=exec
ExecStart=/home/pi/start_mjpg_streamer.sh
ExecStartPost=sleep 1
mjpeg-streamer-proxy.service
[Unit]
Requires=mjpeg-streamer.service
After=mjpeg-streamer.service
Requires=mjpeg-streamer-proxy.socket
After=mjpeg-streamer-proxy.socket
[Service]
Type=exec
ExecStart=/usr/lib/systemd/systemd-socket-proxyd --exit-idle-time=300 127.0.0.1:8085
mjpeg-streamer-proxy.socket
[Socket]
ListenStream=8080
[Install]
WantedBy=sockets.target
After the unit files are created and loaded using systemctl --user daemon-reload
, we only need to explicitly activate the socket with systemctl --user enable --now mjpeg-streamer-proxy.socket
.
Now when somebody connects, the two service units will start and stream the webcam content.
If nobody listens for five consecutive minutes (see --exit-idle-time=300
above), the service units shut themselves down and power down the webcam.
-
The sleep helps to avoid race conditions. This way the dependent
mjpeg-streamer-proxy.service
waits for themjpeg-streamer.service
to fully start and listen on its own socket. ↩