Change rendering method for GUI
Add installation scripts for Windows and Linux, and update README for usage instructions
This commit is contained in:
		
							parent
							
								
									1a01676d9f
								
							
						
					
					
						commit
						f6aa6cd626
					
				
							
								
								
									
										
											BIN
										
									
								
								DISCORD.lnk
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								DISCORD.lnk
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							| @ -11,14 +11,6 @@ This project allows you to control Discord mute and deafen status using an ESP32 | |||||||
| - An ESP32 device | - An ESP32 device | ||||||
| - A USB cable to connect the ESP32 to your computer | - A USB cable to connect the ESP32 to your computer | ||||||
| 
 | 
 | ||||||
| ### Python Packages |  | ||||||
| 
 |  | ||||||
| Install the required Python packages using pip: |  | ||||||
| 
 |  | ||||||
| ```sh |  | ||||||
| pip install pyserial keyboard pygetwindow pyautogui mss numpy pystray pillow |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### Clone the Repository | ### Clone the Repository | ||||||
| 
 | 
 | ||||||
| Clone this repository to your local machine: | Clone this repository to your local machine: | ||||||
| @ -28,14 +20,38 @@ git clone https://github.com/yourusername/ESP32-discord.git | |||||||
| cd ESP32-discord | cd ESP32-discord | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ### Windows Installation | ||||||
|  | 
 | ||||||
|  | Run the following batch file to set up the virtual environment and install the required Python packages: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | install_windows.bat | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Linux Installation | ||||||
|  | 
 | ||||||
|  | Run the following shell script to set up the virtual environment and install the required Python packages: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | ./install_linux.sh | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| ## Usage | ## Usage | ||||||
| 
 | 
 | ||||||
| ### Running the Script | ### Running the Script | ||||||
| 
 | 
 | ||||||
| You can run the script with the following command: | You can run the script with the following command: | ||||||
| 
 | 
 | ||||||
|  | #### Windows | ||||||
|  | 
 | ||||||
| ```sh | ```sh | ||||||
| python main.py | start.bat | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### Linux | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | ./start.sh | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ### Specifying the COM Port | ### Specifying the COM Port | ||||||
| @ -43,13 +59,17 @@ python main.py | |||||||
| You can specify the COM port directly when running the script: | You can specify the COM port directly when running the script: | ||||||
| 
 | 
 | ||||||
| ```sh | ```sh | ||||||
| python main.py -com=COM3 | pythonw main.pyw -com=COM3 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ### Hiding the Console Window | ### Hiding the Console Window | ||||||
| 
 | 
 | ||||||
| If the COM port is specified, the script will hide the console window and run in the system tray. You can quit the application from the tray icon. | If the COM port is specified, the script will hide the console window and run in the system tray. You can quit the application from the tray icon. | ||||||
| 
 | 
 | ||||||
|  | ### GUI | ||||||
|  | 
 | ||||||
|  | The script now includes a GUI that looks like Windows 11 dark mode. It will automatically hide the console window and show the GUI. | ||||||
|  | 
 | ||||||
| ## Notes | ## Notes | ||||||
| 
 | 
 | ||||||
| - Ensure that your ESP32 device is connected to your computer via USB. | - Ensure that your ESP32 device is connected to your computer via USB. | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								install_linux.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								install_linux.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | 
 | ||||||
|  | # Create a virtual environment | ||||||
|  | python3 -m venv .venv | ||||||
|  | 
 | ||||||
|  | # Activate the virtual environment | ||||||
|  | source .venv/bin/activate | ||||||
|  | 
 | ||||||
|  | # Install the required Python packages | ||||||
|  | pip install pyserial keyboard pygetwindow pyautogui mss numpy pystray pillow | ||||||
|  | 
 | ||||||
|  | # Deactivate the virtual environment | ||||||
|  | deactivate | ||||||
|  | 
 | ||||||
|  | echo "Installation complete. You can now run the application using start.sh." | ||||||
							
								
								
									
										15
									
								
								install_windows.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								install_windows.bat
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | @echo off | ||||||
|  | REM Create a virtual environment | ||||||
|  | python -m venv .venv | ||||||
|  | 
 | ||||||
|  | REM Activate the virtual environment | ||||||
|  | call .venv\Scripts\activate | ||||||
|  | 
 | ||||||
|  | REM Install the required Python packages | ||||||
|  | pip install pyserial keyboard pygetwindow pyautogui mss numpy pystray pillow | ||||||
|  | 
 | ||||||
|  | REM Deactivate the virtual environment | ||||||
|  | deactivate | ||||||
|  | 
 | ||||||
|  | echo Installation complete. You can now run the application using start.bat. | ||||||
|  | pause | ||||||
| @ -10,6 +10,25 @@ from PIL import Image, ImageDraw | |||||||
| import threading | import threading | ||||||
| import ctypes | import ctypes | ||||||
| import os | import os | ||||||
|  | import tkinter as tk | ||||||
|  | from tkinter import messagebox | ||||||
|  | from tkinter import ttk | ||||||
|  | 
 | ||||||
|  | # Define the region where the mute and deafen icons are located | ||||||
|  | x = -1772 | ||||||
|  | y = 1064 | ||||||
|  | x2 = -1746 | ||||||
|  | y2 = 1063 | ||||||
|  | 
 | ||||||
|  | # Define the size of the region to check | ||||||
|  | width = 4 | ||||||
|  | height = 4 | ||||||
|  | grid = 4 | ||||||
|  | 
 | ||||||
|  | # Define the expected color of the mute and deafen icons | ||||||
|  | expected_r = 242 | ||||||
|  | expected_g = 63 | ||||||
|  | expected_b = 67 | ||||||
| 
 | 
 | ||||||
| # Set the title for the PowerShell window | # Set the title for the PowerShell window | ||||||
| ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller") | ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller") | ||||||
| @ -26,26 +45,32 @@ def get_serial_port(): | |||||||
|     if len(sys.argv) > 1 and sys.argv[1].startswith("-com="): |     if len(sys.argv) > 1 and sys.argv[1].startswith("-com="): | ||||||
|         return sys.argv[1].split("=")[1] |         return sys.argv[1].split("=")[1] | ||||||
|      |      | ||||||
|     ports = list(list_ports.comports()) |     ports = [port for port in list(list_ports.comports()) if port.device != "COM1"] | ||||||
|     if not ports: |     if not ports: | ||||||
|         print("No serial ports found. Please connect a device.") |         messagebox.showerror("Error", "No serial ports found. Please connect a device.") | ||||||
|         return None |         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 |     if len(ports) == 1: | ||||||
| y = 1064 |         return ports[0].device | ||||||
| x2 = -1746 |      | ||||||
| y2 = 1063 |     port_choices = [port.device for port in ports] | ||||||
| width = 4 |      | ||||||
| height = 4 |     def on_select(): | ||||||
| expected_r = 242 |         selected_port.set(port_listbox.get(port_listbox.curselection())) | ||||||
| expected_g = 63 |         port_window.destroy() | ||||||
| expected_b = 67 |      | ||||||
| grid = 4 |     port_window = tk.Tk() | ||||||
|  |     port_window.title("Select Serial Port") | ||||||
|  |     port_window.configure(bg="#1e1e1e") | ||||||
|  |     tk.Label(port_window, text="Available Ports:", bg="#1e1e1e", fg="#ffffff").pack() | ||||||
|  |     port_listbox = tk.Listbox(port_window, bg="#2d2d2d", fg="#ffffff", selectbackground="#0078d7") | ||||||
|  |     for port in port_choices: | ||||||
|  |         port_listbox.insert(tk.END, port) | ||||||
|  |     port_listbox.pack() | ||||||
|  |     selected_port = tk.StringVar() | ||||||
|  |     tk.Button(port_window, text="Select", command=on_select, bg="#0078d7", fg="#ffffff").pack() | ||||||
|  |     port_window.mainloop() | ||||||
|  |     return selected_port.get() | ||||||
| 
 | 
 | ||||||
| def get_discord_status(): | def get_discord_status(): | ||||||
|     with mss.mss() as sct: |     with mss.mss() as sct: | ||||||
| @ -61,10 +86,6 @@ def get_discord_status(): | |||||||
|         mute_image = np.array(mute_screenshot) |         mute_image = np.array(mute_screenshot) | ||||||
|         deafen_image = np.array(deafen_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 |         # Check the pixel color in a 2x2 region | ||||||
|         mute_status = any( |         mute_status = any( | ||||||
|             (mute_image[i, j, 2] == expected_r and |             (mute_image[i, j, 2] == expected_r and | ||||||
| @ -95,32 +116,35 @@ def create_image(): | |||||||
|     return image |     return image | ||||||
| 
 | 
 | ||||||
| def toggle_console(): | def toggle_console(): | ||||||
|     whnd = ctypes.windll.kernel32.GetConsoleWindow() |     if console_window.state() == "normal": | ||||||
|     if whnd != 0: |         console_window.withdraw() | ||||||
|         if ctypes.windll.user32.IsWindowVisible(whnd): |  | ||||||
|             ctypes.windll.user32.ShowWindow(whnd, 0) |  | ||||||
|     else: |     else: | ||||||
|             ctypes.windll.user32.ShowWindow(whnd, 1) |         console_window.deiconify() | ||||||
|  | 
 | ||||||
|  | def log_message(message): | ||||||
|  |     log_text.insert(tk.END, message + "\n") | ||||||
|  |     log_text.see(tk.END) | ||||||
| 
 | 
 | ||||||
| def on_quit(icon, item): | def on_quit(icon, item): | ||||||
|     icon.stop() |     icon.stop() | ||||||
|     if 'ser' in globals() and ser.is_open: |     if 'ser' in globals() and ser.is_open: | ||||||
|         ser.close() |         ser.close() | ||||||
|         print("Serial connection closed.") |         log_message("Serial connection closed.") | ||||||
|  |     console_window.withdraw() | ||||||
|  |     console_window.quit() | ||||||
|     sys.exit(0) |     sys.exit(0) | ||||||
| 
 | 
 | ||||||
| def hide_console(): | def hide_console(): | ||||||
|     whnd = ctypes.windll.kernel32.GetConsoleWindow() |     log_message("Hiding console window...") | ||||||
|     if whnd != 0: |     time.sleep(2) | ||||||
|         ctypes.windll.user32.ShowWindow(whnd, 0) |     console_window.withdraw() | ||||||
|         ctypes.windll.kernel32.CloseHandle(whnd) |  | ||||||
| 
 | 
 | ||||||
| def hide_in_tray(): | def hide_in_tray(): | ||||||
|     hide_console() |  | ||||||
|     icon = pystray.Icon("ESP32-discord") |     icon = pystray.Icon("ESP32-discord") | ||||||
|     icon.icon = create_image() |     icon.icon = create_image() | ||||||
|     icon.menu = pystray.Menu(pystray.MenuItem('Quit', on_quit), pystray.MenuItem('Toggle Console', toggle_console)) |     icon.menu = pystray.Menu(pystray.MenuItem('Quit', on_quit), pystray.MenuItem('Toggle Console', toggle_console)) | ||||||
|     threading.Thread(target=icon.run).start() |     threading.Thread(target=icon.run).start() | ||||||
|  |     hide_console() | ||||||
| 
 | 
 | ||||||
| def main(): | def main(): | ||||||
|     global ser |     global ser | ||||||
| @ -131,20 +155,20 @@ def main(): | |||||||
|     try: |     try: | ||||||
|         ser = serial.Serial(port, 115200, timeout=1) |         ser = serial.Serial(port, 115200, timeout=1) | ||||||
|         time.sleep(2)  # Wait for the connection to initialize |         time.sleep(2)  # Wait for the connection to initialize | ||||||
|         print("Listening for commands...") |         log_message("Listening for commands...") | ||||||
|          |          | ||||||
|         last_mute_status, last_deafen_status = get_discord_status() |         last_mute_status, last_deafen_status = get_discord_status() | ||||||
|         print(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}") |         log_message(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}") | ||||||
|         ser.write(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}\n".encode('utf-8')) |         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() |         hide_in_tray() | ||||||
| 
 | 
 | ||||||
|  |          | ||||||
|         while True: |         while True: | ||||||
|             try: |             try: | ||||||
|                 if ser.in_waiting > 0: |                 if ser.in_waiting > 0: | ||||||
|                     line = ser.readline().decode('utf-8').strip() |                     line = ser.readline().decode('utf-8').strip() | ||||||
|                     print(f"Received: {line}") |                     log_message(f"Received: {line}") | ||||||
|                      |                      | ||||||
|                     if line == "mute": |                     if line == "mute": | ||||||
|                         keyboard.send('ctrl+shift+f16') |                         keyboard.send('ctrl+shift+f16') | ||||||
| @ -154,28 +178,39 @@ def main(): | |||||||
|                         mute_status, deafen_status = get_discord_status() |                         mute_status, deafen_status = get_discord_status() | ||||||
|                         ser.write(f"Mute: {mute_status}, Deafen: {deafen_status}\n".encode('utf-8')) |                         ser.write(f"Mute: {mute_status}, Deafen: {deafen_status}\n".encode('utf-8')) | ||||||
|                     else: |                     else: | ||||||
|                         print(f"Unknown command: {line}") |                         log_message(f"Unknown command: {line}") | ||||||
|                      |                      | ||||||
|                 current_mute_status, current_deafen_status = get_discord_status() |                 current_mute_status, current_deafen_status = get_discord_status() | ||||||
|                 if current_mute_status != last_mute_status or current_deafen_status != last_deafen_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')) |                     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}") |                     log_message(f"Mute: {current_mute_status}, Deafen: {current_deafen_status}") | ||||||
|                     last_mute_status, last_deafen_status = current_mute_status, current_deafen_status |                     last_mute_status, last_deafen_status = current_mute_status, current_deafen_status | ||||||
|                  |                  | ||||||
|                 time.sleep(0.1) |                 time.sleep(0.1) | ||||||
|             except KeyboardInterrupt: |             except KeyboardInterrupt: | ||||||
|                 print("Exiting program.") |                 log_message("Exiting program.") | ||||||
|                 break |                 break | ||||||
|             except Exception as e: |             except Exception as e: | ||||||
|                 print(f"Error during execution: {e}") |                 log_message(f"Error during execution: {e}") | ||||||
|                 break |                 break | ||||||
|      |      | ||||||
|     except serial.SerialException as e: |     except serial.SerialException as e: | ||||||
|         print(f"Could not open serial port: {e}") |         messagebox.showerror("Error", f"Could not open serial port: {e}") | ||||||
|     finally: |     finally: | ||||||
|         if 'ser' in globals() and ser.is_open: |         if 'ser' in globals() and ser.is_open: | ||||||
|             ser.close() |             ser.close() | ||||||
|             print("Serial connection closed.") |             log_message("Serial connection closed.") | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     main() |     console_window = tk.Tk() | ||||||
|  |     console_window.title("ESP32 Discord Controller") | ||||||
|  |     console_window.configure(bg="#1e1e1e") | ||||||
|  |     style = ttk.Style() | ||||||
|  |     style.theme_use('clam') | ||||||
|  |     style.configure("TLabel", background="#1e1e1e", foreground="#ffffff") | ||||||
|  |     style.configure("TButton", background="#0078d7", foreground="#ffffff") | ||||||
|  |     style.configure("TText", background="#2d2d2d", foreground="#ffffff") | ||||||
|  |     log_text = tk.Text(console_window, wrap=tk.WORD, bg="#2d2d2d", fg="#ffffff") | ||||||
|  |     log_text.pack(expand=True, fill=tk.BOTH) | ||||||
|  |     threading.Thread(target=main).start() | ||||||
|  |     console_window.mainloop() | ||||||
							
								
								
									
										9
									
								
								start.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								start.bat
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | @echo off | ||||||
|  | REM Activate the virtual environment | ||||||
|  | call .venv\Scripts\activate | ||||||
|  | 
 | ||||||
|  | REM Run the Python script | ||||||
|  | start pythonw main.pyw | ||||||
|  | 
 | ||||||
|  | REM Deactivate the virtual environment | ||||||
|  | deactivate | ||||||
| @ -2,7 +2,7 @@ | |||||||
| & .venv\Scripts\activate | & .venv\Scripts\activate | ||||||
| 
 | 
 | ||||||
| # Run the Python script | # Run the Python script | ||||||
| python main.py -com=COM3 | pythonw main.pyw | ||||||
| 
 | 
 | ||||||
| # Deactivate the virtual environment | # Deactivate the virtual environment | ||||||
| deactivate | deactivate | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user