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):
|
if len(ports) == 1:
|
||||||
print(f"{i}: {port.device}")
|
return ports[0].device
|
||||||
choice = int(input("Select a port by number: "))
|
|
||||||
return ports[choice].device
|
port_choices = [port.device for port in ports]
|
||||||
|
|
||||||
x = -1772
|
def on_select():
|
||||||
y = 1064
|
selected_port.set(port_listbox.get(port_listbox.curselection()))
|
||||||
x2 = -1746
|
port_window.destroy()
|
||||||
y2 = 1063
|
|
||||||
width = 4
|
port_window = tk.Tk()
|
||||||
height = 4
|
port_window.title("Select Serial Port")
|
||||||
expected_r = 242
|
port_window.configure(bg="#1e1e1e")
|
||||||
expected_g = 63
|
tk.Label(port_window, text="Available Ports:", bg="#1e1e1e", fg="#ffffff").pack()
|
||||||
expected_b = 67
|
port_listbox = tk.Listbox(port_window, bg="#2d2d2d", fg="#ffffff", selectbackground="#0078d7")
|
||||||
grid = 4
|
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):
|
else:
|
||||||
ctypes.windll.user32.ShowWindow(whnd, 0)
|
console_window.deiconify()
|
||||||
else:
|
|
||||||
ctypes.windll.user32.ShowWindow(whnd, 1)
|
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