Last year I talked about my faithful Logitech C930e webcam, and at the end of the article I mentioned that I have to manually disable the autofocus, and that sadly that setting is gone at every reboot, and even every time I unplug the webcam; my question then was, can I automate this somehow?
And the answer is yes, of course you can. The first thing I’ve done is to change the approach, and instead of manually typing this command:
$ v4l2-ctl --device=/dev/video4 --set-ctrl focus_automatic_continuous=0
… I took a different approach, using the v4l2ctrl command instead:
$ sudo dnf install v4l2ucp
$ v4l2ctrl -d /dev/video4 -s camera-settings.txt
This saves all settings of the camera in a single text file, and the cool thing is that you can use the -l argument to load them back, and it gives you control over many different parameters of the webcam in one place and you can load them in one shot:
$ v4l2ctrl -d /dev/video4 -l camera-settings.txt
Loading on Startup
Now I need to wrap this command as a systemd service that is executed every time my my machine boots up, saved in a file named fix-webcam.service:
[Unit]
Description=Fix Logitech webcam autofocus
[Service]
Type=oneshot
# Wait 10 seconds for systemd-logind to grant video device permissions
ExecStartPre=/usr/bin/sleep 10
ExecStart=/usr/bin/v4l2ctrl -d /dev/video4 -l /home/user/camera-settings.txt
[Install]
WantedBy=default.target
I installed this service it in my local systemd user folder:
$ mkdir -p ~/.config/systemd/user
$ mv fix-webcam.service ~/.config/systemd/user/fix-webcam.service
$ systemctl --user daemon-reload
$ systemctl --user enable fix-webcam.service
Et voilà! Now this service is executed every time I start my machine. But what happens if I unplug the webcam? Then the settings would be gone again. Worry not! Turns out, there’s a way to trigger the systemd service above whenever a USB device is plugged.
Loading on Unplug & Replug
First plug your webcam, and find the ID of your USB device:
$ lsusb | grep 046d
Bus 003 Device 032: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver
Bus 003 Device 034: ID 046d:0843 Logitech, Inc. Webcam C930e
The 046d vendor ID corresponds to Logitech, and in the case of my C930e webcam, 0843 is the product ID. I also have a wireless Logitech MX Master 3S mouse, so the dongle appears there as well.
Then, as a superuser, I created a new file called /etc/udev/rules.d/99-dock-fixes.rules with the following contents:
# Trigger the webcam script when the Logitech camera is plugged in
ACTION=="bind", SUBSYSTEM=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="0843", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}+="fix-webcam.service"
Then reload the changes, and trigger the action to test it:
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --action=bind
watch "v4l2-ctl --list-ctrls --device /dev/video4 | grep focus_automatic"Et voilà (bis)! Now every time, a few seconds after I re-plug your webcam, my preferred settings apply.
bind action instead of add, for a reason; you should know that when you plug in a USB device, ACTION=="add" fires the exact millisecond the metal connects, before Linux has actually loaded the webcam or audio drivers. Sometimes, udev refuses to trigger the systemd service because the underlying device nodes don’t fully exist yet. Instead, bind tells udev to wait until the Linux drivers have actually attached to the hardware before triggering the service.