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()
原因分析
- 异步事件循环使用错误:频繁调用
loop.stop()和loop.run_forever()不符合asyncio的规范逻辑,不同平台的asyncio实现(Windows用SelectorEventLoop,树莓派默认实现存在差异)对这种异常操作的兼容性不同 - 同步阻塞影响:Scanner的
callback中使用time.sleep(3)是同步阻塞,会卡住事件循环,导致BLE扫描任务无法正常执行;树莓派的BLE扫描初始化速度慢于Windows,更容易被这种阻塞打断 - 循环启停的不确定性:
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
相关产品推荐
相关产品推荐

