组件实战指南:从特征结构到源码实现)
esp-iot-solution 中的 BLE 体重秤服务WSS组件实战指南从特征结构到源码实现【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution导读本指南以 esp-iot-solution 仓库中 体重秤服务文档 为主体系统讲解基于 GATT 的 Weight Scale ServiceWSS体重秤服务在 ESP32 系列芯片上的组件化实现。文章将带你掌握 WSS 的 Service/Characteristic 结构、Weight Feature 与 Weight Measurement 两个特征的数据编码方式、esp_ble_wss_*API 的用法并结合 组件源码 与 官方示例最终能够基于 esp-iot-solution 的蓝牙连接管理框架ble_conn_mgr快速搭建一个可被手机 App 读取的蓝牙体重秤 GATT Server。一、WSS 是什么面向健康与健身场景的 BLE 标准服务Weight Scale ServiceWSS是蓝牙 SIG 定义的标准 GATT 服务用于从健康和体育健身类体重秤中获取体重相关数据。它属于 GATT 服务器端Peripheral需要实现的服务客户端Central如手机健康 App通过特征读写来订阅和读取体重测量结果。WSS 属于 esp-iot-solution 中 BLE 标准服务集合ble_services的一部分与 ANS、BAS、CTS、DIS、HRS、HTS、IAS、MIDI、OTA、OTS、TPS、UDS 等服务并列采用统一的连接管理框架esp_ble_conn_mgr实现而非直接操作 NimBLE/Bluedroid 底层 API。1.1 服务与特征 UUID从 esp_wss.h 可以看到本组件定义的核心 UUID名称UUID类型Weight Scale Service0x181D16 位服务 UUIDWeight Measurement0x2A9D16 位特征 UUIDWeight Feature0x2A9E16 位特征 UUIDWeight Feature0x2A9E只读READ特征向客户端描述体重秤支持哪些能力时间戳、多用户、BMI、体重/身高及其分辨率Weight Measurement0x2A9D指示INDICATE特征体重秤测量完成后将体重数据可含时间戳、用户索引、BMI、身高打包后主动通知已订阅的客户端。二、Weight Feature 特征能力位与分辨率编码Weight Feature 用一个 32 位字段声明体重秤的能力。组件在 esp_wss.h 中将其建模为esp_ble_wss_feature_t位域结构体typedef struct { uint32_t timestamp: 1; /*! 0: Dont Support, 1: Support */ uint32_t user_id: 1; /*! 0: Dont Support, 1: Support */ uint32_t bmi: 1; /*! 0: Dont Support, 1: Support */ uint32_t weight: 1; /*! 0: Dont Support, 1: Support */ uint32_t w_resolution: 3; /*! If weight support, this filed should present */ uint32_t height: 1; /*! 0: Dont Support, 1: Support */ uint32_t h_resolution: 2; /*! If height support, this filed should present */ } esp_ble_wss_feature_t;各字段含义如下位域位数含义timestamp1是否支持时间戳user_id1是否支持多用户索引bmi1是否支持 BMIweight1是否支持体重w_resolution3体重分辨率编码见下文height1是否支持身高h_resolution2身高分辨率编码见下文2.1 体重分辨率编码w_resolution依据 esp_wss.h 的枚举体重分辨率按如下编码宏定义值分辨率BLE_WSS_WEIGHT_RESOLUTION_NONE0x0无BLE_WSS_WEIGHT_RESOLUTION_0P5_KG0x10.5 kgBLE_WSS_WEIGHT_RESOLUTION_0P2_KG0x20.2 kgBLE_WSS_WEIGHT_RESOLUTION_0P1_KG0x30.1 kgBLE_WSS_WEIGHT_RESOLUTION_0P05_KG0x40.05 kgBLE_WSS_WEIGHT_RESOLUTION_0P02_KG0x50.02 kgBLE_WSS_WEIGHT_RESOLUTION_0P01_KG0x60.01 kgBLE_WSS_WEIGHT_RESOLUTION_0P005_KG0x70.005 kg2.2 身高分辨率编码h_resolution身高分辨率编码定义在 esp_wss.h宏定义值分辨率BLE_WSS_HEIGHT_RESOLUTION_NONE0x0无BLE_WSS_HEIGHT_RESOLUTION_0P01_M0x10.01 mBLE_WSS_HEIGHT_RESOLUTION_0P005_M0x20.005 mBLE_WSS_HEIGHT_RESOLUTION_0P001_M0x30.001 m组件默认的 Feature 值在 esp_wss.c 中给出默认全部能力开启、w_resolution 10.5 kg、h_resolution 10.01 mstatic esp_ble_wss_feature_t s_wss_feature { .timestamp 1, .user_id 1, .bmi 1, .weight 1, .w_resolution 1, .height 1, .h_resolution 1 };三、Weight Measurement 特征测量数据模型与 Flag 位Weight Measurement 是 WSS 的核心数据特征。组件在 esp_wss.h 中定义了完整的测量数据结构esp_ble_wss_measurement_ttypedef struct { struct { uint32_t measurement_unit: 1; /*! 0: Kg meter, 1: reference to weight and height resolution */ uint32_t time_present: 1; /*! 0: Dont contain time information, 1: time stamp present */ uint32_t user_present: 1; /*! 0: Dont contain user index, 1: contain user index */ uint32_t bmi_height_present: 1; /*! 0: Dont contain BMI and height, 1: contain BMI and height */ } flag; /*! Flag */ uint16_t weight; /*! weight */ struct { uint16_t year; /*! Valid range 1582 to 9999 */ uint8_t month; /*! Valid range 1 to 12 */ uint8_t day; /*! Valid range 1 to 31 */ uint8_t hours; /*! Valid range 0 to 23 */ uint8_t minutes; /*! Valid range 0 to 59 */ uint8_t seconds; /*! Valid range 0 to 59 */ } __attribute__((packed)) timestamp; /*! The date and time */ uint8_t user_id; /*! User index */ uint8_t bmi; /*! BMI */ uint16_t height; /*! Height */ uint8_t weight_resolution; /*! Weight resolution */ uint8_t height_resolution; /*! Height resolution */ } __attribute__((packed)) esp_ble_wss_measurement_t;3.1 Flag 位语义结构体头部是 4 个标志位对应 esp_wss.h 中的宏BLE_WSS_MEASUREMENT_UINTS_FLAGbit 0measurement_unit单位指示。0 表示体重单位为 kg、身高单位为米1 表示参照 Weight Feature 中声明的分辨率字段解析BLE_WSS_TIME_STAMP_FLAGbit 1time_present测量数据中是否携带时间戳BLE_WSS_USER_ID_FLAGbit 2user_present测量数据中是否携带用户索引BLE_WSS_BMI_FLAGbit 3bmi_height_present测量数据中是否携带 BMI 与身高。3.2 字段取值约束时间戳遵循公历年 1582–9999月 1–12日 1–31时 0–23分 0–59秒 0–59user_id为体重秤本地维护的用户编号配合多用户功能区分家庭成员bmi为 BMI 值示例中0x18即 24表示 24.0 kg/m² 一类按协议缩放后的整数height为身高值按 Weight Feature 中声明的身高分辨率缩放。3.3 特征属性与指示INDICATE在 esp_wss.c 的特征查找表中可以看到两个特征的注册属性static const esp_ble_conn_character_t nu_lookup_table[] { { weight feature, BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_READ, { BLE_WSS_CHR_UUID16_WEIGHT_FEATURE }, wss_feature_cb }, { weight measurement, BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_INDICATE, { BLE_WSS_CHR_UUID16_WEIGHT_MEASUREMENT }, NULL }, };Weight Feature 使用READ属性读请求由回调wss_feature_cb即时应答Weight Measurement 使用INDICATE属性客户端必须先通过 CCCD 使能指示订阅服务器才能发送数据INDICATE 带有应用层确认比 NOTIFY 更可靠适合体重这类不允许丢包的测量数据。四、API 使用指南初始化、读写测量值WSS 组件对外只暴露 3 个 API均声明在 esp_wss.h 中4.1esp_ble_wss_init()— 注册服务esp_err_t esp_ble_wss_init(void);将 WSS 服务0x181D及其两个特征注册到 ble_conn_mgr 的 GATT 服务表中。其实现非常简洁esp_wss.cesp_err_t esp_ble_wss_init(void) { return esp_ble_conn_add_svc(svc); }svc是一个静态的esp_ble_conn_svc_t描述符esp_wss.c声明了 16 位服务 UUID、特征数量nu_lookup_count和特征查找表nu_lookup。返回ESP_OK表示成功ESP_ERR_INVALID_ARG/ESP_FAIL表示初始化参数错误或失败。4.2esp_ble_wss_get_measurement()— 读取最近一次测量值esp_err_t esp_ble_wss_get_measurement(esp_ble_wss_measurement_t *out_val);将组件内部缓存的最近一次测量值拷贝到调用者提供的结构体中。out_val为NULL时返回ESP_ERR_INVALID_ARG见 esp_wss.c。该 API 适合在断连恢复、或应用需要重发最近测量数据时使用。4.3esp_ble_wss_set_measurement()— 写入测量值并可选主动上报esp_err_t esp_ble_wss_set_measurement(esp_ble_wss_measurement_t *in_val, bool need_send);这是应用调用最频繁的 API校验in_val非空将测量值拷贝到内部缓存s_wss_measurement根据测量数据的 flag 自动更新 Weight Featureesp_wss.c先清零 Feature再按本次测量携带的字段重建能力位——携带时间戳则置timestamp携带用户索引则置user_id携带 BMI/身高则置bmi与height若measurement_unit 1则将本次的weight_resolution/height_resolution写入 Feature将测量值按协议格式打包build_wss_ind_buf若need_send true通过esp_ble_conn_write()以 INDICATE 方式发送 Weight Measurement 特征UUID0x2A9D给远端客户端。返回ESP_OK成功in_val NULL返回ESP_ERR_INVALID_ARG底层发送失败返回ESP_FAIL。五、源码深析测量数据如何打包成协议字节流理解 build_wss_ind_buf 的实现就掌握了 WSS 在空中的实际字节布局。打包顺序如下Flag4 字节将in_val-flag整体sizeof(uint32_t)拷贝到缓冲区头部Weight2 字节追加uint16_t体重值时间戳7 字节若flag.time_present 1追加year(2) month(1) day(1) hours(1) minutes(1) seconds(1)用户索引1 字节若flag.user_present 1追加user_idBMI1 字节身高2 字节若flag.bmi_height_present 1依次追加bmi与height。indicate_buf_t缓冲区上限为BLE_WSS_MAX_VAL_LEN 20字节esp_wss.c。当全部标志位开启时最大负载为4 2 7 1 1 2 17字节仍在 20 字节以内这是组件按最坏情况设计的冗余余量。需要注意源码中体重追加时offset sizeof(uint32_t)第 46 行是为后续字段扩展预留的步进实际体重仍只占 2 字节读者在自行扩展协议时应以实际字段长度为准。六、实战示例在 ESP32 上跑起一个体重秤 GATT Server官方示例位于 examples/bluetooth/ble_services/ble_wss支持 ESP32 / ESP32-C3 / ESP32-C2 / ESP32-S3 / ESP32-H2 等目标芯片。6.1 工程结构main/app_main.c示例主程序初始化 NVS、事件循环、ble_conn_mgr 与 WSS 服务main/Kconfig.projbuild示例配置菜单广播名等sdkconfig.defaults默认开启蓝牙栈与 WSS 的工程配置sdkconfig.ci.nimbleCI 用的 NimBLE 配置。6.2 构建与烧录先设置目标芯片再编译烧录监控idf.py set-target esp32s3 idf.py menuconfig idf.py -p PORT flash monitor退出串口监控按Ctrl-]。在menuconfig中Example Configuration -- Advertisement name修改广播设备名默认BLE_WSSGATT Weight Scale Service位于 BLE Standard Services 菜单使能 WSS 服务默认关闭。6.3 关键配置项ble_wss 的 sdkconfig.defaults 展示了跑通示例所需的最小配置CONFIG_BT_ENABLEDy CONFIG_BT_NIMBLE_ENABLEDy CONFIG_BLE_CONN_MGR_ROLE_PERIPHERALy CONFIG_BLE_WSSyCONFIG_BT_ENABLED/CONFIG_BT_NIMBLE_ENABLED启用蓝牙控制器与 NimBLE 协议栈CONFIG_BLE_CONN_MGR_ROLE_PERIPHERALble_conn_mgr 工作在从机GATT Server角色CONFIG_BLE_WSS对应 WSS 组件的 Kconfig 开关定义见 Kconfig.in。6.4 主程序逻辑拆解app_main.c 的流程是标准的三步走第一步初始化系统与事件循环nvs_flash_init(); // 初始化 NVS处理 NO_FREE_PAGES 情况 esp_event_loop_create_default(); esp_event_handler_register(BLE_CONN_MGR_EVENTS, ESP_EVENT_ANY_ID, app_ble_conn_event_handler, NULL);第二步初始化 ble_conn_mgr 并注册 WSS 服务esp_ble_conn_config_t config { .device_name CONFIG_EXAMPLE_BLE_ADV_NAME, .broadcast_data CONFIG_EXAMPLE_BLE_SUB_ADV }; esp_ble_conn_init(config); app_ble_wss_init(); // 内部调用 esp_ble_wss_init() if (esp_ble_conn_start() ! ESP_OK) { // 启动广播 esp_ble_conn_stop(); esp_ble_conn_deinit(); esp_event_handler_unregister(BLE_CONN_MGR_EVENTS, ESP_EVENT_ANY_ID, app_ble_conn_event_handler); }第三步在连接事件中构造并上报测量数据事件回调app_ble_conn_event_handler收到ESP_BLE_CONN_EVENT_CONNECTED时构造一份带完整字段的测量数据并调用esp_ble_wss_set_measurement(..., true)主动上报esp_ble_wss_measurement_t wss_measurement { .flag.measurement_unit 0x1, .flag.time_present 0x1, .flag.user_present 0x1, .flag.bmi_height_present 0x1, .timestamp.year 2024, .timestamp.month 10, .timestamp.day 1, .timestamp.hours 9, .timestamp.minutes 10, .timestamp.seconds 25, .user_id 1, .bmi 0x18, .height 0x33, }; ... case ESP_BLE_CONN_EVENT_CONNECTED: ESP_LOGI(TAG, ESP_BLE_CONN_EVENT_CONNECTED); esp_ble_wss_set_measurement(wss_measurement, true); break;这段代码演示了典型的体重秤业务模型连接建立 → 立即把缓存的最新测量值作为一次指示发送给客户端在真实产品中set_measurement应由称重完成中断/ADC 采样任务触发。6.5 预期运行输出烧录并连接后串口日志大致如下节选自示例 READMEI (350) BLE_INIT: Bluetooth MAC: 58:cf:79:1e:9e:de I (410) blecm_nimble: BLE Host Task Started I (410) blecm_nimble: No characteristic(0x2a00) found I (420) NimBLE: GAP procedure initiated: stop advertising. I (430) NimBLE: GAP procedure initiated: advertise; I (450) main_task: Returned from app_main()之后用任意 BLE 扫描/调试 App如 nRF Connect、LightBlue连接名为BLE_WSS的设备即可读取Weight Feature0x2A9E观察能力位与分辨率使能Weight Measurement0x2A9D的指示订阅收到连接时上报的那组测量数据。七、架构总结WSS 如何与 ble_conn_mgr 协同从源码结构可以推断WSS 组件并不直接接触 NimBLE 的 GATT 注册接口而是完全依赖 ble_conn_mgr 提供的抽象层组件通过esp_ble_conn_svc_t描述符声明服务 UUID、特征 UUID 与各特征的属性READ / INDICATE和读回调esp_ble_wss_init()调用esp_ble_conn_add_svc()完成 GATT 服务表注册上报数据时esp_ble_wss_set_measurement()调用esp_ble_conn_write()由连接管理器负责底层指示传输应用只需通过BLE_CONN_MGR_EVENTS事件总线监听连接/断开事件见 示例事件处理无需关心 GATT 细节。这种分层设计使得 WSS 与仓库中其他标准服务ANS、BAS、CTS 等保持完全一致的实现范式开发者可以在同一工程中按需组合多个标准服务实现体重秤 电池电量BAS 设备信息DIS等复合应用。八、使用注意事项测量数据重发INDICATE 需要客户端确认若对端未使能 CCCD 订阅esp_ble_conn_write()可能失败应用层应处理ESP_FAIL返回并考虑重试策略字段一致性esp_ble_wss_set_measurement()会根据 flag 自动重建 Weight Feature因此调用时应确保flag与结构体中的 timestamp / user_id / bmi / height 字段保持一致避免宣称支持但未携带数据的矛盾状态分辨率语义当measurement_unit 0时单位固定为 kg / 米为 1 时解析需参考 Weight Feature 中的w_resolution/h_resolution客户端与服务器端必须使用同一套分辨率约定多用户场景user_id字段用于区分多个用户档案同一体重秤服务一个esp_ble_wss_measurement_t缓存只能保存最近一次测量多用户场景建议在应用层按user_id维护测量历史。参考资料仓库内体重秤服务文档docs/zh_CN/bluetooth/ble_wss.rst组件头文件与实现esp_wss.h、esp_wss.c组件配置项Kconfig.in示例工程examples/bluetooth/ble_services/ble_wss依赖的连接管理框架components/bluetooth/ble_conn_mgr服务总览文档docs/zh_CN/bluetooth/ble_services.rst【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考