During the COVID pandemic, I invested in improving my working-from-home setup with a better webcam and an Elgato Key Light. I usually control the Key Light using my Stream Deck (which was another lockdown purchase and project).
Over the last few weeks, I've been working from home a bit more than usual, which led me to think:
Why haven't I setup my Elgato Key Light to automatically turn on when my webcam is in use?
This feels like another home automation project and a job for Home Assistant.
I want to use Home Assistant to turn the Key Light on and off based on the state of a sensor – that much is easy!
The challenge will be getting the state of my desktop's webcam into Home Assistant as a sensor.
Monitoring Webcam Usage
After some research, it looks like the most straightforward way to approach this will be to use inotify to detect changes to video devices.
Video devices can be shown by listing /dev/video*
:
$ ls -l /dev/video*
crw-rw----+ 1 root video 81, 0 Nov 30 15:47 /dev/video0
crw-rw----+ 1 root video 81, 1 Nov 30 15:47 /dev/video1
crw-rw----+ 1 root video 81, 2 Nov 30 15:47 /dev/video2
crw-rw----+ 1 root video 81, 3 Nov 30 15:47 /dev/video3
We can infer that the camera is in use when we detect a "File opened" event in inotify.
Similarly, we can infer that the camera has stopped being used when a "Writtable file was closed" event has been received.
Basic Prototype
The first task was to put together a basic prototype script that will print out intoify changes to /dev/video*
When a camera is started, there are a lot of rapid "file opened" changes detected by inotify within a very short period:
2023-12-01 20:09:53,651 - __main__ - INFO - Watching for changes in /dev directory...
2023-12-01 20:10:12,489 - __main__ - INFO - Webcam is being used!
2023-12-01 20:10:12,489 - __main__ - INFO - Webcam is being used!
...
2023-12-01 20:10:12,835 - __main__ - INFO - Webcam is being used!
2023-12-01 20:10:12,835 - __main__ - INFO - Webcam is being used!
If I stop using the webcam, inotify captures a single "Writable file was closed" event:
2023-12-01 20:23:02,027 - __main__ - INFO - Webcam stopped being used!
The prototype works, and it proves the concept!
A more refined implementation will need to "debounce" the inotify events to avoid the excessive number of events that are raised when the webcam is initialised.
The Complete Solution
The final solution that I have arrived at is a small utility called Webcam Home Assistant Sensor that is written in Python, and uses MQTT to update an MQTT-based sensor in Home Assistant.
Webcam Home Assistant Sensor will need the connection details of your MQTT broker which are configured in a .env
file. For example:
MQTT_HOST=homeassistant
MQTT_USERNAME=mqttadmin
MQTT_PASSWORD=password
Depending on the state of the webcam, the utility will either push payload of either:
{"state": "on"}
Or:
{"state": "off"}
Home Assistant needs to be configured to have a new MQTT-based sensor that listens on the correct topic. This can be configured by adding the following to the configuration.yaml
:
mqtt:
sensor:
- name: "Desktop Webcam"
state_topic: "homeassistant/binary_sensor/webcam_ha_sensor"
value_template: "{{ value_json.state }}"
Automations
I deliberately wanted this utility to be lightweight, as Home Assistant can handle the automation part of this and the interaction between the webcam and the Elgato Key Light.
I have added two basic automations.
One to turn the Key Light on when the webcam turns on:
And another to turn the Key Light off when the webcam turns off:
Conclusion
The end result is that Home Assistant will automatically toggle the Key Light on and off whenever my webcam is in use – this works regardless of whether I join a meeting via Google Meets, Microsoft Teams, or any other service!
There are a few minor limitations to this. For instance, I have assumed someone will only have one camera plugged in, and the utility makes no attempt to distinguish activity from different /dev/video*
devices. This could, of course, be easily improved. However, the current implementation is perfect for my use case.