Now that the micro controller is programmed, Remainder is to code for reading the serial input and turn the camera and mic on/off depending on the situation. Needed to find some way that Zoom application can be manipulated thru code. As an API for zoom did not exist, first thought was to turn the camera and mic off in device level. but, that seemed like an inefficient way, as there could be issues when reconnecting the devices to zoom app (automatically). the only remaining option was - automation.
Python seemed like the best choice for this. simply due to the support , ease of use, and familiarity. There was no way to get the initial status of the camera and the mic, therefore, a simple GUI was created to launch the application and to see whether the camera and mic is open when the app is open (user input).
GUI indicates whether the app is started or not, and a radio button to indicate the status of the camera/mic. The code is below
import time
import tkinter
import tkinter as tk
from tkinter import messagebox
from threading import *
import sys,os
from main import PresentEx
from PIL import ImageTk
def Confirm():
# print("Thread")
if(t1.isAlive()):
messagebox.showwarning(title=None, message="Program is already running")
labelRunning['text'] = 'Running'
labelRunning['bg'] = 'green'
else:
labelRunning['text'] = 'Not Running'
labelRunning['bg'] = 'red'
if (var.get()<=0):
messagebox.showwarning(title=None, message="Please Select camera/audio status")
else:
Threading()
labelRunning['text'] = 'Running'
labelRunning['bg'] = 'green'
def work():
MainCode = PresentEx(var.get())
MainCode.main()
t1 = Thread(target = work)
def Threading():
global t1
t1.start()
# t1.join()
# time.sleep(5)
def Exit():
global window
global t1
window.destroy()
window.quit()
os._exit(1)
t1.terminate
window = tk.Tk()
window.title('Present!')
window.geometry
window.resizable(False,False)
screen_width = window.winfo_screenwidth()
screen_height = window.winfo_screenheight()
window_width = int(screen_width*0.2)
window_height = int(screen_height*0.1)
window.geometry(f'{window_width}x{window_height}')
var = tk.IntVar()
CameraStatus = tk.Label(window, text= "Is the camera and audio off/on right now?").place(x =(window_width*0.01),y=(window_height*0.09))
p1 = ImageTk.PhotoImage(file ='meeting2.png')
window.iconphoto(False, p1)
labelRunning = tkinter.Label(window, text="")
labelRunning.pack(side=tk.LEFT, pady=30, padx=10)
labelRunning.place(x=window_width * 0.02, y=window_height * 0.65)
if (t1.isAlive()):
labelRunning['text'] = 'Running'
labelRunning['bg'] = 'green'
else:
labelRunning['text'] = 'Not Running'
labelRunning['bg'] = 'red'
print("thread Status")
print(t1.isAlive())
R1 = tk.Radiobutton(window, text="On", variable=var, value=1)
R1.pack(side=tk.LEFT,pady=30,padx=10)
R2 = tk.Radiobutton(window, text="Off", variable=var, value=2)
R2.pack(side=tk.LEFT,pady=30)
B = tk.Button(window, text ="Confirm", command = Confirm)
B.place(x=window_width*0.6, y=window_height*0.4)
B = tk.Button(window, text ="Exit", command = Exit)
B.place(x=window_width*0.8, y=window_height*0.4)
print(window_height,window_width)
window.mainloop()
The GUI starts the background process on a separate thread, so as to avoid crashing the GUI. Tkinter has been used to create the GUI. the GUI calls the PresentEX class from main.py. which has the functionality of automation. The main.py is as below
import serial
import time
import keyboard
import win32gui, win32com.client
import pyautogui
testArray = []
class PresentEx():
serialLine = ""
def __init__(self,status):
self.status = status
def winEnumHandler(hwnd, ctx):
global testArray
if win32gui.IsWindowVisible(hwnd):
count = 0
a = win32gui.GetWindowText(hwnd)
testArray.append(a)
def SerialInitiate(self):
serialLine = serial.Serial('COM3', 9600)
time.sleep(0.1)
return serialLine
def ZoomFunctionality(self,ProgramArray):
global testArray
print(ProgramArray)
if(self.status == 1): #2off 1on
self.status = 2
else:
if "Zoom" in ProgramArray:
ZoomInstances = ProgramArray.count("Zoom")
print(ZoomInstances)
if ZoomInstances >=2:
hwndZoomMeeting = win32gui.FindWindow(None,"Zoom")
print(hwndZoomMeeting)
win32gui.SetForegroundWindow(hwndZoomMeeting)
time.sleep(0.1)
pyautogui.hotkey('alt', 'a')
time.sleep(0.1)
print("audio Disabled")
pyautogui.hotkey('alt', 'v')
time.sleep(0.1)
print("video Disabled")
else:
if "Zoom Meeting" in ProgramArray:
print("XXXX")
hwndZoomMeeting = win32gui.FindWindow(None,"Zoom Meeting")
print(hwndZoomMeeting)
win32gui.SetForegroundWindow(hwndZoomMeeting)
time.sleep(0.1)
pyautogui.hotkey('alt', 'a')
time.sleep(0.1)
print("audio Disabled")
pyautogui.hotkey('alt', 'v')
time.sleep(0.1)
print("video Disabled")
testArray = []
print(self.status)
def main(self):
serialLine = PresentEx.SerialInitiate(self)
print("initiate")
print(self.status)
while (1):
time.sleep(0.1)
try:
print(serialLine.readline().decode().rstrip() == 'PERSON DETECTED')
if (serialLine.readline().decode().rstrip() == 'PERSON DETECTED'):
win32gui.EnumWindows(PresentEx.winEnumHandler, None)
print("IN LOOP")
serialLine.flushInput()
PresentEx.ZoomFunctionality(self,testArray)
while(1):
print("Person Still There")
if (serialLine.readline().decode().rstrip() == "NO PERSON DETECTED"):
win32gui.EnumWindows(PresentEx.winEnumHandler, None)
print(testArray)
PresentEx.ZoomFunctionality(self,testArray)
print("Zoom Turned OFF")
break
serialLine.flushInput()
time.sleep(3)
# serialLine.flushInput()
# print(serialLine.readline().decode().rstrip() == 'PIRSensed')
print("Wait Done")
serialLine.flushInput()
except (UnicodeDecodeError):
print("Unicode Decode Error Exception Handled")
pass
if __name__ == '__main__':
main()
Serial library has been used to read the serial data from the arduino, and pyautogui has been used to automate the functions. The process is as follows. Zoom application has two windows. the main window, which is named "Zoom" and the meeting window is named "Zoom Meeting" and once you minimize the window, the video floats and the floating window is named "Zoom" as well.
Zoom has hotkeys to turn on/off the camera, and turn on/off the mic. Alt+a for the mic, and Alt+v for the camera.
Software chooses the window based on the name, brings it to top, and executes the hotkeys from pyautogui. Hopefully, this gets the job done.
Next, testing.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.