You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows 11与树莓派4上Python蓝牙脚本运行差异问题求助

问题:Python BLE扫描脚本在Windows与树莓派上表现不一致

问题背景

  • 脚本基于Victron Energy硬件的CLI脚本修改,用于读取蓝牙设备数据并写入文件
  • 原脚本使用loop.run_forever()时,Windows 11(VS运行)和树莓派4均能正常工作
  • 修改为5秒限时运行后,Windows正常读取并写入文件,但树莓派无报错却无法读取数据
  • 修改的代码段:
the_end = time.time() + 5
while time.time() < the_end:
    loop.stop()
    loop.run_forever()

原因分析

  1. 异步事件循环使用错误:频繁调用loop.stop()和loop.run_forever()不符合asyncio的规范逻辑,不同平台的asyncio实现(Windows用SelectorEventLoop,树莓派默认实现存在差异)对这种异常操作的兼容性不同
  2. 同步阻塞影响:Scanner的callback中使用time.sleep(3)是同步阻塞,会卡住事件循环,导致BLE扫描任务无法正常执行;树莓派的BLE扫描初始化速度慢于Windows,更容易被这种阻塞打断
  3. 循环启停的不确定性:loop.stop()会立即终止事件循环,而run_forever()重启循环的间隔极短,可能导致BLE扫描任务还未完成初始化或接收数据就被终止

解决方案

修改1:正确实现异步限时运行

将my_scan函数改为使用asyncio.sleep()实现5秒运行时长,通过run_until_complete管理事件循环生命周期:

def my_scan(device_keys: List[Tuple[str, str]]):
    loop = asyncio.get_event_loop()

    async def scan_and_wait(keys):
        scanner = Scanner(keys)
        await scanner.start()
        # 保持扫描运行5秒
        await asyncio.sleep(5)
        await scanner.stop()

    loop.run_until_complete(scan_and_wait({k: v for k, v in device_keys}))

修改2:移除同步阻塞,改用异步延迟

将Scanner的callback中的同步time.sleep(3)替换为异步实现,避免阻塞事件循环:

class Scanner(BaseScanner):
    # ... 保留原有代码 ...

    def callback(self, ble_device: BLEDevice, raw_data: bytes):
        logger.debug(
            f"Received data from {ble_device.address.lower()}: {raw_data.hex()}"
        )
        try:
            device = self.get_device(ble_device, raw_data)
        except AdvertisementKeyMissingError:
            return
        except UnknownDeviceError as e:
            logger.error(e)
            return
        parsed = device.parse(raw_data)

        blob = {
            "name": ble_device.name,
            "address": ble_device.address,
            "rssi": ble_device.rssi,
            "payload": parsed,
        }
        ve_string = json.dumps(blob, cls=DeviceDataEncoder, indent=1)
        print(ve_string)

        # 使用with语句自动管理文件关闭
        with open("this_device.txt", "w") as this_file:
            this_file.write(ve_string)

        print("file written")
        # 启动异步延迟任务,不阻塞事件循环
        asyncio.create_task(self.delay_after_write())

    async def delay_after_write(self):
        await asyncio.sleep(3)

说明

  • 这种方式保证事件循环在5秒内持续运行,BLE扫描可以正常接收设备数据
  • 异步延迟替代同步阻塞,避免打断事件循环的正常调度
  • 统一的事件循环管理逻辑在Windows和树莓派上表现一致

内容的提问来源于stack exchange,提问作者IronDad75

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:59:52