当前位置: 首页 > article >正文

ESP32 BLE扫描实战:手把手教你用ESP-IDF API解析广播包里的设备名、UUID和自定义数据

ESP32 BLE广播数据解析实战从设备名到自定义数据的完整指南在智能家居和物联网应用中BLE低功耗蓝牙设备间的通信已成为标配。作为开发者我们经常需要从BLE设备的广播包中提取关键信息比如设备名称、服务UUID以及厂商自定义数据。本文将深入探讨如何利用ESP32的ESP-IDF框架高效解析这些隐藏在广播数据中的宝贵信息。1. BLE广播数据基础解析BLE设备通过广播包向外传递信息这些数据包遵循特定的结构。每个广播数据单元由长度、类型和值三部分组成[长度][类型][值][长度][类型][值]...ESP-IDF提供了esp_ble_resolve_adv_data()函数来简化解析过程。这个函数接收原始广播数据、目标数据类型和长度指针返回对应数据的指针。常见广播数据类型AD Type包括类型常量值描述ESP_BLE_AD_TYPE_NAME_CMPL0x09完整设备名ESP_BLE_AD_TYPE_16SRV_PART0x0216位UUID部分列表ESP_BLE_AD_TYPE_16SRV_CMPL0x0316位UUID完整列表ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE0xFF厂商自定义数据在智能家居场景中温湿度传感器可能通过厂商自定义数据字段直接发送当前读数而门磁传感器则可能用特定UUID标识设备类型。2. 实战解析设备名称设备名称是最基础也是最重要的信息之一它帮助用户识别设备。以下是提取设备名的完整代码示例uint8_t *adv_name NULL; uint8_t adv_name_len 0; void handle_scan_result(esp_ble_gap_cb_param_t *scan_result) { adv_name esp_ble_resolve_adv_data( scan_result-scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, adv_name_len ); if(adv_name_len 0) { ESP_LOGI(BLE_SCAN, 发现设备: %.*s, adv_name_len, (char*)adv_name); } }关键点说明当设备名超过31字节时部分设备可能只发送缩短的名称AD Type 0x08设备名不一定以null结尾必须依赖返回的长度参数某些设备可能将名称放在扫描响应包而非广播包中提示实际项目中建议同时检查0x08和0x09两种类型并优先使用完整名称。3. 深入UUID提取技巧服务UUID是识别设备功能的关键。BLE设备可能公布部分或全部服务UUIDuint8_t *uuid_list; uint8_t uuid_len; void extract_uuids(esp_ble_gap_cb_param_t *scan_result) { // 尝试获取完整UUID列表 uuid_list esp_ble_resolve_adv_data( scan_result-scan_rst.ble_adv, ESP_BLE_AD_TYPE_16SRV_CMPL, uuid_len ); if(uuid_len 0) { // 回退到部分UUID列表 uuid_list esp_ble_resolve_adv_data( scan_result-scan_rst.ble_adv, ESP_BLE_AD_TYPE_16SRV_PART, uuid_len ); } if(uuid_len 0) { ESP_LOGI(BLE_SCAN, 发现UUID列表:); for(int i 0; i uuid_len; i 2) { uint16_t uuid (uuid_list[i1] 8) | uuid_list[i]; ESP_LOGI(BLE_SCAN, - 0x%04X, uuid); } } }UUID处理注意事项16位UUID是蓝牙SIG定义的标准化服务标识每个UUID占2字节列表长度应为偶数对于32位和128位UUID需要使用对应的AD Type4. 厂商自定义数据解析实战厂商自定义数据Manufacturer Specific Data是设备厂商的自由发挥空间通常包含设备特有的信息。以下是解析示例typedef struct { uint16_t company_id; // 蓝牙公司标识符 uint8_t data[]; // 厂商自定义数据 } manufacturer_data_t; void handle_manufacturer_data(esp_ble_gap_cb_param_t *scan_result) { uint8_t *mfg_data; uint8_t mfg_data_len; mfg_data esp_ble_resolve_adv_data( scan_result-scan_rst.ble_adv, ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE, mfg_data_len ); if(mfg_data_len 2) { // 至少包含2字节的公司ID manufacturer_data_t *data (manufacturer_data_t*)mfg_data; ESP_LOGI(BLE_SCAN, 厂商ID: 0x%04X,>void handle_scan_result_complete(esp_ble_gap_cb_param_t *scan_result) { // 合并广播数据和扫描响应数据 uint8_t total_len scan_result-scan_rst.adv_data_len scan_result-scan_rst.scan_rsp_len; uint8_t *combined_data malloc(total_len); memcpy(combined_data, scan_result-scan_rst.ble_adv, scan_result-scan_rst.adv_data_len); memcpy(combined_data scan_result-scan_rst.adv_data_len, scan_result-scan_rst.ble_adv scan_result-scan_rst.adv_data_len, scan_result-scan_rst.scan_rsp_len); // 从合并数据中解析 uint8_t *name; uint8_t name_len; name esp_ble_resolve_adv_data(combined_data, ESP_BLE_AD_TYPE_NAME_CMPL, name_len); free(combined_data); }5.2 信号强度与距离估算RSSI接收信号强度指示可用于粗略估计设备距离void log_device_distance(esp_ble_gap_cb_param_t *scan_result) { int8_t rssi scan_result-scan_rst.rssi; uint8_t *tx_power esp_ble_resolve_adv_data( scan_result-scan_rst.ble_adv, ESP_BLE_AD_TYPE_TX_PWR, NULL ); if(tx_power) { int8_t tx_pwr *tx_power; // 简单距离估算米 double distance pow(10, (tx_pwr - rssi) / 20.0); ESP_LOGI(BLE_SCAN, 预估距离: %.2f米, distance); } }5.3 过滤重复设备连续扫描时可以使用设备地址和部分特征过滤重复报告#define MAX_DEVICES 20 typedef struct { esp_bd_addr_t addr; uint32_t last_seen; } seen_device_t; seen_device_t seen_devices[MAX_DEVICES]; bool is_new_device(esp_bd_addr_t addr) { for(int i 0; i MAX_DEVICES; i) { if(memcmp(seen_devices[i].addr, addr, ESP_BD_ADDR_LEN) 0) { seen_devices[i].last_seen xTaskGetTickCount(); return false; } } // 找到空位或最旧的记录 int oldest 0; for(int i 1; i MAX_DEVICES; i) { if(seen_devices[i].last_seen seen_devices[oldest].last_seen) { oldest i; } } memcpy(seen_devices[oldest].addr, addr, ESP_BD_ADDR_LEN); seen_devices[oldest].last_seen xTaskGetTickCount(); return true; }6. 实战案例智能家居网关实现结合以上技术我们可以实现一个完整的智能家居网关示例typedef enum { DEVICE_UNKNOWN, DEVICE_THERMOMETER, DEVICE_DOOR_SENSOR, DEVICE_SMART_PLUG } device_type_t; typedef struct { esp_bd_addr_t addr; device_type_t type; char name[32]; time_t last_update; union { struct { float temperature; float humidity; } thermo; struct { bool is_open; } door; } data; } smart_device_t; void handle_smart_home_device(esp_ble_gap_cb_param_t *scan_result) { // 1. 获取设备基本信息 smart_device_t device; memcpy(device.addr, scan_result-scan_rst.bda, ESP_BD_ADDR_LEN); // 2. 解析设备名 uint8_t *name esp_ble_resolve_adv_data( scan_result-scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, name_len ); if(name_len 0) { strncpy(device.name, (char*)name, MIN(name_len, sizeof(device.name)-1)); } // 3. 解析厂商数据确定设备类型 uint8_t *mfg_data; uint8_t mfg_data_len; mfg_data esp_ble_resolve_adv_data( scan_result-scan_rst.ble_adv, ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE, mfg_data_len ); if(mfg_data_len 3 ((manufacturer_data_t*)mfg_data)-company_id 0x02A5) { uint8_t *data mfg_data 2; // 跳过公司ID switch(data[0]) { case 0x01: device.type DEVICE_THERMOMETER; device.data.thermo.temperature ((data[1] 8) | data[2]) / 10.0; device.data.thermo.humidity ((data[3] 8) | data[4]) / 10.0; break; case 0x02: device.type DEVICE_DOOR_SENSOR; device.data.door.is_open data[1]; break; } } device.last_update time(NULL); update_device_in_database(device); }这个示例展示了如何将各种BLE数据解析技术整合到一个实际的智能家居网关应用中实现了设备发现、识别和状态更新的完整流程。

相关文章:

ESP32 BLE扫描实战:手把手教你用ESP-IDF API解析广播包里的设备名、UUID和自定义数据

ESP32 BLE广播数据解析实战:从设备名到自定义数据的完整指南 在智能家居和物联网应用中,BLE(低功耗蓝牙)设备间的通信已成为标配。作为开发者,我们经常需要从BLE设备的广播包中提取关键信息,比如设备名称、…...

Verilog自动化测试进阶:用VSCode插件5分钟生成带时序图的Testbench模板

Verilog自动化测试进阶:用VSCode插件5分钟生成带时序图的Testbench模板 在数字电路设计领域,Testbench的编写往往占据了工程师大量时间。传统手动编写方式不仅效率低下,还容易遗漏关键测试场景。本文将带你探索如何利用VSCode生态中的Verilog…...

保姆级教程:用TSM模型(PyTorch版)实现视频打架检测,从数据预处理到实时推理

实战指南:基于TSM模型的视频暴力行为检测系统开发 在公共安全领域,视频监控系统每天产生海量数据,但传统的人工监控方式效率低下且容易遗漏关键事件。想象一下,当监控中心同时处理数百路视频流时,操作员很难持续保持高…...

终极指南:如何解锁艾尔登法环帧率限制并实现超宽屏支持

终极指南:如何解锁艾尔登法环帧率限制并实现超宽屏支持 【免费下载链接】EldenRingFpsUnlockAndMore A small utility to remove frame rate limit, change FOV, add widescreen support and more for Elden Ring 项目地址: https://gitcode.com/gh_mirrors/el/El…...

终极免费PCB查看器:从零开始掌握OpenBoardView的完整指南

终极免费PCB查看器:从零开始掌握OpenBoardView的完整指南 【免费下载链接】OpenBoardView View .brd files 项目地址: https://gitcode.com/gh_mirrors/op/OpenBoardView 你是否曾经面对复杂的电路板文件感到无从下手?或者为了查看一个简单的.brd…...

保姆级教程:在UniApp Vue3项目中集成live-pusher,打造动态背景的趣味人脸活体检测

UniApp Vue3实战:用live-pusher打造沉浸式人脸活体检测体验 移动应用开发中,人脸活体检测已成为身份验证的核心环节。传统实现往往只关注功能实现,忽略了用户体验。本文将带你用UniApp和Vue3构建一个动态背景动作引导的趣味检测系统&#xff…...

3步解锁电脑玩手机游戏:scrcpy让你的Android设备变身游戏主机

3步解锁电脑玩手机游戏:scrcpy让你的Android设备变身游戏主机 【免费下载链接】scrcpy Display and control your Android device 项目地址: https://gitcode.com/gh_mirrors/sc/scrcpy 想要在电脑大屏幕上畅玩手机游戏吗?scrcpy这款开源工具能让…...

【AGI审计可信度生死线】:从GAAP到IFRS,6类会计估计场景中AGI决策偏差率超阈值的3个隐藏信号

第一章:AGI在财务分析与审计中的范式革命 2026奇点智能技术大会(https://ml-summit.org) 传统财务分析与审计长期受限于规则引擎的刚性、样本抽样的偏差以及人工复核的认知负荷。AGI的崛起正打破这一边界——它不再仅执行预设逻辑,而是具备跨模态理解财…...

全球仅7家对冲基金跑通AGI实时预测闭环——SITS2026泄露其低延迟数据管道设计(纳秒级特征注入+动态置信度熔断机制)

第一章:SITS2026分享:AGI与金融预测 2026奇点智能技术大会(https://ml-summit.org) 在SITS2026大会上,多家前沿研究团队展示了基于通用人工智能(AGI)范式的金融预测新范式——不再依赖孤立的时序模型或静态因子库&am…...

蒸馏你的前同事

上周,一个叫 “Colleague.skill” 的项目火了。 这是一个 AI 代理,它可以收集即将离职同事的 Slack 消息、邮件和文件,然后生成一个 .md 文件,你可以直接将其输入 AI,让 AI 按照那位同事的方式完成工作。 然后有人构建…...

【无人机控制】基于matlab LQR和PSO的无人机舰队分散控制系统设计【含Matlab源码 15351期】含报告

💥💥💥💥💥💥💞💞💞💞💞💞💞💞欢迎来到海神之光博客之家💞💞💞&#x1f49…...

轻松玩转树莓派Pico之五、FreeRTOS多任务实战

1. 为什么要在树莓派Pico上跑FreeRTOS? 树莓派Pico搭载的RP2040芯片虽然定位为微控制器,但其双核Cortex-M0架构和264KB的SRAM资源,在嵌入式领域已经算是"大内存"配置了。我刚开始玩Pico时也习惯用裸机编程,直到有一次需…...

Spring Boot 2.6.4 + MyBatis项目里,那个烦人的‘SqlSession was not registered for synchronization’日志到底要不要管?

Spring Boot中那个烦人的SqlSession警告:该忽略还是该解决? 第一次在控制台看到"SqlSession was not registered for synchronization because synchronization is not active"这条警告时,我正端着咖啡准备开始一天的工作。红色的…...

2026奇点大会AGI推理延迟压降至8.3ms的底层突破,如何让虚拟世界获得类神经突触响应?(附可复现架构图)

第一章:2026奇点智能技术大会:AGI与虚拟世界 2026奇点智能技术大会(https://ml-summit.org) AGI系统架构的范式跃迁 本届大会首次公开展示了基于多模态神经符号融合(Neuro-Symbolic Fusion, NSF)的AGI原型系统“Orion-7”&#…...

别再死磕协议文档了!用Java手撸一个GB28181的SIP心跳保活服务(附完整代码)

实战Java构建GB28181 SIP心跳保活服务的避坑指南 在视频监控系统集成领域,GB28181协议的心跳机制就像人体的脉搏——看似简单却关乎生死。去年我们团队接手某智慧园区项目时,曾因SIP心跳处理不当导致30%的摄像头在夜间频繁离线,运维人员不得不…...

从LSTM到LLM-to-Action:SITS2026发布游戏智能演进年表(2018–2026),标注3次范式跃迁时刻及对应算力/数据拐点)

第一章:SITS2026分享:AGI与游戏智能 2026奇点智能技术大会(https://ml-summit.org) AGI在游戏环境中的验证价值 通用人工智能(AGI)并非仅面向抽象推理任务,游戏世界正成为其核心验证场域。开放世界RPG、实时策略与多…...

相控阵天线(十三):旋转矢量法校准的工程化仿真与优化策略

1. 旋转矢量法校准的工程化挑战 第一次在实际项目中应用旋转矢量法校准256单元相控阵时,探头信号波动幅度比仿真小了近40%。这个意外让我意识到,教科书里的理想模型和工程现场完全是两回事。旋转矢量法(REV法)作为相控阵天线的主流…...

Qt/C++ 信号阻塞的RAII实践:QSignalBlocker的进阶用法与场景剖析

1. 为什么需要信号阻塞? 在Qt开发中,信号与槽机制是UI交互的核心。但有时候,我们并不希望某些操作触发信号。比如在批量更新控件状态时,每次修改都会触发信号,导致性能下降和逻辑混乱。我遇到过这样一个场景&#xff1…...

Scapy实战:从ARP缓存投毒到中间人攻击的攻防演练

1. ARP协议与缓存投毒原理剖析 ARP(Address Resolution Protocol)是局域网通信的基础协议,它的作用就像现实生活中的电话簿,负责将IP地址转换成对应的MAC地址。每台设备都维护着一个ARP缓存表,记录着最近通信过的设备信…...

XFCE桌面环境深度定制:彻底禁用自动锁屏与待机策略

1. 为什么需要禁用自动锁屏与待机功能? 很多使用Xubuntu系统的朋友都遇到过这样的困扰:正在跑一个长时间的任务,比如视频渲染、代码编译或者远程服务器监控,突然屏幕黑了,系统进入待机状态。更糟的是,有些…...

从宏观到微观:交通流模型如何驱动现代仿真系统

1. 交通流模型的三大流派:宏观、微观与混合 第一次接触交通流模型时,我被各种术语搞得晕头转向。直到在智慧城市项目里实际调试仿真系统,才真正理解不同模型的适用场景。简单来说,交通流模型就像观察蚂蚁搬家——你可以站在高处看…...

【实战指南】FreeRTOS 10.4.6源码解析与STM32F429移植全流程

1. FreeRTOS 10.4.6源码获取与解析 第一次接触FreeRTOS源码时,我对着官网密密麻麻的目录树发懵——这堆文件到底哪些才是核心?后来踩过几次坑才明白,Source和portable这两个文件夹就是整个系统的灵魂所在。以STM32F429为例,我们从…...

用PyTorch搞定ShapeNet部件分割:从数据加载到可视化,一份避坑指南

用PyTorch搞定ShapeNet部件分割:从数据加载到可视化,一份避坑指南 在3D点云深度学习领域,ShapeNet数据集因其丰富的部件标注信息而成为研究热点。但对于刚接触该领域的研究者来说,从原始数据到可视化结果的全流程往往充满陷阱——…...

CamOver实战指南:从零部署到自动化摄像头安全评估

1. CamOver工具简介与核心价值 CamOver是一款专注于网络摄像头安全评估的专业工具,它能够帮助安全研究人员快速发现并验证摄像头设备的安全漏洞。不同于普通的扫描工具,CamOver最大的特点在于它集成了Shodan和ZoomEye两大搜索引擎的API接口,可…...

TMS320F28335新手避坑指南:从零搭建CCS7.2项目到点亮第一个LED(附完整源码包)

TMS320F28335实战入门:CCS7.2环境搭建与LED控制全流程解析 第一次接触TMS320F28335这款经典DSP芯片时,面对CCS开发环境和复杂的项目配置,很多开发者都会经历从兴奋到困惑的过程。本文将以最简路径带你完成开发环境搭建、项目配置到第一个LED控…...

C#与Halcon控件深度集成:打造高交互性图像浏览窗口

1. 为什么需要深度集成Halcon控件? 在工业视觉和图像处理领域,Halcon一直是功能强大的工具库。但很多开发者在使用C#开发界面时,常常会遇到一个尴尬的问题:Halcon自带的图像显示窗口交互体验不够友好。想象一下,当操作…...

[CTF实战]从数字密文到Flag:Base与凯撒的联合破译

1. 数字密文的初步观察 拿到这道CTF题目时,首先映入眼帘的是一串长达百位的数字:3207357975641587136122466514425152961654613410728337142271750273124995105747053991640817066352343657398947248938255086358418100814441196784643527787764297。这…...

Vivado里AXI接口IP核怎么选?从DMA到VDMA,一次讲清ZYNQ数据搬运的“十八般兵器”

ZYNQ数据搬运核心IP选型指南:从DMA到VDMA的实战解析 在ZYNQ异构计算架构中,PS与PL的高效数据交互直接影响系统性能表现。面对Vivado IP Catalog中琳琅满目的AXI接口IP,开发者常陷入选择困境——AXI-DMA与AXI-VDMA有何本质区别?何时…...

告别迷茫!手把手教你用IQxel搞定Wi-Fi 6E信号测试(附详细配置截图)

告别迷茫!手把手教你用IQxel搞定Wi-Fi 6E信号测试 第一次拿到IQxel测试仪时,面对密密麻麻的网页界面和数十个参数选项,我完全不知从何下手。作为一款专业级无线测试设备,IQxel在Wi-Fi 6/6E测试领域确实功能强大,但它的…...

别再傻傻分不清了!Arduino编程中I/O和GPIO到底有啥区别?(附实战代码)

Arduino编程实战:I/O与GPIO的本质区别与正确用法 第一次接触Arduino开发板时,看到引脚上密密麻麻标注着"Digital I/O"、"Analog Input"和"PWM"等字样,而查阅芯片手册又频繁遇到"GPIO"这个专业术语&a…...