work: Отладил переподключение к Tion. Раньше при разрыве соединения в библиотеке btle соединение зависало. Сейчас при сбросе устройства явно вызывается disconnect библиотеки, чтобы сессия Bluetooth освобождалась.
This commit is contained in:
+74
-18
@@ -1,6 +1,6 @@
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from bleak import BleakScanner
|
||||
from tion_btle import TionS4
|
||||
|
||||
from .models import TionState
|
||||
@@ -18,7 +18,7 @@ class TionController:
|
||||
|
||||
def __init__(self, mac: str):
|
||||
self._mac = mac
|
||||
self._device = TionS4(mac)
|
||||
self._device: TionS4 | None = None
|
||||
|
||||
# Не позволяем двум частям программы одновременно работать с BLE.
|
||||
self._lock = asyncio.Lock()
|
||||
@@ -35,27 +35,88 @@ class TionController:
|
||||
|
||||
@property
|
||||
def connected(self) -> bool:
|
||||
return self._device.connection_status == "connected"
|
||||
return (
|
||||
self._device is not None
|
||||
and self._device.connection_status == "connected"
|
||||
)
|
||||
|
||||
@property
|
||||
def state(self) -> TionState | None:
|
||||
async def _reset_device(self) -> None:
|
||||
"""
|
||||
Последнее известное состояние без обращения к Bluetooth.
|
||||
Полностью уничтожить текущий BLE transport.
|
||||
|
||||
Важно:
|
||||
tion-btle не вызывает BleakClient.disconnect(),
|
||||
если WinRT уже считает устройство disconnected.
|
||||
|
||||
Поэтому при полном reset принудительно закрываем
|
||||
BleakClient напрямую.
|
||||
"""
|
||||
return self._state
|
||||
|
||||
old_device = self._device
|
||||
|
||||
# Controller сразу больше не считает старый объект рабочим.
|
||||
self._device = None
|
||||
self._started = False
|
||||
|
||||
if old_device is None:
|
||||
return
|
||||
|
||||
try:
|
||||
# Нам нужен именно настоящий BleakClient.disconnect().
|
||||
#
|
||||
# Не old_device.disconnect(), потому что tion-btle
|
||||
# может пропустить физический cleanup при
|
||||
# connection_status == "disc".
|
||||
await old_device._btle.disconnect()
|
||||
|
||||
except Exception:
|
||||
# Старый transport всё равно больше использоваться
|
||||
# не будет.
|
||||
pass
|
||||
|
||||
"""
|
||||
Соединение
|
||||
"""
|
||||
|
||||
async def connect(self) -> None:
|
||||
"""
|
||||
Открыть постоянное BLE-соединение.
|
||||
"""
|
||||
async with self._lock:
|
||||
if self._started:
|
||||
if self.connected:
|
||||
self._started = True
|
||||
return
|
||||
|
||||
await self._device.connect()
|
||||
# Полностью закрываем всё, что осталось
|
||||
# от предыдущего соединения.
|
||||
await self._reset_device()
|
||||
|
||||
# Получаем свежий BLEDevice.
|
||||
ble_device = await BleakScanner.find_device_by_address(
|
||||
self._mac,
|
||||
timeout=5.0,
|
||||
)
|
||||
|
||||
if ble_device is None:
|
||||
raise ConnectionError(
|
||||
f"Tion {self._mac} not found"
|
||||
)
|
||||
|
||||
# Новый TionS4 = новый BleakClient.
|
||||
device = TionS4(ble_device)
|
||||
|
||||
try:
|
||||
await device.connect()
|
||||
|
||||
except Exception:
|
||||
# ВАЖНО:
|
||||
# освобождаем даже частично созданную
|
||||
# WinRT/GATT-сессию.
|
||||
try:
|
||||
await device._btle.disconnect()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
raise
|
||||
|
||||
self._device = device
|
||||
self._started = True
|
||||
|
||||
async def disconnect(self) -> None:
|
||||
@@ -63,13 +124,8 @@ class TionController:
|
||||
Закрыть BLE-соединение.
|
||||
"""
|
||||
async with self._lock:
|
||||
if not self._started:
|
||||
return
|
||||
await self._reset_device()
|
||||
|
||||
try:
|
||||
await self._device.disconnect()
|
||||
finally:
|
||||
self._started = False
|
||||
|
||||
"""
|
||||
Состояние
|
||||
|
||||
Reference in New Issue
Block a user