Search code examples
c++bluetooth-lowenergyesp32

How to dynamically BLE advertise on ESP32 and reflect on flutter app


My ESP32-based custom-PCB BLE peripheral is advertising LiFP batteries dynamic physical values, such as current or SoC (State of Charge).

Basically, the code is as follows:

/// Returns the manufacturer data as a String
void Ble :: setAdvertisingManufacturerData(BLEAdvertisementData *advertisementData) {

    const float soc = battery.getSoc();
    log("Advertising Soc %d%%", soc);
    
    const char bytes[] = {
        (manCode>>8)&0xff, manCode&0xff,
        // SoC: 2 bytes | 0~2 bytes
        (soc>>8)&0xff, soc&0xff,

    };

    advertisementData->setManufacturerData(std::string(bytes, sizeof(bytes)));
}

/// Prepares the advertising manif data
void Ble :: advertise() {
    BLEAdvertisementData advertisementData;
    advertisementData.setFlags(0x6);
    
    setAdvertisingManufacturerData(&advertisementData);

    pAdvertising = BLEDevice::getAdvertising();
    pAdvertising->setScanResponse(true);
    pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
    pAdvertising->setMinPreferred(0x12);
    
    pAdvertising->setAdvertisementData(advertisementData);
    pAdvertising->start();
}

void Ble :: setup() {
    // == Start the advertising
    advertise();
}

/// Dynamically advertises every seconds
void Ble :: loop() {
    // == Dynamically advertise
    static unsigned lastAdvertised = 0;
    const unsigned now = millis();
    
    if (!lastAdvertised || now - lastAdvertised > 1000) {
        lastAdvertised = now;

        BLEAdvertisementData scanResponse;
        setAdvertisingManufacturerData(&scanResponse);
        pAdvertising->stop();
        pAdvertising->setScanResponseData(scanResponse);
        pAdvertising->start();
    }
}

So far so good. But from the Flutter app, the advertisement manufacturer data still shows SoC to be zero (aka the initial value) despite the evolving value I see in my ESP32 logs.

I probably made a mistake, any help welcome!

[UPDATE] With the nRF mobile app I get this:

enter image description here

And I see there are two sections with type 0x09: the first one is "empty" while the second has the right data.


Solution

  • I finally did that, that makes my advertising being dynamic.

    I removed the setScanResponseData()and replaced by another call of setAdvertisementData() as I do in advertise().

    But I still don't get what setScanResponseData() is for.

    
    void Ble :: loop() {
    
        // == Dynamically advertise
        static unsigned lastAdvertised = 0;
        const unsigned now = millis();
    
        if (!lastAdvertised || now - lastAdvertised > 5000) {
            lastAdvertised = now;
            
            log("Dynamic advertising");
    
            BLEAdvertisementData scanResponse;
            std::string md = getAdvertisingManufacturerData();
            setAdvertisingManufacturerData(md, &scanResponse);
            pAdvertising->stop();
            //pAdvertising->setScanResponseData(scanResponse);
            pAdvertising->setAdvertisementData(scanResponse);
            pAdvertising->start();
    
        }
    }