Python+BleakClient:如何将BLE传感器温湿度压力值传递至主程序用于绘图
解决BLE客户端异步读取传感器数据的传递问题
核心问题分析
你遇到的本质是异步函数间的状态共享问题:如果用不可变类型(如int/float)做全局变量,在get_THP里修改其实是创建了局部变量,主程序看不到;如果get_THP是异步函数但没通过await调用,返回的是协程对象而非实际值。
可行解决方案
方案1:使用共享可变对象(字典/列表)
因为字典、列表是可变类型,异步函数里修改它们的内部元素会直接反映到主程序中,单线程异步环境下无需额外同步机制。
示例代码:
import asyncio from bleak import BleakClient # 定义共享字典存储传感器时序数据 sensor_data = { "temperature": [], "humidity": [], "pressure": [] } async def get_THP(client, characteristic_uuid): # 从ESP32读取特征原始数据 raw_data = await client.read_gatt_char(characteristic_uuid) # 解析数据(需根据你的ESP32端协议调整解析逻辑) temp = float(raw_data[0:4].hex()) / 100 humi = float(raw_data[4:8].hex()) / 100 press = float(raw_data[8:12].hex()) / 10 # 将数据存入共享字典的列表 sensor_data["temperature"].append(temp) sensor_data["humidity"].append(humi) sensor_data["pressure"].append(press) async def main(): device_address = "你的ESP32蓝牙地址" char_uuid = "传感器数据特征UUID" async with BleakClient(device_address) as client: print("已连接到ESP32") # 循环读取数据(模拟时序采集) for _ in range(10): await get_THP(client, char_uuid) await asyncio.sleep(1) # 实时查看已采集的数据 print(f"已采集温度值: {sensor_data['temperature']}") # 后续直接用sensor_data中的数组做时序绘图 print("所有采集数据:") print(sensor_data) if __name__ == "__main__": asyncio.run(main())
方案2:使用asyncio.Queue做数据传递
如果需要分离数据读取和绘图逻辑,用asyncio.Queue实现生产者-消费者模式更规范,适合复杂异步场景。
示例代码:
import asyncio from bleak import BleakClient async def get_THP(client, characteristic_uuid, data_queue): while True: raw_data = await client.read_gatt_char(characteristic_uuid) # 解析数据 temp = float(raw_data[0:4].hex()) / 100 humi = float(raw_data[4:8].hex()) / 100 press = float(raw_data[8:12].hex()) / 10 # 将数据放入队列 await data_queue.put({ "temp": temp, "humi": humi, "press": press }) await asyncio.sleep(1) async def data_collector(data_queue, sample_count): # 收集指定数量的时序数据 collected_data = { "temperature": [], "humidity": [], "pressure": [] } for _ in range(sample_count): data = await data_queue.get() collected_data["temperature"].append(data["temp"]) collected_data["humidity"].append(data["humi"]) collected_data["pressure"].append(data["press"]) data_queue.task_done() return collected_data async def main(): device_address = "你的ESP32蓝牙地址" char_uuid = "传感器数据特征UUID" sample_count = 10 data_queue = asyncio.Queue(maxsize=sample_count) async with BleakClient(device_address) as client: print("已连接到ESP32") # 启动数据读取任务 read_task = asyncio.create_task(get_THP(client, char_uuid, data_queue)) # 同步收集数据 collected_data = await data_collector(data_queue, sample_count) # 终止读取任务 read_task.cancel() try: await read_task except asyncio.CancelledError: print("数据读取任务已终止") # 用collected_data做时序绘图 print("最终采集数据:") print(collected_data) if __name__ == "__main__": asyncio.run(main())
常见错误排查
- 未await异步函数:如果调用
get_THP时没加await,返回的是协程对象而非实际数据,必须用await get_THP(...)获取结果。 - 使用不可变全局变量:比如定义
temp = 0后在get_THP里重新赋值,会创建局部变量,主程序看不到变化——必须用字典、列表这类可变对象存储数据。
内容的提问来源于stack exchange,提问作者waszee
相关产品推荐
相关产品推荐

