У меня есть программа Tkinter, которая использует несколько библиотек (matplotlib, numpy, pygame, …), а также мрачную библиотеку BLE. Я создаю exe-файл в Windows с помощью PyInstaller, и большая часть программы работает правильно, за исключением случаев, когда я пытаюсь использовать мрачную библиотеку. Я получаю исключения и упоминание в трассировке ModuleNotFoundError: Нет модуля с именем «winrt.windows.foundation.collections»
Я не знаю, как решить проблему, и буду признателен за помощь!Вот пример сообщений, которые я получаю:
2024-10-23 14:09:21,946 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run*emphasized text*
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
__________________ ОБНОВЛЕНИЕ _________________
Это большая программа, состоящая из 3500+ строк, поэтому я извлек простой модуль ble, который воспроизводит ошибки.
from __future__ import annotations
import asyncio
import threading
import tkinter as tk
from bleak import BleakScanner, BleakClient
from bleak.backends.device import BLEDevice
from bleak.backends.service import BleakGATTService, BleakGATTServiceCollection
import bleak.exc
import logging
import copy
import seq, dmutil, dme
# from concurrent.futures import ThreadPoolExecutor
# from bleak.exc import BleakError
# https://stackoverflow.com/questions/621 ... th-asyncio
# https://bleak.readthedocs.io/en/latest/ ... ce%20Bleak
# https://stackoverflow.com/questions/638 ... th-asyncio
class Ble:
DM_DATA_SERVICE_UUID = "36794f20-3a88-418c-8df8-7394c5c80200"
DM_COMMAND_CHAR_UUID = "36794f20-3a88-418c-8df8-7394c5c80201"
DM_BRIGHT_CHAR_UUID = "36794f20-3a88-418c-8df8-7394c5c80202"
def __init__(self, app) -> None:
def run_asyncio_loop(loop):
"""Run an asyncio loop forever"""
asyncio.set_event_loop(loop)
loop.run_forever()
# Create and start a thread for the ble asynchronous loop
self.ble_loop = asyncio.new_event_loop()
asyncio_thread = threading.Thread(
target=run_asyncio_loop, args=(self.ble_loop,), daemon=True
)
asyncio_thread.start()
self.app: dme.App = app
self.found_dm = False
self.device: BLEDevice
self.client: BleakClient
async def aio_scan_for_dm(self) -> bool:
"""Scan BLE devices looking for DM. Store device/client info if found"""
logging.info("Scanning Bluetooth Low Energy for devices ...")
self.found_dm = False
devices = await BleakScanner.discover()
for device in devices:
logging.info(f"Found device {device.name} at {device.address} ")
if device.name and (device.name.startswith("DM_")):
self.found_dm = True
self.device = device
self.client = BleakClient(self.device, timeout=5.0)
return self.found_dm
async def aio_connect(self) -> bool:
"""Connect to the found DM"""
logging.info(f"Connecting to {self.name} ...")
if not self.found_dm:
await self.aio_scan_for_dm()
if self.found_dm:
try:
await self.client.connect()
logging.info("Connected ...")
except asyncio.exceptions.TimeoutError as e:
logging.error(f"Can't connect to device {self.device.address} {e}.")
return False
else:
return False
return True
async def aio_disconnect(self) -> None:
"""Disconnect from the DM"""
logging.info(f"Disconnecting from {self.name} ...")
if self.found_dm and self.client.is_connected:
await self.client.disconnect()
async def aio_send_brightness(self, level: int):
"""Set DM brightness level"""
if not (0 bytearray:
"""Encode one step"""
data = bytearray()
data.append(cmd_index)
data.append(osc_index)
data.extend(duration.to_bytes(2, byteorder="big"))
data.extend(Ble.encode_led(oscillator.leds).to_bytes(2, byteorder="big"))
data.extend(int(oscillator.f_start * 10).to_bytes(2, byteorder="big"))
data.extend(int(oscillator.f_end * 10).to_bytes(2, byteorder="big"))
data.append(int(oscillator.d_start))
data.append(int(oscillator.d_end))
data.extend(int(oscillator.b_start * 10).to_bytes(2, byteorder="big"))
data.extend(int(oscillator.b_end * 10).to_bytes(2, byteorder="big"))
# s = [" ".join(format(x, "02x") for x in data)]
# logging.info(s)
return data
async def aio_send_step(self, step: seq.Step):
"""Send one Step to the DM"""
logging.info(
f"Sending the step with index={step.index} osc {len(step.oscillators)} to {self.name}"
)
duration = step.t_end - step.t_start
data: list[bytearray] = []
data.append(bytearray([1])) # start command list
# data.append(bytearray.fromhex("00000001000707d007d0646400320005"))
# data.append(bytearray.fromhex("01000001006007d007d0646400320005"))
# data.append(bytearray.fromhex("02000001001807d007d0646400320005"))
# data.append(bytearray.fromhex("03000001018007d007d0646400320005"))
# data.append(bytearray.fromhex("04000001000107d007d0646400320005"))
# append all the oscillators for this step
for osc_idx, osc in enumerate(step.oscillators):
data.append(Ble.encode_oscillator(0, osc_idx, duration, osc))
data.append(bytearray([2])) # start playing step
try:
for cmd in data:
logging.info(f"{cmd.hex(" ", 2)}")
await self.client.write_gatt_char(Ble.DM_COMMAND_CHAR_UUID, cmd)
except bleak.exc.BleakError as e:
logging.info(f"Can't send data to {self.name}: {e}")
async def aio_send_seq(self, seq: seq.Sequence):
"""Send one Step to the DM"""
logging.info(
f"Sending sequence {seq.name} to {self.name} with {len(seq.steps)} steps length={seq.duration}"
)
data: list[bytearray] = []
data.append(bytearray([1])) # start command code
# append all steps
for step_idx, step in enumerate(seq.steps):
duration = step.t_end - step.t_start
# append all the oscillators for this step
for osc_idx, osc in enumerate(step.oscillators):
if osc.leds == []: # if no led used skip
continue
data.append(Ble.encode_oscillator(step_idx, osc_idx, duration, osc))
data.append(bytearray([2])) # stop cmd code: start playing step
# send the sequence to the DM
try:
for cmd in data:
logging.info(f"--- {cmd.hex(" ", 2)}")
await self.client.write_gatt_char(Ble.DM_COMMAND_CHAR_UUID, cmd)
except bleak.exc.BleakError as e:
logging.info(f"Can't send data to {self.name}: {e}")
async def aio_show_ble_info(self):
"""Show Services, Characteritic, and Descriptor of a connected DM (for debug)"""
for service in self.client.services:
logging.info("Services:")
for service in self.client.services:
logging.info(f"- Service Description: {service.description}")
logging.info(f" UUID: {service.uuid}")
logging.info(f" Handle: {service.handle}")
for char in service.characteristics:
value = None
if "read" in char.properties:
try:
value = bytes(await self.client.read_gatt_char(char))
except Exception as error:
value = error
logging.info(f" - Characteristic Description: {char.description}")
logging.info(f" UUID: {char.uuid}")
logging.info(f" Handle: {char.handle}")
logging.info(f" Properties: {', '.join(char.properties)}")
logging.info(f" Value: {value}")
for descriptor in char.descriptors:
desc_value = None
try:
desc_value = bytes(
await self.client.read_gatt_descriptor(char.handle)
)
except Exception as error:
desc_value = error
logging.info(
f" - Descriptor Description: {descriptor.description}"
)
logging.info(f" UUID: {descriptor.uuid}")
logging.info(f" Handle: {descriptor.handle}")
logging.info(f" Value: {desc_value}")
@property
def name(self) -> str | None:
if self.found_dm:
return self.device.name
return ""
@property
def address(self) -> str | None:
if self.found_dm:
return self.device.address
return ""
@property
def is_connected(self) -> bool:
if self.found_dm:
return self.client.is_connected
else:
return False
async def aio_play_seq(self, seq) -> None:
logging.info("Play thread started")
await self.aio_send_brightness(self.app.param_frame.brightness_var.get())
await self.aio_send_seq(seq)
await asyncio.sleep(seq.duration)
def play_dmled(self, position: float):
if position == 0.0: # send original sequence
asyncio.run_coroutine_threadsafe(
self.aio_play_seq(self.app.sequence), self.ble_loop
)
else: # we create a new seq that start from position
cur_step, pos, osc_values = dmutil.step_pos_values_at_time(
position, self.app.sequence
)
actual_step = self.app.sequence.steps[cur_step]
oscillators = []
for osc_idx, osc in enumerate(actual_step.oscillators):
osc.f_start = osc_values[osc_idx][0]
osc.f_end = actual_step.oscillators[osc_idx].f_end
osc.b_start = osc_values[osc_idx][1]
osc.b_end = actual_step.oscillators[osc_idx].b_end
osc.d_start = osc_values[osc_idx][2]
osc.d_end = actual_step.oscillators[osc_idx].d_end
osc.leds = actual_step.oscillators[osc_idx].leds
oscillators.append(osc)
duration = actual_step.t_end - actual_step.t_start - pos
# logging.info(f"{cur_step=} {pos=} {duration=}")
new_step = seq.Step(actual_step.index, 0, duration, oscillators)
# logging.info(new_step)
# create a sequence starting with new_step
new_seq = seq.Sequence("temp_seq", None, 0, [new_step])
# now add the following steps
last_time = duration
if cur_step != len(self.app.sequence.steps) - 1:
for step_idx, step in enumerate(
self.app.sequence.steps[cur_step + 1 :]
):
new_seq.steps.insert(step_idx + 1, copy.deepcopy(step))
duration = step.t_end - step.t_start
new_seq.steps[-1].t_start = last_time
new_seq.steps[-1].t_end = last_time + duration
new_seq.steps[-1].index = step.index
new_seq.steps[-1].oscillators = step.oscillators
last_time = new_seq.steps[-1].t_end
new_seq.duration = new_seq.steps[-1].t_end
# logging.info(new_seq)
asyncio.run_coroutine_threadsafe(self.aio_play_seq(new_seq), self.ble_loop)
def stop_dmled(self):
asyncio.run_coroutine_threadsafe(self.aio_stop_seq(), self.ble_loop)
####################### BELOW TEST ###############################
####################### BELOW TEST ###############################
####################### BELOW TEST ###############################
class App(tk.Tk):
"""Test program: scan for dm, connect/disconnect, send sequence"""
def __init__(self) -> None:
super().__init__()
self.ble = Ble(self)
self.loop = self.ble.ble_loop
self.title("Test BLE")
self.protocol("WM_DELETE_WINDOW", self._quit)
logging.basicConfig(
level=20,
format="{asctime} - {module} {levelname} - {message}",
style="{",
# datefmt="%Y-%m-%d %H:%M:%S",
)
tk.Button(self, text="Scan DM", width=15, command=self.scan_for_dm).grid(
row=0, column=0, padx=5, sticky="w"
)
self.tb_dm_name = tk.Label(
self,
width=30,
justify="left",
bg="silver",
text="Click scan ...",
anchor="w",
)
self.tb_dm_name.grid(row=0, column=1, sticky="w")
self.bt_connect = tk.Button(
self, text="Connect", width=15, command=self.connect_disconnect
)
self.bt_connect.grid(row=1, column=0, padx=5, sticky="w")
self.tb_dm_status = tk.Label(
self, width=30, text="Disconnected", justify="left", anchor="w", bg="silver"
)
self.tb_dm_status.grid(row=1, column=1, sticky="w")
scan_button = tk.Button(self, text="Test DM", width=15, command=self.start_test)
scan_button.grid(row=2, column=0, columnspan=2, padx=5, sticky="w")
def _quit(self) -> None:
self.quit()
self.destroy()
def scan_for_dm(self):
# Submit the scan task to the asyncio loop and set up a callback
future = asyncio.run_coroutine_threadsafe(self.ble.aio_scan_for_dm(), self.loop)
future.add_done_callback(lambda f: self.update_dm_name())
def connect_disconnect(self):
if not self.ble.is_connected:
self.tb_dm_status.configure(text=f"Connecting...")
future = asyncio.run_coroutine_threadsafe(self.ble.aio_connect(), self.loop)
else:
self.tb_dm_status.configure(text=f"Disonnecting...")
future = asyncio.run_coroutine_threadsafe(
self.ble.aio_disconnect(), self.loop
)
future.add_done_callback(lambda f: self.update_dm_status())
future.add_done_callback(lambda f: self.update_dm_name())
def start_test(self):
logging.info("calling test_dm in a thread")
asyncio.run_coroutine_threadsafe(self.test_dm(), self.loop)
def update_dm_name(self):
# Update the text with detected devices
if self.ble.found_dm:
self.tb_dm_name.configure(
text=f"{self.ble.name} ({self.ble.address})",
justify="left",
)
else:
self.tb_dm_name.configure(text="No DM found", justify="left")
def update_dm_status(self):
# Update the text with connection status
if self.ble.is_connected:
self.tb_dm_status.configure(text=f"Connected")
self.bt_connect.configure(text="Disconnect")
else:
self.tb_dm_status.configure(text=f"Disconnected")
self.bt_connect.configure(text="Connect", justify="left")
async def test_dm(self) -> None:
osc1 = seq.Oscillator(["A1", "A4", "B1"], 9, 10, 50, 50, 80, 10)
osc2 = seq.Oscillator(["A1", "A5", "B2"], 8, 9, 30, 30, 10, 80)
step1 = seq.Step(0, 0, 10, [osc1, osc2])
step2 = seq.Step(0, 0, 5, [osc2, osc1])
if not self.ble.is_connected:
await self.ble.aio_connect()
await self.ble.aio_send_brightness(50)
await self.ble.aio_send_step(step1)
await asyncio.sleep(5)
logging.info("changing brightness at middle of step")
await self.ble.aio_send_brightness(20)
await asyncio.sleep(5)
logging.info("second step")
await self.ble.aio_send_brightness(50)
await self.ble.aio_send_step(step2)
# create seq
logging.info("Creating and sending sequence")
new_seq = seq.Sequence("Test", None, 15, [step1, step2])
await self.ble.aio_send_seq(new_seq)
if __name__ == "__main__":
app = App() # build initial display
app.mainloop() # process tkinter events
чтобы воспроизвести ошибку, используйте
pyinstaller ble.py
сгенерированный запуск программы
здесь находится начало файла журнала, создаваемого при запуске
2024-10-25 14:10:31,659 - ble INFO - Scanning Bluetooth Low Energy for devices ...
2024-10-25 14:10:32,744 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:32,746 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,026 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,030 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,990 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,993 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:34,307 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
Подробнее здесь: https://stackoverflow.com/questions/791 ... ollections
ModuleNotFoundError: нет модуля с именем «winrt.windows.foundation.collections». ⇐ Python
Программы на Python
1729858576
Anonymous
У меня есть программа Tkinter, которая использует несколько библиотек (matplotlib, numpy, pygame, …), а также мрачную библиотеку BLE. Я создаю exe-файл в Windows с помощью PyInstaller, и большая часть программы работает правильно, за исключением случаев, когда я пытаюсь использовать мрачную библиотеку. Я получаю исключения и упоминание в трассировке ModuleNotFoundError: Нет модуля с именем «winrt.windows.foundation.collections»
Я не знаю, как решить проблему, и буду признателен за помощь!Вот пример сообщений, которые я получаю:
2024-10-23 14:09:21,946 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run*emphasized text*
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
__________________ ОБНОВЛЕНИЕ _________________
Это большая программа, состоящая из 3500+ строк, поэтому я извлек простой модуль ble, который воспроизводит ошибки.
from __future__ import annotations
import asyncio
import threading
import tkinter as tk
from bleak import BleakScanner, BleakClient
from bleak.backends.device import BLEDevice
from bleak.backends.service import BleakGATTService, BleakGATTServiceCollection
import bleak.exc
import logging
import copy
import seq, dmutil, dme
# from concurrent.futures import ThreadPoolExecutor
# from bleak.exc import BleakError
# https://stackoverflow.com/questions/62162898/run-bleak-python-library-in-background-with-asyncio
# https://bleak.readthedocs.io/en/latest/troubleshooting.html#:~:text=Calling%20asyncio.run()%20more%20than%20once%20Bleak
# https://stackoverflow.com/questions/63858511/using-threads-in-combination-with-asyncio
class Ble:
DM_DATA_SERVICE_UUID = "36794f20-3a88-418c-8df8-7394c5c80200"
DM_COMMAND_CHAR_UUID = "36794f20-3a88-418c-8df8-7394c5c80201"
DM_BRIGHT_CHAR_UUID = "36794f20-3a88-418c-8df8-7394c5c80202"
def __init__(self, app) -> None:
def run_asyncio_loop(loop):
"""Run an asyncio loop forever"""
asyncio.set_event_loop(loop)
loop.run_forever()
# Create and start a thread for the ble asynchronous loop
self.ble_loop = asyncio.new_event_loop()
asyncio_thread = threading.Thread(
target=run_asyncio_loop, args=(self.ble_loop,), daemon=True
)
asyncio_thread.start()
self.app: dme.App = app
self.found_dm = False
self.device: BLEDevice
self.client: BleakClient
async def aio_scan_for_dm(self) -> bool:
"""Scan BLE devices looking for DM. Store device/client info if found"""
logging.info("Scanning Bluetooth Low Energy for devices ...")
self.found_dm = False
devices = await BleakScanner.discover()
for device in devices:
logging.info(f"Found device {device.name} at {device.address} ")
if device.name and (device.name.startswith("DM_")):
self.found_dm = True
self.device = device
self.client = BleakClient(self.device, timeout=5.0)
return self.found_dm
async def aio_connect(self) -> bool:
"""Connect to the found DM"""
logging.info(f"Connecting to {self.name} ...")
if not self.found_dm:
await self.aio_scan_for_dm()
if self.found_dm:
try:
await self.client.connect()
logging.info("Connected ...")
except asyncio.exceptions.TimeoutError as e:
logging.error(f"Can't connect to device {self.device.address} {e}.")
return False
else:
return False
return True
async def aio_disconnect(self) -> None:
"""Disconnect from the DM"""
logging.info(f"Disconnecting from {self.name} ...")
if self.found_dm and self.client.is_connected:
await self.client.disconnect()
async def aio_send_brightness(self, level: int):
"""Set DM brightness level"""
if not (0 bytearray:
"""Encode one step"""
data = bytearray()
data.append(cmd_index)
data.append(osc_index)
data.extend(duration.to_bytes(2, byteorder="big"))
data.extend(Ble.encode_led(oscillator.leds).to_bytes(2, byteorder="big"))
data.extend(int(oscillator.f_start * 10).to_bytes(2, byteorder="big"))
data.extend(int(oscillator.f_end * 10).to_bytes(2, byteorder="big"))
data.append(int(oscillator.d_start))
data.append(int(oscillator.d_end))
data.extend(int(oscillator.b_start * 10).to_bytes(2, byteorder="big"))
data.extend(int(oscillator.b_end * 10).to_bytes(2, byteorder="big"))
# s = [" ".join(format(x, "02x") for x in data)]
# logging.info(s)
return data
async def aio_send_step(self, step: seq.Step):
"""Send one Step to the DM"""
logging.info(
f"Sending the step with index={step.index} osc {len(step.oscillators)} to {self.name}"
)
duration = step.t_end - step.t_start
data: list[bytearray] = []
data.append(bytearray([1])) # start command list
# data.append(bytearray.fromhex("00000001000707d007d0646400320005"))
# data.append(bytearray.fromhex("01000001006007d007d0646400320005"))
# data.append(bytearray.fromhex("02000001001807d007d0646400320005"))
# data.append(bytearray.fromhex("03000001018007d007d0646400320005"))
# data.append(bytearray.fromhex("04000001000107d007d0646400320005"))
# append all the oscillators for this step
for osc_idx, osc in enumerate(step.oscillators):
data.append(Ble.encode_oscillator(0, osc_idx, duration, osc))
data.append(bytearray([2])) # start playing step
try:
for cmd in data:
logging.info(f"{cmd.hex(" ", 2)}")
await self.client.write_gatt_char(Ble.DM_COMMAND_CHAR_UUID, cmd)
except bleak.exc.BleakError as e:
logging.info(f"Can't send data to {self.name}: {e}")
async def aio_send_seq(self, seq: seq.Sequence):
"""Send one Step to the DM"""
logging.info(
f"Sending sequence {seq.name} to {self.name} with {len(seq.steps)} steps length={seq.duration}"
)
data: list[bytearray] = []
data.append(bytearray([1])) # start command code
# append all steps
for step_idx, step in enumerate(seq.steps):
duration = step.t_end - step.t_start
# append all the oscillators for this step
for osc_idx, osc in enumerate(step.oscillators):
if osc.leds == []: # if no led used skip
continue
data.append(Ble.encode_oscillator(step_idx, osc_idx, duration, osc))
data.append(bytearray([2])) # stop cmd code: start playing step
# send the sequence to the DM
try:
for cmd in data:
logging.info(f"--- {cmd.hex(" ", 2)}")
await self.client.write_gatt_char(Ble.DM_COMMAND_CHAR_UUID, cmd)
except bleak.exc.BleakError as e:
logging.info(f"Can't send data to {self.name}: {e}")
async def aio_show_ble_info(self):
"""Show Services, Characteritic, and Descriptor of a connected DM (for debug)"""
for service in self.client.services:
logging.info("Services:")
for service in self.client.services:
logging.info(f"- Service Description: {service.description}")
logging.info(f" UUID: {service.uuid}")
logging.info(f" Handle: {service.handle}")
for char in service.characteristics:
value = None
if "read" in char.properties:
try:
value = bytes(await self.client.read_gatt_char(char))
except Exception as error:
value = error
logging.info(f" - Characteristic Description: {char.description}")
logging.info(f" UUID: {char.uuid}")
logging.info(f" Handle: {char.handle}")
logging.info(f" Properties: {', '.join(char.properties)}")
logging.info(f" Value: {value}")
for descriptor in char.descriptors:
desc_value = None
try:
desc_value = bytes(
await self.client.read_gatt_descriptor(char.handle)
)
except Exception as error:
desc_value = error
logging.info(
f" - Descriptor Description: {descriptor.description}"
)
logging.info(f" UUID: {descriptor.uuid}")
logging.info(f" Handle: {descriptor.handle}")
logging.info(f" Value: {desc_value}")
@property
def name(self) -> str | None:
if self.found_dm:
return self.device.name
return ""
@property
def address(self) -> str | None:
if self.found_dm:
return self.device.address
return ""
@property
def is_connected(self) -> bool:
if self.found_dm:
return self.client.is_connected
else:
return False
async def aio_play_seq(self, seq) -> None:
logging.info("Play thread started")
await self.aio_send_brightness(self.app.param_frame.brightness_var.get())
await self.aio_send_seq(seq)
await asyncio.sleep(seq.duration)
def play_dmled(self, position: float):
if position == 0.0: # send original sequence
asyncio.run_coroutine_threadsafe(
self.aio_play_seq(self.app.sequence), self.ble_loop
)
else: # we create a new seq that start from position
cur_step, pos, osc_values = dmutil.step_pos_values_at_time(
position, self.app.sequence
)
actual_step = self.app.sequence.steps[cur_step]
oscillators = []
for osc_idx, osc in enumerate(actual_step.oscillators):
osc.f_start = osc_values[osc_idx][0]
osc.f_end = actual_step.oscillators[osc_idx].f_end
osc.b_start = osc_values[osc_idx][1]
osc.b_end = actual_step.oscillators[osc_idx].b_end
osc.d_start = osc_values[osc_idx][2]
osc.d_end = actual_step.oscillators[osc_idx].d_end
osc.leds = actual_step.oscillators[osc_idx].leds
oscillators.append(osc)
duration = actual_step.t_end - actual_step.t_start - pos
# logging.info(f"{cur_step=} {pos=} {duration=}")
new_step = seq.Step(actual_step.index, 0, duration, oscillators)
# logging.info(new_step)
# create a sequence starting with new_step
new_seq = seq.Sequence("temp_seq", None, 0, [new_step])
# now add the following steps
last_time = duration
if cur_step != len(self.app.sequence.steps) - 1:
for step_idx, step in enumerate(
self.app.sequence.steps[cur_step + 1 :]
):
new_seq.steps.insert(step_idx + 1, copy.deepcopy(step))
duration = step.t_end - step.t_start
new_seq.steps[-1].t_start = last_time
new_seq.steps[-1].t_end = last_time + duration
new_seq.steps[-1].index = step.index
new_seq.steps[-1].oscillators = step.oscillators
last_time = new_seq.steps[-1].t_end
new_seq.duration = new_seq.steps[-1].t_end
# logging.info(new_seq)
asyncio.run_coroutine_threadsafe(self.aio_play_seq(new_seq), self.ble_loop)
def stop_dmled(self):
asyncio.run_coroutine_threadsafe(self.aio_stop_seq(), self.ble_loop)
####################### BELOW TEST ###############################
####################### BELOW TEST ###############################
####################### BELOW TEST ###############################
class App(tk.Tk):
"""Test program: scan for dm, connect/disconnect, send sequence"""
def __init__(self) -> None:
super().__init__()
self.ble = Ble(self)
self.loop = self.ble.ble_loop
self.title("Test BLE")
self.protocol("WM_DELETE_WINDOW", self._quit)
logging.basicConfig(
level=20,
format="{asctime} - {module} {levelname} - {message}",
style="{",
# datefmt="%Y-%m-%d %H:%M:%S",
)
tk.Button(self, text="Scan DM", width=15, command=self.scan_for_dm).grid(
row=0, column=0, padx=5, sticky="w"
)
self.tb_dm_name = tk.Label(
self,
width=30,
justify="left",
bg="silver",
text="Click scan ...",
anchor="w",
)
self.tb_dm_name.grid(row=0, column=1, sticky="w")
self.bt_connect = tk.Button(
self, text="Connect", width=15, command=self.connect_disconnect
)
self.bt_connect.grid(row=1, column=0, padx=5, sticky="w")
self.tb_dm_status = tk.Label(
self, width=30, text="Disconnected", justify="left", anchor="w", bg="silver"
)
self.tb_dm_status.grid(row=1, column=1, sticky="w")
scan_button = tk.Button(self, text="Test DM", width=15, command=self.start_test)
scan_button.grid(row=2, column=0, columnspan=2, padx=5, sticky="w")
def _quit(self) -> None:
self.quit()
self.destroy()
def scan_for_dm(self):
# Submit the scan task to the asyncio loop and set up a callback
future = asyncio.run_coroutine_threadsafe(self.ble.aio_scan_for_dm(), self.loop)
future.add_done_callback(lambda f: self.update_dm_name())
def connect_disconnect(self):
if not self.ble.is_connected:
self.tb_dm_status.configure(text=f"Connecting...")
future = asyncio.run_coroutine_threadsafe(self.ble.aio_connect(), self.loop)
else:
self.tb_dm_status.configure(text=f"Disonnecting...")
future = asyncio.run_coroutine_threadsafe(
self.ble.aio_disconnect(), self.loop
)
future.add_done_callback(lambda f: self.update_dm_status())
future.add_done_callback(lambda f: self.update_dm_name())
def start_test(self):
logging.info("calling test_dm in a thread")
asyncio.run_coroutine_threadsafe(self.test_dm(), self.loop)
def update_dm_name(self):
# Update the text with detected devices
if self.ble.found_dm:
self.tb_dm_name.configure(
text=f"{self.ble.name} ({self.ble.address})",
justify="left",
)
else:
self.tb_dm_name.configure(text="No DM found", justify="left")
def update_dm_status(self):
# Update the text with connection status
if self.ble.is_connected:
self.tb_dm_status.configure(text=f"Connected")
self.bt_connect.configure(text="Disconnect")
else:
self.tb_dm_status.configure(text=f"Disconnected")
self.bt_connect.configure(text="Connect", justify="left")
async def test_dm(self) -> None:
osc1 = seq.Oscillator(["A1", "A4", "B1"], 9, 10, 50, 50, 80, 10)
osc2 = seq.Oscillator(["A1", "A5", "B2"], 8, 9, 30, 30, 10, 80)
step1 = seq.Step(0, 0, 10, [osc1, osc2])
step2 = seq.Step(0, 0, 5, [osc2, osc1])
if not self.ble.is_connected:
await self.ble.aio_connect()
await self.ble.aio_send_brightness(50)
await self.ble.aio_send_step(step1)
await asyncio.sleep(5)
logging.info("changing brightness at middle of step")
await self.ble.aio_send_brightness(20)
await asyncio.sleep(5)
logging.info("second step")
await self.ble.aio_send_brightness(50)
await self.ble.aio_send_step(step2)
# create seq
logging.info("Creating and sending sequence")
new_seq = seq.Sequence("Test", None, 15, [step1, step2])
await self.ble.aio_send_seq(new_seq)
if __name__ == "__main__":
app = App() # build initial display
app.mainloop() # process tkinter events
чтобы воспроизвести ошибку, используйте
pyinstaller ble.py
сгенерированный запуск программы
здесь находится начало файла журнала, создаваемого при запуске
2024-10-25 14:10:31,659 - ble INFO - Scanning Bluetooth Low Energy for devices ...
2024-10-25 14:10:32,744 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:32,746 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,026 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,030 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,990 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:33,993 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
2024-10-25 14:10:34,307 - base_events ERROR - Exception in callback BleakScannerWinRT._received_handler(, )
handle:
Traceback (most recent call last):
File "asyncio\events.py", line 88, in _run
File "bleak\backends\winrt\scanner.py", line 147, in _received_handler
ModuleNotFoundError: No module named 'winrt.windows.foundation.collections'
Подробнее здесь: [url]https://stackoverflow.com/questions/79117864/modulenotfounderror-no-module-named-winrt-windows-foundation-collections[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия