Add system tray functionality and improve Discord status detection logic

This commit is contained in:
ZareMate 2025-01-13 20:23:39 +01:00
parent 2fdfa7d3df
commit 062c6252a2
Signed by: zaremate
GPG Key ID: 369A0E45E03A81C3
7 changed files with 130 additions and 16 deletions

1
.gitignore vendored
View File

@ -0,0 +1 @@
./*.png

Binary file not shown.

60
README.md Normal file
View File

@ -0,0 +1,60 @@
# ESP32 Discord Controller
This project allows you to control Discord mute and deafen status using an ESP32 device. The script captures the screen to detect the status and communicates with the ESP32 via a serial connection.
## Installation
### Prerequisites
- Python 3.x
- pip (Python package installer)
- An ESP32 device
- 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 this repository to your local machine:
```sh
git clone https://github.com/yourusername/ESP32-discord.git
cd ESP32-discord
```
## Usage
### Running the Script
You can run the script with the following command:
```sh
python main.py
```
### Specifying the COM Port
You can specify the COM port directly when running the script:
```sh
python main.py -com=COM3
```
### 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.
## Notes
- Ensure that your ESP32 device is connected to your computer via USB.
- The script captures a small region of the screen to detect the mute and deafen status. Adjust the coordinates and dimensions in the script if necessary.
## License
This project is licensed under the MIT License.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 99 B

83
main.py
View File

@ -2,13 +2,21 @@ import serial
import time
import keyboard
import serial.tools.list_ports as list_ports
import pygetwindow as gw
import pyautogui
import mss
import numpy as np
import sys
import pystray
from PIL import Image, ImageDraw
import threading
import ctypes
# Set the title for the PowerShell window
ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller")
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.")
@ -20,14 +28,15 @@ def get_serial_port():
return ports[choice].device
x = -1772
y = 1059
x2 = -1745
y2 = 1064
width = 1
height = 1
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:
@ -47,16 +56,57 @@ def get_discord_status():
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 at (0, 0)
mute_status = (mute_image[0, 0, 2] == expected_r and
mute_image[0, 0, 1] == expected_g and
mute_image[0, 0, 0] == expected_b)
deafen_status = (deafen_image[0, 0, 2] == expected_r and
deafen_image[0, 0, 1] == expected_g and
deafen_image[0, 0, 0] == expected_b)
# 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 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))
threading.Thread(target=icon.run).start()
def main():
global ser
port = get_serial_port()
if not port:
return
@ -70,6 +120,9 @@ def main():
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:
@ -103,7 +156,7 @@ def main():
except serial.SerialException as e:
print(f"Could not open serial port: {e}")
finally:
if 'ser' in locals() and ser.is_open:
if 'ser' in globals() and ser.is_open:
ser.close()
print("Serial connection closed.")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 110 B

View File

@ -2,7 +2,7 @@
& .venv\Scripts\activate
# Run the Python script
python main.py
python main.py -com=COM3
# Deactivate the virtual environment
deactivate