Looking great on camera while working from home requires good lighting.
Working at Doximity, a company that has been remote-first since long before the pandemic, necessitates a fair number of video calls as we collaborate and work on challenging problems together. Though meetings constitute only a fraction of my time, I appreciate having some good lighting during those calls. I also appreciate having a little less light at other times to avoid irritating my eyes. I have a simple desk lamp that does the job, but it’s slightly tedious to turn it on and off around my meetings. Time for some automation!
I picked up a pack of Meross Smart Plugs that are HomeKit-compatible, so I could control them with my iPhone or Mac, added one using the Home app on my phone, and plugged in the lamp. After I could toggle the lamp on and off using the Home app, I set out to build some automation to turn on and off the lamp whenever my Macbook camera turns on or off.
This guide walks through the process of setting up HomeKit automation on MacOS whenever any of your Mac’s cameras turn on or off.
- Identify camera off events for your triggers.
- Use the Shortcuts app to create shortcuts that trigger your desired HomeKit actions.
- Create a script that triggers shortcuts when the camera turns on/off.
- Run the script manually or automatically.
Identify camera events for your triggers
log stream command provides a stream of logged system events, which we can
filter and monitor for camera on/off events.
In Terminal, run this to filter the logs to the expected messages on MacOS Monterey 12.1:
log stream | /usr/bin/grep -E 'UVCAssistant:.*(stop|start) stream'
While that’s running, open the Photo Booth app or any video conferencing software. You’ll hopefully see lines like these output from the filtered log stream when the camera starts and stops (which you can trigger by quitting and restarting Photo Booth or toggling the camera).
2022-01-04 14:56:58.628006-0500 0xb35b3 Default 0x18025b 266 0 UVCAssistant: (UVCFamily) [com.apple.UVCFamily:device] UVCUSBDeviceStreamingInterface: 0x1000005a6 [0x7fcd7bd08260] [start stream] format : UVCDeviceStreamFormat:[1280 * 720 (YUV420_420v)] [0x7fcd7bd08e90] [subtype 4] frameInterval : 333333 2022-01-04 14:57:31.179027-0500 0xb2227 Default 0x1803a4 266 0 UVCAssistant: (UVCFamily) [com.apple.UVCFamily:device] UVCUSBDeviceStreamingInterface: 0x1000005a6 [0x7fcd7bd08260] [stop stream] format : UVCDeviceStreamFormat:[1280 * 720 (YUV420_420v)] [0x7fcd7bd08e90] [subtype 4] frameInterval : 333333
If you get output, you’re done with this step and can use the regular expression matchers I provide in the next steps.
If you get no output, you’ll need to broaden the filter to search for event logs that appear when the camera starts and stops. This might be a good starting filter for your search:
log stream | /usr/bin/grep -iE 'UVCAssistant|camera|stream|tccd'
For example, according to this AskDifferent question, an earlier version of MacOS instead emitted event log messages containing
Post event kCameraStreamStart and
Post event kCameraStreamStop.
Ensure the events you choose are emitted for any camera usage (e.g. in Zoom and Meet) and not just Photo Booth.
You’ll need to come up with a regular expression for
grep that matches only when your camera is toggled on or off. Modify your
grep regular expression until you get (ideally) a single line of output when the camera turns on or off. Beware of anything too generic, like
stream, which may trigger your automation when other stream events happen like activating a Bluetooth microphone stream when the microphone turns on.
If you have multiple cameras, you may also want to test switching between cameras.
Create Shortcuts to trigger HomeKit actions
First, confirm that you’re able to use the Home app on your Mac to trigger changes to whatever accessories or scenes you’re interested in.
In the Shortcuts app, create a new shortcut (
+ button). For toggling a light, you’ll need a separate shortcut for each state (e.g. on/off). Give the shortcut a name such as Turn on lamp.
For each shortcut, select the Home app and add its Control <home name> action to your shortcut (drag or double-click). Select the specific scene or accessory you want to control, and select a state for you to set it to when the shortcut runs.
When complete, you should see your shortcuts in your shortcuts list and be able to run them and trigger your expected behavior.
Last, confirm that you can trigger these successfully on the command line via Terminal:
shortcuts run 'Turn on lamp' shortcuts run 'Turn off lamp'
Trigger shortcuts on camera state events
Create a script file (e.g.
camera-lamp.sh) that, while running, will toggle your light based on whether the camera is running. A starter example:
#!/bin/bash exec log stream | /usr/bin/grep -E --line-buffered 'UVCAssistant:.*(stop|start) stream' | # filter log events tee /dev/stderr | # output matching events for debugging /usr/bin/sed -Eu 's/.*(start|stop).*/\1/' | # reduce the log message down to a single word identifying the event/state while read -r event; do # store that word in the $event variable echo "Camera $event" if [ "$event" = "start" ]; then echo "Lamp on" shortcuts run 'Turn on lamp' & else echo "Lamp off" shortcuts run 'Turn off lamp' & fi done
Replace my shortcut names
Turn on lamp and
Turn off lamp with your own, if different. Feel free to alter messages like
"Lamp on" to fit your scenario.
If you needed to choose a different filter in step 1:
- replace the
grepregular expression with one that matches both your camera on and camera off event log messages,
- replace the
sedsubstitution regular expression with one that matches the equivalent word that indicates the camera state, and
- if that word is not
startwhen the camera turns on, update the
ifconditional that matches the
This will trigger when any connected camera changes its state, but you can make the grep filter more specific to limit it to a specific camera.
Run the script
Run the script, and test it out. If you named it
While the script is running, your HomeKit shortcuts should trigger whenever your camera turns on or off.
Once the script is stable, run it in the background, and close the terminal.
bash camera-lamp.sh &
- Drop the extension, make the file executable, and relocate it to
/usr/local/binor elsewhere in your
$PATH, so you can just run
camera-lampas a command.
- Find a way to run the script in the background as a daemon on login. How to accomplish this is beyond the scope of this guide. Importantly though, this cannot run as a
launchctldaemon, as these daemons cannot run shortcuts due to
Error: Couldn’t communicate with a helper application.
With that running… Magic! My desk lamp automatically turns on whenever I join a meeting or a Roundsy social mixer (a free app Doximity built for any kind of virtual event attendees to chat with other random attendees in small groups).
Next up: Light up a sign outside my office to signal my kids not to walk into my meetings! 😃