Skip to content

Instantly share code, notes, and snippets.

@antonmry
Last active February 26, 2024 13:08
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save antonmry/8bf2d07db75df538c385bfa1cd6d5cf2 to your computer and use it in GitHub Desktop.
Save antonmry/8bf2d07db75df538c385bfa1cd6d5cf2 to your computer and use it in GitHub Desktop.
This is script to auto on/off a Logitech light when the webcam is on/off in Mac. It requires hidapitester
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>litra-auto-on</string>
<key>ProgramArguments</key>
<array><string>/Library/LaunchDaemons/litra-auto-on.sh</string></array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
#! /bin/bash
# Download both files and https://github.com/todbot/hidapitester to /Library/LaunchDaemons/
# Execute the following commands to launch it on login
# sudo chown root:wheel /Library/LaunchDaemons/litra-auto-on.plist
# sudo chmod o-w /Library/LaunchDaemons/litra-auto-on.plist
# sudo launchctl load -w /Library/LaunchDaemons/litra-auto-on.plist
# For test it:
# launchctl start litra-auto-on
# tail -f /var/log/system.log
# Use 046D/C900 for older models
model="046D/C901"
# Change to your own path
hidapitester="/Library/LaunchDaemons/hidapitester"
log stream --predicate 'subsystem contains "com.apple.UVCExtension" and composedMessage contains "Post PowerLog"' | while read LOGLINE
do
[[ "${LOGLINE}" == *"On;"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
[[ "${LOGLINE}" == *"Off;"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c"
done
@joeytepp
Copy link

joeytepp commented Apr 4, 2023

@dudo I used your script and found that my light was turning on and off at random times. This was on an M1 Pro on Ventura 13.3. Have you noticed this as well? I ended up copying the last few lines from the original gist and that fixed it, but the testing and installation steps were super helpful 👌

@driley-abbvie
Copy link

@joeytepp thanks for the comment, i was coming to check which files I needed to delete because the same thing was happening to me. replacing 18-22 with original sh file fixed for me as well

@aardvark82
Copy link

FWIW, my final script on M2:

#! /bin/bash

# Download both files and https://github.com/todbot/hidapitester to /Library/LaunchDaemons/
# Execute the following commands to launch it on login
# sudo chown root:wheel /Library/LaunchDaemons/litra-auto-on.plist
# sudo chmod o-w /Library/LaunchDaemons/litra-auto-on.plist
# sudo launchctl load -w /Library/LaunchDaemons/litra-auto-on.plist
# sudo chmod 0744 /Library/LaunchDaemons/litra-auto-on.sh
# sudo chown root:wheel /Library/LaunchDaemons/litra-auto-on.sh
# sudo launchctl bootstrap system /Library/LaunchDaemons/litra-auto-on.plist
# For test it:
# launchctl start litra-auto-on
# tail -f /var/log/system.log

model="046D/C900" # for a Litra Glow
# model="046D/C901" # for a Litra Beam connected over USB

hidapitester="/Library/LaunchDaemons/hidapitester"

log stream --predicate 'subsystem contains "com.apple.UVCExtension" and composedMessage contains "client" and composedMessage contains "onnect"' | while read LOGLINE; do
  [[ "$LOGLINE" == *"clientConnect"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
  [[ "$LOGLINE" == *"clientDisconnect"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c"
done

Be sure to run sudo launchctl unload /Library/LaunchDaemons/litra-auto-on.plist if you already started the daemon before assigning permissions after saving this file.

This final script worked for me as well - 13.3.1 on a Macbook Pro M1. Logitech brio 4k + LITRA Glow

@arough007
Copy link

I have everything up and running, but my Litra is turning on when connecting other devices, not only cameras.
If I connect or disconnect my AirPods Pro the light turns on for five seconds and then off again.
The output below is a mix of my camera turning on/off and my AirPods connecting/disconnecting.
The devices seem indistinguishable to me, except that the Airpods "disconnect" after 5s. They function as they should and only connect and disconnect in the logs. Not functionally.

log stream --predicate 'subsystem contains "com.apple.UVCExtension"'                                                                                                    ✔   3s  20:36:07
Filtering the log data using "subsystem CONTAINS "com.apple.UVCExtension""
Timestamp                       Thread     Type        Activity             PID    TTL
2023-06-13 20:36:24.424267+0200 0x7f9d2a   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientConnect : <private>
2023-06-13 20:36:24.424382+0200 0x7f9d2a   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] propertyStatesForProperties {(
    CMIOExtensionPropertyProviderManufacturer,
    CMIOExtensionPropertyProviderName
)}
2023-06-13 20:36:36.510297+0200 0x7f9d2a   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientDisconnect : <private>
2023-06-13 20:36:49.492843+0200 0x7fa984   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientConnect : <private>
2023-06-13 20:36:49.492891+0200 0x7fa984   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] propertyStatesForProperties {(
    CMIOExtensionPropertyProviderManufacturer,
    CMIOExtensionPropertyProviderName
)}
2023-06-13 20:36:54.545676+0200 0x7fa984   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientDisconnect : <private>
2023-06-13 20:37:20.305052+0200 0x7faff4   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientConnect : <private>
2023-06-13 20:37:20.305110+0200 0x7faff4   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] propertyStatesForProperties {(
    CMIOExtensionPropertyProviderManufacturer,
    CMIOExtensionPropertyProviderName
)}
2023-06-13 20:37:25.366577+0200 0x7faff4   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientDisconnect : <private>
2023-06-13 20:38:48.483159+0200 0x7fb544   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientConnect : <private>
2023-06-13 20:38:48.483271+0200 0x7fb544   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] propertyStatesForProperties {(
    CMIOExtensionPropertyProviderManufacturer,
    CMIOExtensionPropertyProviderName
)}
2023-06-13 20:39:03.880503+0200 0x7fb545   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientDisconnect : <private>
2023-06-13 20:39:13.260052+0200 0x7fb8c2   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientConnect : <private>
2023-06-13 20:39:13.260187+0200 0x7fb8c2   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] propertyStatesForProperties {(
    CMIOExtensionPropertyProviderManufacturer,
    CMIOExtensionPropertyProviderName
)}
2023-06-13 20:39:18.301562+0200 0x7fb8c2   Default     0x0                  297    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:provider] UVCExtensionProvider: [0x123a126e0] clientDisconnect : <private>

As I don't see a difference in the logs I don't know how to edit the code to ignore certain devices or only listen to specific devices connecting.

Something similar happens when my Mac goes into standby and the dock disconnects/goes to sleep.

Does anyone have an idea?

@joeytepp
Copy link

@arough007 I had the same issue, and I detailed how I solved it here. This is the script that worked for me on both my M1 and Intel macs:

#! /bin/bash

# https://gist.github.com/antonmry/8bf2d07db75df538c385bfa1cd6d5cf2
#
# Download both files to /Library/LaunchDaemons/
# Download https://github.com/todbot/hidapitester to /usr/local/bin/
#
# Execute the following commands to launch it on login
# sudo chown root:wheel /Library/LaunchDaemons/litra-auto-on.plist
# sudo chmod o-w /Library/LaunchDaemons/litra-auto-on.plist
# sudo launchctl load -w /Library/LaunchDaemons/litra-auto-on.plist
# sudo chmod 0744 /Library/LaunchDaemons/litra-auto-on.sh
# sudo chown root:wheel /Library/LaunchDaemons/litra-auto-on.sh
# sudo launchctl bootstrap system /Library/LaunchDaemons/litra-auto-on.plist
#
# Testing:
# launchctl start litra-auto-on
# tail -f /var/log/system.log

# model="046D/C900" # for a Litra Glow
model="046D/C900" # for a Litra Beam connected over USB

hidapitester="/Library/LaunchDaemons/hidapitester"


log stream --predicate 'subsystem contains "com.apple.UVCExtension" and composedMessage contains "Post PowerLog"' | while read LOGLINE
do
	[[ "${LOGLINE}" == *"On;"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
	[[ "${LOGLINE}" == *"Off;"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c"
done

@arough007
Copy link

@joeytepp Sadly your solution only works with my external Logitech C900 webcam, but neither with the built-in cam nor with Continuity Camera (iPhone).
As seen in my original reply, there is no "Post PowerLog" in the output so your filters won't work for me.

@joeytepp
Copy link

@arough007 😞 that's a shame. Hopefully someone else in the comments will have a working solution for you!

@JohnAllenTech
Copy link

Can anyone let me know what the name of the service is when they do sudo launchctl list please

Think my issue is the service isnt running. I can switch on and off the light with the commands just doesnt seem to be monitoring for the events

@keifgwinn
Copy link

I've got both a glow and a beam and did a little fiddling with the log stream to make it work in my case where I've got them connected via a Mac Studio Monitor

hidapitester="/usr/local/bin/hidapitester"

beam="046D/C901"
glow="046D/C900"

log stream --predicate 'subsystem contains "com.apple.UVCExtension" and composedMessage contains "VDCAssistant_Power_State"' | while read LOGLINE
do
  [[ "${LOGLINE}" == *"On;"* ]] && \
  eval "$hidapitester --vidpid $glow --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01" && \
  eval "$hidapitester --vidpid $beam --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"

  [[ "${LOGLINE}" == *"Off;"* ]] && \
  eval "$hidapitester --vidpid $glow --open --length 20 --send-output 0x11,0xff,0x04,0x1c" && \
  eval "$hidapitester --vidpid $beam --open --length 20 --send-output 0x11,0xff,0x04,0x1c"
done

@vosechu
Copy link

vosechu commented Jul 18, 2023

To expand on this comment about multiple lights from @evanr76: https://gist.github.com/antonmry/8bf2d07db75df538c385bfa1cd6d5cf2?permalink_comment_id=4441654#gistcomment-4441654

I'm sure there's a fancy way to do this, but I did it manually with these steps:

./hidapitester --list-detail

Which yielded something that looked like this:

046D/C901: Logitech - Litra Beam
  vendorId:      0x046D
  productId:     0xC901
  usagePage:     0x000C
  usage:         0x0001
  serial_number: 2312FE6071G8
  interface:     0
  path: DevSrvsID:4295031427

046D/C901: Logitech - Litra Beam
  vendorId:      0x046D
  productId:     0xC901
  usagePage:     0xFF43
  usage:         0x0202
  serial_number: 2312FE6071G8
  interface:     0
  path: DevSrvsID:4295031427

046D/C901: Logitech - Litra Beam
  vendorId:      0x046D
  productId:     0xC901
  usagePage:     0x000C
  usage:         0x0001
  serial_number: 2312FE6072D8
  interface:     0
  path: DevSrvsID:4295031379

046D/C901: Logitech - Litra Beam
  vendorId:      0x046D
  productId:     0xC901
  usagePage:     0xFF43
  usage:         0x0202
  serial_number: 2312FE6072D8
  interface:     0
  path: DevSrvsID:4295031379

From that, I copied the two unique path values and pasted them into the revised script:

log stream --predicate 'subsystem contains "com.apple.UVCExtension" and composedMessage contains "Post PowerLog"' | while read LOGLINE
do
  [[ "${LOGLINE}" == *"On;"* ]] &&
    eval "$hidapitester --open-path DevSrvsID:4295031379 --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01" &&
    eval "$hidapitester --open-path DevSrvsID:4295031427 --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
  [[ "${LOGLINE}" == *"Off;"* ]] &&
    eval "$hidapitester --open-path DevSrvsID:4295031379 --length 20 --send-output 0x11,0xff,0x04,0x1c" &&
    eval "$hidapitester --open-path DevSrvsID:4295031427 --length 20 --send-output 0x11,0xff,0x04,0x1c"
done

I don't know if this id will change, if so, I'll have to delve into how to pull out those device paths automatically. The --list-detail option isn't very parseable, so I decided to see if those ids are static first before committing time to the problem.

@jsill14
Copy link

jsill14 commented Jul 27, 2023

A few people want this to work with iPhone and continuity. Based on the camera events, the log stream below should give you a good place to start and stop the light.

log stream --predicate 'subsystem == "com.apple.CMContinuityCapture" and composedMessage contains "CMContinuityCaptureVideoStream stopStreamAndReturnError"'
log stream --predicate 'subsystem == "com.apple.CMContinuityCapture" and composedMessage contains "CMContinuityCaptureVideoStream stopStreamAndReturnError"'

@Agusum
Copy link

Agusum commented Aug 17, 2023

This script worked great for me, however, if I'm using the webcam a Google Meet call from the PWA to a Chrome window, the light turns off. This doesn't happen if I switch to a different application though.

Does anyone know how to fix this?

@dudo
Copy link

dudo commented Aug 24, 2023

I found this to work well for both intel and arm based macs. It's been super reliable for months now, using slack, zoom, or google meet.

log stream --predicate 'eventMessage contains "Cameras changed to"' | while read LOGLINE
do
  # ON
  [[ "${LOGLINE}" == *"changed to [ControlCenterApp.VideoCamera"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
  # OFF
  [[ "${LOGLINE}" == *"changed to []"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c"
done

@er-minio
Copy link

Upgraded to Sonoma, the light comes one when you start a video stream, but doesn't turn off when you close it.
I tried using dudo's code too (mine is a bit 'hacky', to be gentle) but same error.

@ijcarson1
Copy link

ijcarson1 commented Sep 26, 2023

Just upgraded to Sonoma, i'm having a similar issue - Bootstrap failed: 5: Input/output error

I'm using a very slightly modified version of wkoutre's script

This is how mine looks

log stream --predicate 'subsystem contains "com.apple.UVCExtension" and composedMessage contains "Post PowerLog"' | while read LOGLINE
do
	[[ "${LOGLINE}" == *"On;"* ]] && 
    eval "$hidapitester --open-path DevSrvsID:4294974364 --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01" &&
    eval "$hidapitester --open-path DevSrvsID:4294973605 --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
	[[ "${LOGLINE}" == *"Off;"* ]] &&
    eval "$hidapitester --open-path DevSrvsID:4294974364 --length 20 --send-output 0x11,0xff,0x04,0x1c" &&
    eval "$hidapitester --open-path DevSrvsID:4294973605 --length 20 --send-output 0x11,0xff,0x04,0x1c"
done

Running the commands in order, sudo launchctl bootstrap system /Library/LaunchDaemons/litra-auto-on.plist gives me the boostrap error, but if I unload first, then bootstrap it doesn't error - but lights no longer react

@er-minio
Copy link

I disabled the script entirely on my machine, but the light still comes on when I boot the computer.

@ijcarson1
Copy link

Just managed to get mine running - had to start and stop the service a few times and then it just started working. Weird.

@spexxyy
Copy link

spexxyy commented Sep 27, 2023

For Macbook air m2 @sonoma this variation is working for me

log stream --predicate 'eventMessage contains "Cameras changed to"' | while read LOGLINE
do
  # OFF
  [[ "${LOGLINE}" == *"appEffects: []"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c"
  # ON
  [[ "${LOGLINE}" == *"appEffects: [ControlCenterAp"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
done

@ekrapfl
Copy link

ekrapfl commented Oct 12, 2023

I am on an M1 on Sonoma, and I am not getting anything to work. Like someone mentioned before, it will automatically turn on both on login and when starting the camera, but it seems to do that even with the script disabled. It never turns off. My logs look like this for on, then off:
image

So I have my script looking like so:

log stream --predicate 'eventMessage contains "Cameras changed to"' | while read LOGLINE
do
  # ON
  [[ "${LOGLINE}" == *"changed to [ControlCenterApp.VideoCamera"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01"
  # OFF
  [[ "${LOGLINE}" == *"changed to [:]"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c"
done

I even confirmed that the eval command definitely works, but for some reason, I am having trouble detecting that log for off. Do I need an escape character for the : perhaps?

Anyone else have any luck?

@er-minio
Copy link

The script I am using (ijcarson1's one above) started working correctly after rebooting the computer a couple of times. No idea why.

@ekrapfl
Copy link

ekrapfl commented Oct 12, 2023

I think I finally got it for my setup (MacBook Pro M1 Ultra)
I used this script:

log stream --predicate 'eventMessage contains[c] "cameras changed to "' | while read LOGLINE;

do
  # ON
  [[ "${LOGLINE}" == *"changed to [ControlCenterApp.VideoCamera"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c,0x01";
  # OFF
  [[ "${LOGLINE}" == *"changed to [:]"* ]] && eval "$hidapitester --vidpid $model --open --length 20 --send-output 0x11,0xff,0x04,0x1c";
done

Note: I added [c] for case insensitivity (that is what was breaking between off and on), and I made sure to run these to reset:

launchctl stop litra-auto-on
sudo launchctl load -w /Library/LaunchDaemons/litra-auto-on.plist;
sudo launchctl load -w /Library/LaunchDaemons/litra-auto-on.plist;
# the next line errors, so not positive if it is necessary or not
sudo launchctl bootstrap system /Library/LaunchDaemons/litra-auto-on.plist
launchctl start litra-auto-on

Hope this helps someone!

@aronrosenberg
Copy link

Hi Everybody,

Just a note that we have now integrated official support for Litra Lights being turned automatically on/off in the October 2023 release of GHub. This version will roll out to all users over the next week or two.

@aardvark82
Copy link

aardvark82 commented Oct 19, 2023

Excellent news! Thank you Aron & Logitech engineering team. Quick question - will this be supported in LogiOptions + as well or do we have to install both GHub for the Litra and logioptions+ separately for other devices?

@aronrosenberg
Copy link

This is only supported in GHub right now.

@Agusum
Copy link

Agusum commented Oct 26, 2023

Thanks for adding this feature to GHub!

Now all I need is to be able to manually turn it off using one of the programmable keys in my Logitech MX Keys. @aronrosenberg Are you looking to enable that feature?

@aronrosenberg
Copy link

You should already be able to assign Litra actions to a G key, just look for it under the assignments section for your keyboard.

@Agusum
Copy link

Agusum commented Oct 26, 2023

The Logitech MX Keys doesn't have G keys and it's not detected by GHub, only Logi Options+.

image

@aronrosenberg
Copy link

I missed the part where you said you had a MX Keys. That device is currently only supported in Options+ which does not have the Litra auto-on/off functionality at this time.

@Agusum
Copy link

Agusum commented Oct 27, 2023

Ideally there will only be one software for everything but I can live with having the auto on/off in GHub, if I'm able to have Smart actions for the light in Options+ to toggle it on/off manually, which are missing.

@patrickrushton
Copy link

@aronrosenberg Nice that this is now supported by Logitech G-Hub. Is there any progress with a native Apple Silicon version that doesn't require Rosetta?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment