当函数返回时,BleakScanner 与 asyncio.wait_for 超时

问题描述 投票:0回答:1
  • 黯淡版本:0.22.2
  • Python版本:3.8.18
  • 操作系统:Linux
  • Linux 下的 BlueZ 版本 (
    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

“正在连接”日志发生在函数返回之前。

python bluetooth-lowenergy python-asyncio python-bleak
1个回答
0
投票

我也在 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
© www.soinside.com 2019 - 2024. All rights reserved.