Mini-project: “On Air” During Zoom Calls

My Setup

I’m on MacOS, and I have a Phillips Hue home bridge. There is a Hue bulb assigned the name “OnAir”.

Detecting if Video is Turned On/Off

Rather than hook into APIs or dig too deeply, it seemed that a simple (or at least, lazy) way to know if a video camera is being used on MacOS is to look at the system log. Whenever a camera turns on, there is a log entry for kCameraStreamStart; and then when a camera stops, there’s an entry kCameraStreamStop.

% log show — last 2m — predicate ‘(sender == “VDCAssistant”)’ | grep kCameraStream2021–10–07 10:40:54.892531–0400 0xe7dcf2 Default 0x0 48943 0 VDCAssistant: [] [guid:0x1130000046d0892] Post event kCameraStreamStart2021–10–07 10:40:54.892540–0400 0xe7dcf2 Default 0x0 48943 0 VDCAssistant: [] [guid:0x1130000046d0892] Init -> Streaming on event kCameraStreamStart2021–10–07 10:40:57.851867–0400 0xe7dcf2 Default 0x1f8015d 48943 0 VDCAssistant: [] [guid:0x1130000046d0892] Post event kCameraStreamStop2021–10–07 10:40:57.851874–0400 0xe7dcf2 Default 0x1f8015d 48943 0 VDCAssistant: [] [guid:0x1130000046d0892] Streaming -> Init on event kCameraStreamStop

Controlling Lights From a Script

phue is a nice Python package for controlling your Hue lights.

 % pip install phue
% python>>> from phue import Bridge
>>> b = Bridge(‘’)
>>> b.connect()
# Turn on
b.set_light('OnAir', 'on', True)
# Turn off
b.set_light('OnAir', 'on', False)

Putting it Together

Originally, I just thought I’d fire up a Python script that would poll the MacOS log file every few seconds. However, when process forked from Python checks the log, it was coming up empty (as opposed to when the command to check logs was being invoked from the terminal). I’m still not sure why — I searched for a while, but I’m sure there’s some MacOS arcane knowledge about process trees having different permissions — but I decided to stop beating my head against this problem, and instead have a shell script that does the polling and invokes Python code.

#/bin/zshwhile true
log show --last 5m --predicate '(sender == "VDCAssistant")' | grep kCameraStream > camera.log
sleep 5
import subprocess
from phue import Bridge
import time
# Find your IP from your Hue app
# Light is named using the Hue app ahead of time
# Log file dumped from the shell script
LOG = "./camera.log"
# isCameraOn returns True if we think the camera is currently
# on, False if not. We're trying to find if the last line was
# kCameraStreamStart (True) or kCameraStreamStop (False); no match
# is False.
def isCameraOn():
camera_is_on = False
with open(LOG, "r") as a_file:
for line in a_file:
if 'kCameraStreamStart' in line:
camera_is_on = True
elif 'kCameraStreamStop' in line:
camera_is_on = False
return camera_is_on
def setLight(bridge, is_on):
bridge.set_light(LIGHT_NAME, 'on', is_on)
# Note that the first time you run this, you'll
# need to first press the button on the hue bridge
# before running this application
b = Bridge(BRIDGE_IP)
camera_on = isCameraOn()
setLight(b, camera_on)



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Chuck Groom

Chuck Groom


Consulting CTO open to projects. I’m a serial entrepreneur, software engineer, and leader at early- and mid-stage companies.