How to Integrate Webex Status Indication with Philips Hue
Usually, the following happens…
- Son (opens the office door): “Dad! where is my Power Rangers Dino Charge Beast Saber Sword?”
- Daughter (opens the office door): “Dad, where is the phone charger?“.
- Wife (very softly opens the office door): “Just a quick question… can you pick up the kids later today?“.
- Mother-in-law when visiting (opens the office door): “What is the issue with the water pressure??” (BTW, there is no issue with the water pressure…).
Yes, I did ask them (many times) to be more mindful/considerable and check if I’m on a call before approaching these super-important questions.
Then I asked my son the following:
- Me: “Buddy, you see that I’m working and on a video call. Can you wait a bit with your question?“.
- Son: “But dad! I didn’t know that you were in a meeting with the video on…“.
Well, he is right. He didn’t know that I was on a video call. So… How can I “better educate” my family to know when I’m on a call and prefer not to be disturbed?
My options:
- Ask again (and again) – I will do that, but I need something more immediate…
- Use some physical indication every time I’m in a meeting (see 👉) – That wouldn’t scale…
- Relocate my office space – Then I’ll be far away from the refrigerator 😉
- Leverage & integrate different technologies – Yes! 👍
The Plan
Let’s integrate Webex (status indication) with Philips Hue! That way, they will know (see! 👀) my availability status!
- Green == Available.
- Blue == On a call.
- Orange== On a Webex meeting with video OFF.
- Red== On a Webex meeting with video ON.
- Yellow == Asking for quiet time (DoNotDisturb).
Cisco Webex and Philips Hue expose their APIs
As both Webex and Philips Hue expose their APIs, that shouldn’t be complicated. Right?
Well, I found two challenges
- Webex Token:
- Webex API requires a valid and permanent token
- The personal token is limited to 12 hours
- The guest user token cannot access the “status” data as it isn’t part of the organization
- The integration token (OAuth grant using a web browser) isn’t applicable for a simple script
- How can I find out if/when the Webex video is turned on/off during a call? 🤔
After some quick research, I came up with the following solutions
- Create a new Webex Bot and leverage its token (which is permanent and part of the organization).
- Option #1 – Use this Webex API call. The response returns if the participants are using video or not. However, when I tried that, I always got “video: off” in the response. I had a quick discussion with the Webex Dev team, and they confirmed it is a bug (also, the API call works ONLY if you are the meeting host…).
- Option #2 – Use the macOS “log stream” CLI command to track when the video is being used. True, It’s a bit more complicated, but… worth it. (To learn more about the “log stream,” check here).
The Code (Mac OS only) 👨💻
To constantly tail the Mac OS “log stream” log (to track if the video is on/off), and at the same time, run the Webex API code portion, I created a multithreaded python script. One thread is dedicated to tail the “log stream”, while the second thread is dedicated to the Webex API integration code.
Let’s review the code
Step #1 – Import the required python modules.
- requests – Python HTTP library.
- phue – Philips Hue library.
- time – To set up a sleep statement.
- Threading & Subprocess – For multithreading.
importrequests
from phue import Bridge
from threading import Thread
from time import sleep
import subprocess
Step #2 – Define Webex and Philips Hue variables.
- myID – My personal Webex ID (check here for more info).
- URL – Webex API call to determine my availability status.
- token – Webex Bot token.
- bridgeIpAddress – Philips Hue bridge IP address.
# Webex variables myID = "xxx" url = "https://webexapis.com/v1/people/" + myID token = "xxx" # pHue variables bridgeIpAddress = 'x.x.x.x'
Step #3 – Define the Philips Hue connectivity function (Note: the first connection will require authentication using: “b.connect()”).
def access_lights(bridgeIpAddress): b = Bridge(bridgeIpAddress) # b.connect() light_names = b.get_light_objects('name') return light_names
Step #4 – Define the five availability options/functions.
- The functions are applicable for the “Office Lightstrip” (you can configure a group of lights as well).
- on/off – On/Off state of the light.
- hue – The hue value to set light to (The hue value is a wrapping value between 0 and 65535).
- saturation – Saturation of the light (254 is the most saturated, colored, and 0 is the least saturated, white).
- brightness – The brightness value to set the light to (Brightness is a scale from 1, the minimum the light is capable of, to 254, the maximum).
def active():
lights = access_lights(bridgeIpAddress)
for light in ['Office Lightstrip']:
lights[light].on = True
lights[light].hue = 25500 # Green
lights[light].saturation = 254
lights[light].brightness = 254
def call():
lights = access_lights(bridgeIpAddress)
for light in ['Office Lightstrip']:
lights[light].on = True
lights[light].hue = 46920 # Blue
lights[light].saturation = 254
lights[light].brightness = 254
def meeting_without_video():
lights = access_lights(bridgeIpAddress)
for light in ['Office Lightstrip']:
lights[light].on = True
lights[light].hue = 7000 # Orange
lights[light].saturation = 254
lights[light].brightness = 254
def meeting_with_video():
lights = access_lights(bridgeIpAddress)
for light in ['Office Lightstrip']:
lights[light].on = True
lights[light].hue = 65535 # Red
lights[light].saturation = 254
lights[light].brightness = 254
def DoNotDisturb():
lights = access_lights(bridgeIpAddress)
for light in ['Office Lightstrip']:
lights[light].on = True
lights[light].hue = 12750 # Yellow
lights[light].saturation = 254
lights[light].brightness = 254
Step #5 – Define the function to check if the is video is on/off.
- The creation of the “output.txt” file was needed as I was unable to (really) tail the “log stream” process/output (the “output.txt” file stores the video status information, which is used in step 6). If you have a suggestion for a better approach, let me know!
- the full (unparsed) “log stream” command is: “log stream –info –debug –predicate ‘(process == “VDCAssistant”) and (eventMessage contains “Post event kCameraStream”)’” Learn more about the “log stream” command).
def func1(): f = open("output.txt", "w") subprocess.call(['/usr/bin/log', 'stream' ,'--info', '--debug', '--predicate' , '(process == "VDCAssistant") and (eventMessage contains "Post event kCameraStream")'], stdout=f) return f
Step #6 – Check the Webex status indication AND the video status to determine the Philips Hue light color.
- This function runs on a 5 seconds loop to check the 8 conditions.
- print statements were added for debugging/demo purposes.
def func2(): while True: sleep(5) headers = { 'Authorization': 'Bearer ' + token } response = requests.request("GET", url, headers=headers) r_json = response.json() myStatus = r_json["status"] with open("output.txt", "r") as file: result = (list(file)[-1]) if "kCameraStreamStart" in result and myStatus == "meeting": # print("Meeting is ON and Video is ON") meeting_with_video() elif "kCameraStreamStart" not in result and myStatus == "meeting": # print("Meeting is ON and Video is OFF") meeting_without_video() elif "kCameraStreamStart" in result and myStatus == "active": # print("Available") active() elif "kCameraStreamStart" not in result and myStatus == "active": # print("Available") active() elif "kCameraStreamStart" in result and myStatus == "call": # print("On a Call") call() elif "kCameraStreamStart" not in result and myStatus == "call": # print("On a Call") call() elif "kCameraStreamStart" in result and myStatus == "DoNotDisturb": # print("DoNotDisturb") DoNotDisturb() elif "kCameraStreamStart" not in result and myStatus == "DoNotDisturb": # print("DoNotDisturb") DoNotDisturb() if __name__ == '__main__': Thread(target = func1).start() Thread(target = func2).start()
The Demo 🎥
Final thoughts
BTW, over the weekend, I found another (funny) solution 👇 😉
Related resources
We’d love to hear what you think. Ask a question or leave a comment below.
And stay connected with Cisco DevNet on social!
Twitter @CiscoDevNet | Facebook | LinkedIn
Visit the new Developer Video Channel