Добавлена бета терминалка

Для подключния к мышке надо её отключить сначала от windows, т.е. к уже открытому каналу bluetooth она не подключится
This commit is contained in:
Razvalyaev 2025-05-22 19:53:57 +03:00
parent 4539a0787f
commit 7dffb83d05
17 changed files with 37734 additions and 0 deletions

274
py_mouse_gue/ble_gui.py Normal file
View File

@ -0,0 +1,274 @@
import asyncio
import threading
import colorsys
from tkinter import Tk, Button, Label, Scale, HORIZONTAL, Canvas, Frame
from PIL import Image, ImageTk
from bleak import BleakClient, BleakScanner
import math
TARGET_NAME = "Ball Mouse"
COLOR_SERVICE_UUID = "12345678-1234-5678-1234-56789abcdef0"
COLOR_CHAR_R_UUID = "12345678-1234-5678-1234-56789abcdef1"
COLOR_CHAR_G_UUID = "12345678-1234-5678-1234-56789abcdef2"
COLOR_CHAR_B_UUID = "12345678-1234-5678-1234-56789abcdef3"
COLOR_CHAR_BRIGHTNESS_UUID = "12345678-1234-5678-1234-56789abcdef4"
# Часто используемые цвета (R, G, B)
preset_colors = [
(255, 0, 0), # Красный
(0, 255, 0), # Зеленый
(0, 0, 255), # Синий
(255, 255, 0), # Желтый
(255, 0, 255), # Пурпурный
(0, 255, 255), # Голубой (циан)
(255, 255, 255) # Белый
]
class BLEController:
def __init__(self):
self.client = None
async def connect(self):
devices = await BleakScanner.discover()
device = next((d for d in devices if d.name and TARGET_NAME in d.name), None)
if not device:
print("BLE-устройство не найдено")
return False
self.client = BleakClient(device.address)
try:
await self.client.connect()
print("Подключено к", device.name)
return True
except Exception as e:
print("Ошибка подключения:", e)
return False
async def send_color_components(self, r, g, b, brightness=255):
if not self.client or not self.client.is_connected:
print("Не подключено к устройству")
return False
try:
await self.client.write_gatt_char(COLOR_CHAR_R_UUID, bytes([r]))
await self.client.write_gatt_char(COLOR_CHAR_G_UUID, bytes([g]))
await self.client.write_gatt_char(COLOR_CHAR_B_UUID, bytes([b]))
await self.client.write_gatt_char(COLOR_CHAR_BRIGHTNESS_UUID, bytes([brightness]))
print(f"Отправлен цвет: R={r} G={g} B={b} яркость={brightness}")
return True
except Exception as e:
print("Ошибка при отправке:", e)
return False
async def read_color_and_brightness(self):
if not self.client or not self.client.is_connected:
print("Не подключено к устройству")
return None
try:
r_bytes = await self.client.read_gatt_char(COLOR_CHAR_R_UUID)
g_bytes = await self.client.read_gatt_char(COLOR_CHAR_G_UUID)
b_bytes = await self.client.read_gatt_char(COLOR_CHAR_B_UUID)
brightness_bytes = await self.client.read_gatt_char(COLOR_CHAR_BRIGHTNESS_UUID)
r = int.from_bytes(r_bytes, byteorder="little")
g = int.from_bytes(g_bytes, byteorder="little")
b = int.from_bytes(b_bytes, byteorder="little")
brightness = int.from_bytes(brightness_bytes, byteorder="little")
return (r, g, b, brightness)
except Exception as e:
print("Ошибка чтения цвета и яркости:", e)
return None
def create_color_wheel(size):
radius = size // 2
image = Image.new("RGB", (size, size), (255, 255, 255))
pixels = image.load()
for x in range(size):
for y in range(size):
dx = x - radius
dy = y - radius
dist = math.sqrt(dx*dx + dy*dy)
if dist <= radius:
hue = (math.atan2(dy, dx) / (2 * math.pi)) + 0.5
saturation = dist / radius
r, g, b = colorsys.hsv_to_rgb(hue, saturation, 1)
pixels[x, y] = (int(r*255), int(g*255), int(b*255))
else:
pixels[x, y] = (255, 255, 255)
return image
def run_gui():
brightness_send_job = None
brightness_delay_ms = 100 # например, 100 мс задержки
ble = BLEController()
root = Tk()
root.title("BLE RGB Контроллер")
label = Label(root, text="Ожидание подключения...")
label.pack(pady=10)
brightness_scale = Scale(root, from_=0, to=100, orient=HORIZONTAL, label="Яркость", length=300)
brightness_scale.set(100)
brightness_scale.pack(pady=10)
canvas_size = 300
radius = canvas_size // 2
canvas = Canvas(root, width=canvas_size, height=canvas_size)
canvas.pack()
pil_image = create_color_wheel(canvas_size)
tk_image = ImageTk.PhotoImage(pil_image)
canvas.create_image(0, 0, anchor="nw", image=tk_image)
selected_color = [0, 0, 0]
# Создаем фрейм для кнопок с цветами
preset_frame = Frame(root)
preset_frame.pack(pady=10)
# Квадрат для отображения итогового цвета
color_display = Frame(root, width=100, height=100, bg="#000000", relief="sunken", borderwidth=2)
color_display.pack(pady=10)
def on_read():
label.config(text="Чтение данных...")
def read_and_update():
color_bright = asyncio.run(ble.read_color_and_brightness())
if color_bright is None:
root.after(0, lambda: label.config(text="Ошибка чтения данных"))
return
r, g, b, brightness = color_bright
selected_color[0], selected_color[1], selected_color[2] = r, g, b
def update_gui():
brightness_scale.set(brightness)
update_color_display(r, g, b, brightness)
label.config(text=f"Считано: R={r} G={g} B={b}, яркость={brightness}")
root.after(0, update_gui)
threading.Thread(target=read_and_update).start()
def update_color_display(r, g, b, brightness):
# Учитываем яркость — просто умножаем компоненты на коэффициент
factor = brightness / 100
r_adj = int(r * factor)
g_adj = int(g * factor)
b_adj = int(b * factor)
hex_color = f"#{r_adj:02x}{g_adj:02x}{b_adj:02x}"
color_display.config(bg=hex_color)
def send_color_and_update(r, g, b):
brightness = brightness_scale.get()
async def task():
return await ble.send_color_components(r, g, b, brightness)
def thread_func():
result = asyncio.run(task())
def update_label():
if result:
label.config(text="Цвет установлен")
else:
label.config(text="Цвет не установлен")
root.after(0, update_label)
threading.Thread(target=thread_func).start()
update_color_display(r, g, b, brightness)
def on_canvas_click(event):
dx = event.x - radius
dy = event.y - radius
dist = math.sqrt(dx*dx + dy*dy)
if dist > radius:
return
hue = (math.atan2(dy, dx) / (2 * math.pi)) + 0.5
saturation = dist / radius
r, g, b = colorsys.hsv_to_rgb(hue, saturation, 1)
r, g, b = int(r*255), int(g*255), int(b*255)
selected_color[0], selected_color[1], selected_color[2] = r, g, b
send_color_and_update(r, g, b)
canvas.bind("<Button-1>", on_canvas_click)
def on_preset_click(r, g, b):
selected_color[0], selected_color[1], selected_color[2] = r, g, b
send_color_and_update(r, g, b)
for color in preset_colors:
r, g, b = color
hex_color = f"#{r:02x}{g:02x}{b:02x}"
btn = Button(preset_frame, bg=hex_color, width=3, height=1,
command=lambda r=r, g=g, b=b: on_preset_click(r, g, b))
btn.pack(side="left", padx=3)
def delayed_send_brightness():
nonlocal brightness_send_job
brightness_send_job = None
r, g, b = selected_color
send_color_and_update(r, g, b)
def on_brightness_change(val):
nonlocal brightness_send_job
if brightness_send_job is not None:
root.after_cancel(brightness_send_job)
brightness_send_job = root.after(brightness_delay_ms, delayed_send_brightness)
brightness_scale.config(command=on_brightness_change)
def on_connect():
label.config(text="Подключение...")
def connect_and_sync():
result = asyncio.run(ble.connect())
if not result:
root.after(0, lambda: label.config(text="Ошибка подключения"))
return
# Читаем цвет и яркость из устройства
color_bright = asyncio.run(ble.read_color_and_brightness())
if color_bright is None:
root.after(0, lambda: label.config(text="Не удалось прочитать цвет"))
return
r, g, b, brightness = color_bright
selected_color[0], selected_color[1], selected_color[2] = r, g, b
# Обновляем GUI в основном потоке
def update_gui():
brightness_scale.set(brightness)
update_color_display(r, g, b, brightness)
label.config(text=f"Подключено: R={r} G={g} B={b}, яркость={brightness}")
root.after(0, update_gui)
# Отправляем цвет-яркость на устройство для синхронизации
send_color_and_update(r, g, b)
threading.Thread(target=connect_and_sync).start()
connect_btn = Button(root, text="Подключиться к мыши", command=on_connect)
connect_btn.pack(pady=10)
read_btn = Button(root, text="Считать", command=on_read)
read_btn.pack(pady=10)
root.mainloop()
if __name__ == "__main__":
run_gui()

38
py_mouse_gue/ble_gui.spec Normal file
View File

@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['ble_gui.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='ble_gui',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,86 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean this module is required for running your program. Python and
Python 3rd-party packages include a lot of conditional or optional modules. For
example the module 'ntpath' only exists on Windows, whereas the module
'posixpath' only exists on Posix systems.
Types if import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named pyimod02_importers - imported by C:\Users\wot89\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed), C:\Users\wot89\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgres.py (delayed)
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), setuptools._distutils.util (delayed, conditional, optional), netrc (delayed, conditional), getpass (delayed, optional), setuptools._vendor.backports.tarfile (optional), setuptools._distutils.archive_util (optional), http.server (delayed, optional)
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), setuptools._vendor.backports.tarfile (optional), setuptools._distutils.archive_util (optional)
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
missing module named fcntl - imported by subprocess (optional), _pyrepl.unix_console (top-level)
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional), _pyrepl.unix_console (delayed, optional)
missing module named resource - imported by posix (top-level)
missing module named _manylinux - imported by packaging._manylinux (delayed, optional), setuptools._vendor.packaging._manylinux (delayed, optional), setuptools._vendor.wheel.vendored.packaging._manylinux (delayed, optional)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
missing module named _scproxy - imported by urllib.request (conditional)
missing module named termios - imported by getpass (optional), tty (top-level), _pyrepl.pager (delayed, optional), _pyrepl.unix_console (top-level), _pyrepl.fancy_termios (top-level), _pyrepl.unix_eventqueue (top-level)
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
missing module named usercustomize - imported by site (delayed, optional)
missing module named sitecustomize - imported by site (delayed, optional)
missing module named _curses - imported by curses (top-level), curses.has_key (top-level), _pyrepl.curses (optional)
missing module named readline - imported by site (delayed, optional), rlcompleter (optional), code (delayed, conditional, optional)
missing module named trove_classifiers - imported by setuptools.config._validate_pyproject.formats (optional)
missing module named typing_extensions.Buffer - imported by setuptools._vendor.typing_extensions (top-level), setuptools._vendor.wheel.wheelfile (conditional)
missing module named typing_extensions.Literal - imported by setuptools._vendor.typing_extensions (top-level), setuptools.config._validate_pyproject.formats (conditional)
missing module named typing_extensions.Self - imported by setuptools._vendor.typing_extensions (top-level), setuptools.config.expand (conditional), setuptools.config.pyprojecttoml (conditional), setuptools.config._validate_pyproject.error_reporting (conditional)
missing module named typing_extensions.deprecated - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.sysconfig (conditional), setuptools._distutils.command.bdist (conditional)
missing module named typing_extensions.TypeAlias - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.compilers.C.base (conditional), setuptools._reqs (conditional), setuptools.warnings (conditional), setuptools._path (conditional), setuptools._distutils.dist (conditional), setuptools.config.setupcfg (conditional), setuptools.config._apply_pyprojecttoml (conditional), setuptools.dist (conditional), setuptools.command.bdist_egg (conditional), setuptools.compat.py311 (conditional)
missing module named typing_extensions.Unpack - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.util (conditional), setuptools._distutils.compilers.C.base (conditional), setuptools._distutils.cmd (conditional)
missing module named typing_extensions.TypeVarTuple - imported by setuptools._vendor.typing_extensions (top-level), setuptools._distutils.util (conditional), setuptools._distutils.compilers.C.base (conditional), setuptools._distutils.cmd (conditional)
missing module named '_typeshed.importlib' - imported by pkg_resources (conditional)
missing module named _typeshed - imported by setuptools._distutils.dist (conditional), setuptools.glob (conditional), setuptools.compat.py311 (conditional), pkg_resources (conditional)
missing module named jnius - imported by bleak.backends.p4android.client (top-level), bleak.backends.p4android.defs (top-level), bleak.backends.p4android.utils (top-level), bleak.backends.p4android.scanner (top-level), setuptools._vendor.platformdirs.android (delayed, conditional, optional)
missing module named android - imported by bleak.backends.p4android.client (top-level), setuptools._vendor.platformdirs.android (delayed, conditional, optional)
missing module named importlib_resources - imported by setuptools._vendor.jaraco.text (optional)
missing module named 'collections.abc' - imported by traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level), tracemalloc (top-level), asyncio.base_events (top-level), http.client (top-level), asyncio.coroutines (top-level), PIL.Image (top-level), PIL._typing (top-level), setuptools (top-level), setuptools._distutils.filelist (top-level), setuptools._distutils.util (top-level), setuptools._vendor.jaraco.functools (top-level), setuptools._vendor.more_itertools.more (top-level), setuptools._vendor.more_itertools.recipes (top-level), setuptools._distutils._modified (top-level), setuptools._distutils.compat (top-level), setuptools._distutils.spawn (top-level), setuptools._distutils.compilers.C.base (top-level), setuptools._distutils.fancy_getopt (top-level), setuptools._reqs (top-level), setuptools.discovery (top-level), setuptools.dist (top-level), setuptools._distutils.command.bdist (top-level), setuptools._distutils.core (top-level), setuptools._distutils.cmd (top-level), setuptools._distutils.dist (top-level), configparser (top-level), setuptools._distutils.extension (top-level), setuptools.config.setupcfg (top-level), setuptools.config.expand (top-level), setuptools.config.pyprojecttoml (top-level), setuptools.config._apply_pyprojecttoml (top-level), tomllib._parser (top-level), setuptools._vendor.tomli._parser (top-level), setuptools.command.egg_info (top-level), setuptools._distutils.command.build (top-level), setuptools._distutils.command.sdist (top-level), setuptools.glob (top-level), setuptools.command._requirestxt (top-level), setuptools.command.bdist_wheel (top-level), setuptools._vendor.wheel.cli.convert (top-level), setuptools._vendor.wheel.cli.tags (top-level), setuptools._vendor.typing_extensions (top-level), xml.etree.ElementTree (top-level), PIL.TiffImagePlugin (top-level), PIL.ImageOps (top-level), PIL.ImagePalette (top-level), PIL.ImageFilter (top-level), PIL.PngImagePlugin (top-level), bleak (conditional), bleak.backends.client (conditional), bleak.backends.bluezdbus.client (conditional), winrt.system (top-level), bleak.backends.corebluetooth.client (conditional), bleak.backends.winrt.client (conditional), pkg_resources (top-level), setuptools._vendor.platformdirs.windows (conditional), PIL.Jpeg2KImagePlugin (top-level), PIL.IptcImagePlugin (top-level), setuptools._distutils.command.build_ext (top-level), _pyrepl.types (top-level), _pyrepl.readline (top-level), setuptools._distutils.compilers.C.msvc (top-level)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
missing module named vms_lib - imported by platform (delayed, optional)
missing module named 'java.lang' - imported by platform (delayed, optional)
missing module named java - imported by platform (delayed)
missing module named bleak_winrt - imported by bleak.backends.winrt.scanner (conditional)
missing module named 'winrt.windows.networking' - imported by winrt._winrt_windows_devices_bluetooth (top-level)
missing module named 'winrt.windows.devices.radios' - imported by winrt._winrt_windows_devices_bluetooth (top-level)
missing module named 'winrt.windows.devices.bluetooth.rfcomm' - imported by winrt._winrt_windows_devices_bluetooth (top-level)
missing module named 'winrt.windows.ui' - imported by winrt._winrt_windows_devices_enumeration (top-level)
missing module named 'winrt.windows.security' - imported by winrt._winrt_windows_devices_enumeration (top-level)
missing module named 'winrt.windows.applicationmodel' - imported by winrt._winrt_windows_devices_enumeration (top-level)
missing module named 'winrt.windows.system' - imported by winrt._winrt_windows_storage_streams (top-level)
missing module named 'bleak_winrt.windows' - imported by bleak.backends.winrt.client (conditional), bleak.backends.winrt.characteristic (conditional), bleak.backends.winrt.descriptor (conditional), bleak.backends.winrt.service (conditional)
missing module named libdispatch - imported by bleak.backends.corebluetooth.CentralManagerDelegate (top-level)
missing module named Foundation - imported by bleak.backends.corebluetooth.scanner (top-level), bleak.backends.corebluetooth.CentralManagerDelegate (top-level), bleak.backends.corebluetooth.utils (top-level), bleak.backends.corebluetooth.client (top-level), bleak.backends.corebluetooth.PeripheralDelegate (top-level)
missing module named CoreBluetooth - imported by bleak.backends.corebluetooth.scanner (top-level), bleak.backends.corebluetooth.CentralManagerDelegate (top-level), bleak.backends.corebluetooth.utils (top-level), bleak.backends.corebluetooth.client (top-level), bleak.backends.corebluetooth.characteristic (top-level), bleak.backends.corebluetooth.descriptor (top-level), bleak.backends.corebluetooth.PeripheralDelegate (top-level), bleak.backends.corebluetooth.service (top-level)
missing module named objc - imported by bleak.backends.corebluetooth (top-level), bleak.backends.corebluetooth.scanner (top-level), bleak.backends.corebluetooth.CentralManagerDelegate (top-level), bleak.backends.corebluetooth.PeripheralDelegate (top-level)
missing module named 'dbus_fast.message' - imported by bleak.backends.bluezdbus.client (top-level), bleak.backends.bluezdbus.utils (top-level), bleak.backends.bluezdbus.signals (top-level)
missing module named 'dbus_fast.constants' - imported by bleak.backends.bluezdbus.client (top-level), bleak.backends.bluezdbus.utils (top-level)
missing module named 'dbus_fast.auth' - imported by bleak.backends.bluezdbus.utils (top-level)
missing module named 'dbus_fast.validators' - imported by bleak.backends.bluezdbus.signals (top-level)
missing module named 'dbus_fast.errors' - imported by bleak.backends.bluezdbus.signals (top-level)
missing module named 'dbus_fast.aio' - imported by bleak.backends.bluezdbus.manager (top-level), bleak.backends.bluezdbus.signals (top-level)
missing module named 'dbus_fast.service' - imported by bleak.backends.bluezdbus.advertisement_monitor (top-level)
missing module named dbus_fast - imported by bleak.backends.bluezdbus.client (top-level), bleak.backends.bluezdbus.manager (top-level), bleak.backends.bluezdbus.scanner (top-level)
missing module named 'android.permissions' - imported by bleak.backends.p4android.scanner (top-level)
missing module named 'android.broadcast' - imported by bleak.backends.p4android.scanner (top-level)
missing module named 'dbus_fast.signature' - imported by bleak.backends.bluezdbus.client (top-level)
missing module named async_timeout - imported by bleak (conditional), bleak.backends.bluezdbus.client (conditional), bleak.backends.p4android.scanner (conditional), bleak.backends.corebluetooth.CentralManagerDelegate (conditional), bleak.backends.winrt.util (conditional), bleak.backends.corebluetooth.PeripheralDelegate (conditional), bleak.backends.winrt.client (conditional)
missing module named numpy - imported by PIL._typing (conditional, optional)
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
missing module named PIL._avif - imported by PIL (optional), PIL.AvifImagePlugin (optional)
missing module named defusedxml - imported by PIL.Image (optional)
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)

File diff suppressed because it is too large Load Diff

BIN
py_mouse_gue/dist/ble_gui.exe vendored Normal file

Binary file not shown.