import serial import time import keyboard import serial.tools.list_ports as list_ports import mss import numpy as np import sys import pystray from PIL import Image, ImageDraw import threading import ctypes import os # Set the title for the PowerShell window ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller") # Set the process name for Task Manager try: import ctypes ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller") os.system("title ESP32 Discord Controller") except: pass def get_serial_port(): if len(sys.argv) > 1 and sys.argv[1].startswith("-com="): return sys.argv[1].split("=")[1] ports = list(list_ports.comports()) if not ports: print("No serial ports found. Please connect a device.") return None print("Available Ports:") for i, port in enumerate(ports): print(f"{i}: {port.device}") choice = int(input("Select a port by number: ")) return ports[choice].device x = -1772 y = 1064 x2 = -1746 y2 = 1063 width = 4 height = 4 expected_r = 242 expected_g = 63 expected_b = 67 grid = 4 def get_discord_status(): with mss.mss() as sct: # Define the region where the mute and deafen icons are located mute_region = {"top": y, "left": x, "width": width, "height": height} deafen_region = {"top": y2, "left": x2, "width": width, "height": height} # Capture the screen region mute_screenshot = sct.grab(mute_region) deafen_screenshot = sct.grab(deafen_region) # Convert the screenshots to numpy arrays mute_image = np.array(mute_screenshot) deafen_image = np.array(deafen_screenshot) # Save the screenshots to files mss.tools.to_png(mute_screenshot.rgb, mute_screenshot.size, output="mute_screenshot.png") mss.tools.to_png(deafen_screenshot.rgb, deafen_screenshot.size, output="deafen_screenshot.png") # Check the pixel color in a 2x2 region mute_status = any( (mute_image[i, j, 2] == expected_r and mute_image[i, j, 1] == expected_g and mute_image[i, j, 0] == expected_b) for i in range(grid) for j in range(grid) ) deafen_status = any( (deafen_image[i, j, 2] == expected_r and deafen_image[i, j, 1] == expected_g and deafen_image[i, j, 0] == expected_b) for i in range(grid) for j in range(grid) ) return mute_status, deafen_status def create_image(): # Generate an image for the system tray icon width = 64 height = 64 image = Image.new('RGB', (width, height), (255, 255, 255)) dc = ImageDraw.Draw(image) dc.rectangle( [(width // 2, 0), (width, height // 2)], fill="black") dc.rectangle( [(0, height // 2), (width // 2, height)], fill="black") return image def toggle_console(): whnd = ctypes.windll.kernel32.GetConsoleWindow() if whnd != 0: if ctypes.windll.user32.IsWindowVisible(whnd): ctypes.windll.user32.ShowWindow(whnd, 0) else: ctypes.windll.user32.ShowWindow(whnd, 1) def on_quit(icon, item): icon.stop() if 'ser' in globals() and ser.is_open: ser.close() print("Serial connection closed.") sys.exit(0) def hide_console(): whnd = ctypes.windll.kernel32.GetConsoleWindow() if whnd != 0: ctypes.windll.user32.ShowWindow(whnd, 0) ctypes.windll.kernel32.CloseHandle(whnd) def hide_in_tray(): hide_console() icon = pystray.Icon("ESP32-discord") icon.icon = create_image() icon.menu = pystray.Menu(pystray.MenuItem('Quit', on_quit), pystray.MenuItem('Toggle Console', toggle_console)) threading.Thread(target=icon.run).start() def main(): global ser port = get_serial_port() if not port: return try: ser = serial.Serial(port, 115200, timeout=1) time.sleep(2) # Wait for the connection to initialize print("Listening for commands...") last_mute_status, last_deafen_status = get_discord_status() print(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}") ser.write(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}\n".encode('utf-8')) if len(sys.argv) > 1 and sys.argv[1].startswith("-com="): hide_in_tray() while True: try: if ser.in_waiting > 0: line = ser.readline().decode('utf-8').strip() print(f"Received: {line}") if line == "mute": keyboard.send('ctrl+shift+f16') elif line == "deafen": keyboard.send('ctrl+shift+f15') elif line == "status": mute_status, deafen_status = get_discord_status() ser.write(f"Mute: {mute_status}, Deafen: {deafen_status}\n".encode('utf-8')) else: print(f"Unknown command: {line}") current_mute_status, current_deafen_status = get_discord_status() if current_mute_status != last_mute_status or current_deafen_status != last_deafen_status: ser.write(f"Mute: {current_mute_status}, Deafen: {current_deafen_status}\n".encode('utf-8')) print(f"Mute: {current_mute_status}, Deafen: {current_deafen_status}") last_mute_status, last_deafen_status = current_mute_status, current_deafen_status time.sleep(0.1) except KeyboardInterrupt: print("Exiting program.") break except Exception as e: print(f"Error during execution: {e}") break except serial.SerialException as e: print(f"Could not open serial port: {e}") finally: if 'ser' in globals() and ser.is_open: ser.close() print("Serial connection closed.") if __name__ == "__main__": main()