Can I trigger a HomeKit scene when my laptop's camera is turned on or off?
It doesn't seem possible to do this with HomeKit, but it is possible to make a script that communicates with IFTTT, and IFTTT will communicate with Hue directly. If you have a Hubitat hub or Home assistant that will also work as a webhook-in-the-middle.
I got through the first part easily: getting a push when camera is opened or closed. To detect camera on:
while true; do log stream | grep -o -m 1 "Post event kCameraStreamStop" > /dev/null && echo STOPPED; done
And camera off:
while true; do log stream | grep -o -m 1 "Post event kCameraStreamStart" > /dev/null && echo STARTED; done
These can be easily converted into a silent, single script that launches at startup. To communicate with the bulbs, we will replace "echo STARTED/STOPPED" with curl to an IFTTT webhook. So you need to make an IFTTT account (If you have used up more than one of your 3 free rules, create another account unless you're paying for premium already), and link up Hue with a webhook. Curl will call this webhook and set your hue bulb to whatever color, Kelvin, and brightness you want or turn it off. If you need more specific guidance then I can help you.
With the Shortcuts app and its shortcuts
command line utility, it's now possible to trigger specific shortcuts that control your HomeKit scenes and accessories.
Overall steps
- Identify 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 events for your triggers
As of MacOS 12.1 Monterey, the Post event kCameraStreamStart
and kCameraStreamStop
events referenced in the answer by anonymous are no longer logged, but there are new equivalents. It's likely that the event logs may change over time, so first check that these are still correct.
In Terminal, run this to filter the logs to the expected messages as of Monterey:
log stream | /usr/bin/grep -E 'UVCAssistant:.*(stop|start) stream'
While that's running, open the Photo Booth app. You'll hopefully see lines like these output from the filtered log stream when the camera starts and stops (when you quit the app).
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 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 place:
log stream | /usr/bin/grep -iE 'UVCAssistant|camera|stream|tccd'
Ensure the events you choose are emitted for any camera use (e.g. Zoom, Meet), not just PhotoBooth.
You'll need to come up with a regular expression for grep
that matches only when your camera is toggled on or off. 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 via the Terminal command line:
shortcuts run 'Turn on lamp'
shortcuts run 'Turn off lamp'
Trigger shortcuts on camera state
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 'Desk lamp on' &
else
echo "Lamp off"
shortcuts run 'Desk lamp off' &
fi
done
Replace my shortcut names Desk lamp on
and Desk lamp off
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
grep
regular expression with one that matches both your camera on and camera off event log messages, - replace the
sed
substitution regular expression with one that matches the equivalent word that indicates the camera state, and - if that word is not
start
when the camera turns on, update theif
conditional that matches thestart
word.
Run the script
Run the script, and test it out. If you named it camera-lamp.sh
, run
bash camera-lamp.sh
While the script is running, your HomeKit shortcuts should trigger whenever your camera turns on or off.
Optional steps:
-
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/bin
or elsewhere in your$PATH
, so you can just runcamera-lamp
as 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 answer. Importantly though, this cannot run as a launchctl daemon, as these daemons cannot run shortcuts due to
Error: Couldn’t communicate with a helper application
. If you find a good approach, feel free to comment.