I've been doing this recently:
-
Python script that
- runs a shell script query (pmset -g) every N seconds
- Checks the output to see if the "meeting state" has changed
- If the meeting state has changed, print some status information and update the BTT variable "meeting_app" so that its value is one of '', '
MSTeams
' 'Webex
', 'zoom.us
', where the empty value indicates no meeting in progress.
-
BTT Trigger on Variable Value did change / variable "meeting_app".
- Using this to run actions that change the set of buttons visible on my StreamDeck.
This are lots of ways to improve this*, but it does reliably work to change the streamdeck buttons soon after a meeting starts, and change them back when the meeting finishes. I'm on Sonoma 14.6 and have not tested this on other OS versions. The frequency with which you run pmset -g is related to how long this takes to notice that a meeting has started/stopped, and how much extra load you want to put on your mac in doing the monitoring. I found 5 sec to be reasonable.
I'd be happy to have some discussion about how other people are doing this; I found the pmset -g method by doing a lot of googling.
(*for instance, I'm just starting the py script in a terminal window rather than running it as a daemon. It dies occasionally for reasons I haven't tried to figure out yet, then I just restart it...)
The "upload" button doesn't seem to allow me to upload a python script, so I'll paste it in below...
# TODO add shebang
# meetingMonitor.py
# code to check whether we are in a Teams or Webex or Zoom Meeting
import re, argparse, subprocess, time
sleep_CRE = re.compile('sleep prevented by ([^()]+)')
# return the meeting app preventing sleep or None
def check_status():
#output = subprocess.check_output(['pmset', '-g']
# pmset -g for Teams: sleep 0 (sleep prevented by MSTeams, ...
# pmset -g for zoom : displaysleep 180 (display sleep prevented by zoom.us)
# Note, this is a separate line from ' sleep' (zoom only shows up in this line on Sonoma 14.6)
#pmsetCmd = 'pmset -g | grep "^ sleep"'
# Note, will return several lines
pmsetCmd = 'pmset -g | grep "^ [[:alpha:]]*sleep"'
output = subprocess.check_output(pmsetCmd, shell=True, encoding='UTF-8')
# The output of this will be more than one line
for line in output.splitlines():
m = sleep_CRE.search(line)
if m is not None:
# m.group(1) will be the list of things preventing sleep, i.e. : 'coreaudiod, WebexHelper'
unsleepers = m.group(1)
for meetingApp in ['MSTeams', 'Webex', 'zoom.us']:
if meetingApp in unsleepers:
return meetingApp
return None
# TODO maybe notify btt of the app the first time through the loop
def notify_btt(meetingApp=''):
if meetingApp is None:
meetingApp = ''
btt_args = ['open']
btt_url = f'"btt://set_persistent_string_variable/?variableName=meeting_app&to={meetingApp}"'
btt_args.append(btt_url)
if True:
print(f'[notify btt subproc args] {btt_args}')
try:
btt_args = " ".join(btt_args)
subprocess.check_call(btt_args, shell=True)
except:
# TODO, what to do on fail, for instance, if btt not open? TEST?
print('unable to update btt with meeting status')
def monitor_status(interval_sec=10, print_updates=True):
was_meeting = False
while True:
meetingApp = check_status()
is_meeting = meetingApp is not None
if was_meeting != is_meeting:
if print_updates:
print(f'Now Meeting [{is_meeting}] in app {meetingApp}')
was_meeting = is_meeting
notify_btt(meetingApp)
time.sleep(interval_sec)
if __name__ == '__main__':
parser = argparse.ArgumentParser(usage='MacOS monitor status of MSTeams and Webex and Zoom meetings')
# TODO maybe add print/noprint option
parser.add_argument('-i', '--interval', help='polling interval in sec', default=5, type=int)
args = parser.parse_args()
interval_sec = args.interval
if interval_sec < 1:
interval_sec = 1
try:
monitor_status(interval_sec)
except KeyboardInterrupt:
# OK, user pressed ctrl-c, clean exit
print(' Done.')