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

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())

常见错误排查

  1. 未await异步函数:如果调用get_THP时没加await,返回的是协程对象而非实际数据,必须用await get_THP(...)获取结果。
  2. 使用不可变全局变量:比如定义temp = 0后在get_THP里重新赋值,会创建局部变量,主程序看不到变化——必须用字典、列表这类可变对象存储数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:52:58