最近更新于 2026-08-09 23:07
测试环境
- ESP32-WROOM-32
- PlatformIO IDE 3.3.4
- PlatformIO Core 6.1.19
- pioarduino platform-espressif32 55.03.311(Arduino Release v3.3.11 based on ESP-IDF v5.5.5)
platformio.ini
[env:esp32dev]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
framework = arduino
monitor_speed = 115200
实践
#include <Arduino.h>
// 引入 ESP32 BLE 相关的核心头文件
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLEEddystoneURL.h>
#include <BLEEddystoneTLM.h>
#include <BLEBeacon.h>
int scanTime = 5; // 每次扫描持续的时间(单位:秒)
BLEScan *pBLEScan; // 声明 BLE 扫描对象的指针
// 自定义回调类:处理扫描过程中接收到的所有 BLE 广播设备
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice)
{
Serial.println("==================================================");
// 1. 设备名称 & MAC 地址 & 信号强度 (RSSI)
String devName = advertisedDevice.haveName() ? advertisedDevice.getName().c_str() : "N/A";
Serial.printf("%s\n", devName.c_str());
Serial.printf("%s\n", advertisedDevice.getAddress().toString().c_str());
Serial.printf("RSSI: %d dBm\n", advertisedDevice.getRSSI());
// 2. 广播标志位 (Flags) 检查
if (advertisedDevice.haveAppearance()) {
Serial.printf("Appearance: 0x%04X\n", advertisedDevice.getAppearance());
}
// 3. 服务 UUID (Service UUID)
if (advertisedDevice.haveServiceUUID()) {
Serial.printf("Service UUID: %s\n", advertisedDevice.getServiceUUID().toString().c_str());
}
// 4. 解析 厂商自定义数据 (Manufacturer Data)
if (advertisedDevice.haveManufacturerData())
{
String mData = advertisedDevice.getManufacturerData();
size_t dataLen = mData.length();
if (dataLen >= 2)
{
// 提取前两个字节作为 Company ID (BLE 中使用小端序)
uint16_t companyId = (uint8_t)mData[1] << 8 | (uint8_t)mData[0];
Serial.printf("Manufacturer data:\n");
Serial.printf(" Company ID: 0x%04X ", companyId);
// 判断常见厂商 (可以根据需要自行补充)
if (companyId == 0x06A8) {
Serial.print("(GD Midea Air-Conditioning Equipment Co., Ltd.)\n");
} else if (companyId == 0x004C) {
Serial.print("(Apple Inc.)\n");
} else if (companyId == 0x00E0) {
Serial.print("(Google)\n");
} else {
Serial.print("(Unknown)\n");
}
// 以 16 进制字符串格式输出 payload 内容
Serial.print(" Payload: 0x");
for (size_t i = 0; i < dataLen; i++) {
Serial.printf("%02X", (uint8_t)mData[i]);
}
Serial.println();
}
}
// 5. 判断 Eddystone URL / TLM 协议
if (advertisedDevice.getFrameType() == BLE_EDDYSTONE_URL_FRAME) {
BLEEddystoneURL eddystoneURL(&advertisedDevice);
Serial.printf("Eddystone URL: %s\n", eddystoneURL.getDecodedURL().c_str());
}
if (advertisedDevice.getFrameType() == BLE_EDDYSTONE_TLM_FRAME) {
BLEEddystoneTLM eddystoneTLM(&advertisedDevice);
Serial.printf("Eddystone TLM Temp: %.2f°C, Batt: %umV\n", eddystoneTLM.getTemp(), eddystoneTLM.getVolt());
}
Serial.println("==================================================\n");
}
};
void setup()
{
// 初始化串口通信,波特率设置为 115200
Serial.begin(115200);
Serial.println("Scanning...");
// 初始化 ESP32 BLE 设备(传入的设备名称参数可留空)
BLEDevice::init("");
// 获取 BLE 扫描器单例指针
pBLEScan = BLEDevice::getScan();
// 设置设备扫描回调函数(当发现新设备时调用MyAdvertisedDeviceCallbacks)
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
// 开启主动扫描 (Active Scan):
// 主动模式下扫描器会在接收到广播包后发送 Scan Request 索要更多数据;
// 虽然比被动模式 (Passive Scan) 更耗电,但能更快速且完整地获取外设信息。
pBLEScan->setActiveScan(true);
// 设置扫描间隔 (Interval) 与 扫描窗口大小 (Window),单位均为 毫秒 (ms)
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // 窗口值必须小于或等于间隔值
}
void loop()
{
// 启动一次 BLE 扫描:
// 参数 1: 扫描持续时间 (秒)
// 参数 2: is_continue,设置为 false 表示重新进行一次扫描,而不是接着上次的继续
BLEScanResults *foundDevices = pBLEScan->start(scanTime, false);
// 打印本次扫描到的设备总数
Serial.print("Devices found: ");
Serial.println(foundDevices->getCount());
Serial.println("Scan done!");
// 及时清空扫描结果缓冲区,防止内存泄漏或过度占用内存
pBLEScan->clearResults();
// 延迟 2 秒后进入下一轮扫描循环
delay(2000);
}

基于 ESP32-WROOM-32 实践 Beacon 扫描 – PlatformIO
