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

最近更新于 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

实践

源码参考来源:https://github.com/espressif/arduino-esp32/blob/3.3.11/libraries/BLE/examples/Beacon_Scanner/Beacon_Scanner.ino

#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);
}

file

基于 ESP32-WROOM-32 实践 Beacon 扫描 – PlatformIO
Scroll to top
打开目录