I thought it would be interesting, and incredibly useful, to build a device that displays a visual cue when my laptops webcam is turned on. I work from home and I’m in a large amount of video meetings either on Zoom or Google Meet. This handy device helps others in the household know when I’m on a video call without needing to see the screen.

GitHub Repository containing full code

I based my work largely on another great tutorial I found here on medium:

https://edransit.medium.com/an-on-air-sign-with-iot-5bf2f2bc7dc9

The principle is the same, but things are a bit updated and expanded. I needed this to work on both my MacBook and my Linux laptop.

Hardware:

  1. ESP32 microcontroller
  2. Neopixel LED strip
  3. Wooden box
  4. Translucent Plexiglass (3mm)
  5. Micro USB cord
  6. Mosquitto Broker Server

Mosquitto Server:

The original tutorial utilizes an Arduino to run the broker. However, Arduinos are currently like gold because of the chip shortage and are both hard and expensive to find. Since I already have a server at home running TrueNAS, I spun up a broker server there from the community repository.

Checking the camera (Linux):

I’m sure there may be a more efficient way to write this, but I created a quick bash script that checks for a 1 or 0 on the uncvideo output under lsmod.

camera_on=$(lsmod | awk '{print $1,$3}' | grep uvcvideo | awk '{if ($2 == 1) print "true"; else print "false";}')

Once the camera turns on, I publish a message to the broker with the JSON displaying 1 for onair.

mosquitto_pub --topic sensor/camera/laptop -h 192.168.86.245 --message "{\"onair\": 1}"

I setup the script (full code below) to run in a cron job on reboot, continuously checking for the status of the camera.

#!/usr/bin/env bash
echo 'Running Script'
camera_on=false

while :
do

  until [ $camera_on = true ]
  do
    camera_on=$(lsmod | awk '{print $1,$3}' | grep uvcvideo | awk '{if ($2 == 1) print "true"; else print "false";}')
    sleep 2
  done

  mosquitto_pub --topic sensor/camera/laptop -h 192.168.86.245 --message "{\"onair\": 1}"

  until [ $camera_on = false ]
  do
    camera_on=$(lsmod | awk '{print $1,$3}' | grep uvcvideo | awk '{if ($2 == 1) print "true"; else print "false";}')
    sleep 2
  done

  mosquitto_pub --topic sensor/camera/laptop -h 192.168.86.245 --message "{\"onair\": 0}"

done

Checking the camera (MacOS):

The original tutorial utilizes a slightly different check in the log stream. In my version of MacOS, the kCameraStreamStart event simply wasn’t in the logs – so I set out to find what I could utilize.

For my OS – I found the proper log message being displayed for on and off under appleh13camerad. I’m not sure how future-proof this may be, but it works for now.

log stream | grep "ISP_PowerOnCamera: powered on camera"

log stream | grep "PowerOffCamera : ISP_PowerOffCamera"

With that knowledge I edited to the final script below and setup a ‘Run Shell Script’ task in Automator to run at login.

#!/bin/bash
log stream | awk '
                    /ISP_PowerOnCamera: powered on camera/  { system("/opt/homebrew/bin/mosquitto_pub --topic sensor/camera/laptop -h 192.168.86.245 --message \"{ \\\"onair\\\": 1 }\"") }
                    /PowerOffCamera : ISP_PowerOffCamera/   { system("/opt/homebrew/bin/mosquitto_pub --topic sensor/camera/laptop -h 192.168.86.245 --message \"{ \\\"onair\\\": 0 }\"") }'

Arduino Source Code

The source code has been modified slightly from the original. The loop will continually check for WIFI and Moquitto connections. If WIFI is lost/connecting then the box will glow Yellow, and if the Mosquitto Broker connection is lost/connecting then the box will glow Blue. The box glows red when the camera turns on.

Project Box Build

The build was straight forward. I found a hollow wooden cube at a craft store and cut it open, drilling out a window and filing until it was smooth. Then I found some 3mm Acrylic/Plexiglass from Amazon that was translucent and cut to shape.