bluetoothctl -v
):5.64我有一个超时的 BleakScanner。从
asyncio.wait_for
函数返回后(函数返回后20s)仍然出现超时。然后,任何进一步的扫描都会被以下 DBus 错误阻止
我有一个网关以循环方式不断连接到 4 个相同类型的设备。
我运行了以下代码并从
asyncio.TimeoutError
获取日志,即使 asyncio.wait_for(_scan_with_timeout(filter, device_id), timeout)
应该已返回
async def scan(
device_id, timeout=SCAN_TIMEOUT_S
) -> Optional[Tuple[BLEDevice, Set[str]]]:
try:
filter = get_device_filter(device_id)
return await asyncio.wait_for(_scan_with_timeout(filter, device_id), timeout)
except asyncio.TimeoutError:
logger.info(
f"Timeout reached. Device {device_id} not found after {timeout} seconds"
)
return None
async def _scan_with_timeout(filter, device_id):
seen = set()
async with BleakScanner() as scanner:
async for device, advertisement in scanner.advertisement_data():
found_device_id = get_device_id(device)
if found_device_id and found_device_id.startswith(filter):
logger.info(f"Found {device!r}")
logger.debug(f"{advertisement!r}")
logger.debug(f"platform_data: {advertisement.platform_data}")
logger.debug(f"service_data: {advertisement.service_data}")
seen.add(found_device_id)
if found_device_id == device_id:
logger.info(f"Connecting")
return (device, seen)
这些是我拥有的日志,我还没有任何更深入的日志。
2024-08-13 15:25:10,187 | INFO | xtel | Found BLEDevice(D0:83:D4:00:A2:61, XAIRQ-00A261)
2024-08-13 15:25:10,385 | INFO | xtel | Found BLEDevice(D0:83:D4:00:A2:97, XAIRQ-00A297)
2024-08-13 15:25:10,426 | INFO | xtel | Found BLEDevice(D0:83:D4:00:A2:D1, XAIRQ-00A2D1)
2024-08-13 15:25:10,427 | INFO | xtel | Connecting
2024-08-13 15:25:30,122 | INFO | xtel | Timeout reached. Device D0:83:D4:00:A2:D1 not found after 30 seconds
2024-08-13 15:25:30,123 | INFO | xtel | Rendezvous failed
2024-08-13 15:25:30,124 | INFO | gateway | Device D0:83:D4:00:A2:D1 data collection: None.
2024-08-13 15:25:30,124 | INFO | gateway | Device D0:83:D4:00:A2:D1 status: DeviceStatus(t_slot_index=1, is_configured=True, is_defective=False, last_connect=1723562100.0084567, retry_count=1).
2024-08-13 15:25:30,125 | INFO | gateway | Time to sensor connect: 119.87453603744507
2024-08-13 15:27:30,098 | INFO | gateway | Time slots: ['D0:83:D4:00:A2:6A', 'D0:83:D4:00:A2:D1', 'D0:83:D4:00:A2:82', 'D0:83:D4:00:5E:9A']
2024-08-13 15:27:30,100 | INFO | xtel | Reconnecting to device to fetch data
2024-08-13 15:27:30,101 | INFO | xtel | Rendezvous - waiting for data...
2024-08-13 15:27:30,101 | INFO | xtel | Scanning for D0:83:D4:00:A2:82...
2024-08-13 15:27:30,107 | ERROR | xtel | Rendezvous connect failed because: BleakDBusError('org.bluez.Error.InProgress', 'Operation already in progress')
2024-08-13 15:27:30,108 | INFO | xtel | Rendezvous failed
2024-08-13 15:27:30,109 | INFO | gateway | Device D0:83:D4:00:A2:82 data collection: None.
2024-08-13 15:27:30,109 | INFO | gateway | Device D0:83:D4:00:A2:82 status: DeviceStatus(t_slot_index=2, is_configured=True, is_defective=False, last_connect=1723562250.0088952, retry_count=1).
2024-08-13 15:27:30,111 | INFO | gateway | Time to sensor connect: 149.88888812065125
这两行是问题所在:
2024-08-13 15:25:10,427 | INFO | xtel | Connecting
2024-08-13 15:25:30,122 | INFO | xtel | Timeout reached. Device D0:83:D4:00:A2:D1 not found after 30 seconds
“正在连接”日志发生在函数返回之前。
我也在 Bleak GitHub 存储库讨论#1629中问了这个问题。
答案是:
asyncio.wait_for() 不会等待取消的任务完成。使用 asyncio.timeout() 可能会有更好的运气。否则,您将需要使用 asyncio.Lock() 来保护扫描仪以防止并发扫描。
需要升级到 Python 3.11 并使用
asyncio.timeout
。我还确保 _scan_with_timeout
返回 None
async def scan(
device_id, timeout=SCAN_TIMEOUT_S
) -> Optional[Tuple[BLEDevice, Set[str]]]:
try:
filter = get_device_filter(device_id)
# Enforce a scanning timeout
async with asyncio.timeout(timeout):
return await _scan_with_timeout(filter, device_id)
except asyncio.TimeoutError:
logger.info(
f"Timeout reached. Device {device_id} not found after {timeout} seconds"
)
return None
async def _scan_with_timeout(filter, device_id):
seen = set()
async with BleakScanner() as scanner:
async for device, advertisement in scanner.advertisement_data():
found_device_id = get_device_id(device)
if found_device_id and found_device_id.startswith(filter):
logger.info(f"Found {device!r}")
logger.debug(f"{advertisement!r}")
logger.debug(f"platform_data: {advertisement.platform_data}")
logger.debug(f"service_data: {advertisement.service_data}")
seen.add(found_device_id)
if found_device_id == device_id:
logger.info(f"Found desired {device!r}")
return (device, seen)
return None