Wrap `bluetooth.connect` in a per-device locked section.

This commit is contained in:
Fabio Manganiello 2023-02-19 23:11:19 +01:00
parent 9112239ac3
commit 73bf2446bd
Signed by: blacklight
GPG Key ID: D90FBA7F76362774
1 changed files with 14 additions and 10 deletions

View File

@ -1,5 +1,5 @@
import base64 import base64
from asyncio import Event, ensure_future from asyncio import Event, Lock, ensure_future
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from threading import RLock, Timer from threading import RLock, Timer
from time import time from time import time
@ -127,6 +127,7 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
self._scan_enabled = Event() self._scan_enabled = Event()
self._scan_controller_timer: Optional[Timer] = None self._scan_controller_timer: Optional[Timer] = None
self._connections: Dict[str, BleakClient] = {} self._connections: Dict[str, BleakClient] = {}
self._connection_locks: Dict[str, Lock] = {}
self._devices: Dict[str, BLEDevice] = {} self._devices: Dict[str, BLEDevice] = {}
self._device_last_updated_at: Dict[str, float] = {} self._device_last_updated_at: Dict[str, float] = {}
self._device_name_by_addr = device_names or {} self._device_name_by_addr = device_names or {}
@ -255,7 +256,6 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
or old_props.get('TxPower') != new_props.get('TxPower') or old_props.get('TxPower') != new_props.get('TxPower')
): ):
event_types.append(BluetoothDeviceSignalUpdateEvent) event_types.append(BluetoothDeviceSignalUpdateEvent)
else: else:
event_types.append(BluetoothDeviceFoundEvent) event_types.append(BluetoothDeviceFoundEvent)
@ -278,14 +278,18 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
timeout: Optional[float] = None, timeout: Optional[float] = None,
) -> AsyncGenerator[BleakClient, None]: ) -> AsyncGenerator[BleakClient, None]:
dev = await self._get_device(device) dev = await self._get_device(device)
async with BleakClient(
dev.address, async with self._connection_locks.get(dev.address, Lock()) as lock:
adapter=interface or self._interface, self._connection_locks[dev.address] = lock or Lock()
timeout=timeout or self._connect_timeout,
) as client: async with BleakClient(
self._connections[dev.address] = client dev.address,
yield client adapter=interface or self._interface,
self._connections.pop(dev.address) timeout=timeout or self._connect_timeout,
) as client:
self._connections[dev.address] = client
yield client
self._connections.pop(dev.address, None)
async def _read( async def _read(
self, self,