NimBLE-Arduino icon indicating copy to clipboard operation
NimBLE-Arduino copied to clipboard

Request for info - Dynamic MachineData Advertising/BroadCast

Open LeeNX opened this issue 1 year ago • 7 comments

Please could I ask for some help with getting Dynamic MachineData Advertising / BroadCast working?

I have Googled and LLM my way to what I think should work, but keep running into

E NimBLEAdvertisementData: Data length exceeded

my function been:

void setAdvertisingData() {
   NimBLEAdvertisementData advData = pAdvertising->getAdvertisementData(); // Get existing data

   uint8_t manufacturerData[12];
    manufacturerData[0] = 0xff; // manufacturer data value - custom
    manufacturerData[1] = 0xff;
    manufacturerData[2] = 0xa0; // begin sig
    manufacturerData[3] = 0x00;
    manufacturerData[4] = advertiseInterval;    // how often broadcast
    manufacturerData[5] = batteryLevel;         // battery level
    manufacturerData[6] = chargingState;        // charging state
    manufacturerData[7] = uint8_t(internalTempInt);  // temp of SOC
    manufacturerData[8] = uint8_t(internalTempDec);  // temp below decimal
    manufacturerData[9] = 0x00; // end sig
    manufacturerData[10] = 0xa0;

    advData.setManufacturerData(std::string((char *)manufacturerData, sizeof(manufacturerData)));

    pAdvertising->setAdvertisementData(advData);
}

First call works correctly, but future calls fails with the Data length exceeded.

I was not able to find any examples that did this, thou I did find a few PRs and issues that refer to this. I was also not able to following the Classes reference, like removeData() int, but which int Types?

Thinking I might need to remove the old setManufacturerData before updating and refreshAdvertisingData?

I was also wondering how I could get the Advertising data length? This is limited to 31 characters, if I understand. Would be nice to catch and oversized data length. I was not sure if sizeof(NimBLEAdvertisementData::getPayload()) would be correct.

If seeing the rest of my sketch is helpful - esp32base-test

LeeNX avatar Feb 13 '25 12:02 LeeNX

When updating the advertised data you need to first clear all of the existing data and rebuild the entire advertisement with the new data. Unfortunately there is no way to update just a part of the data because of varying lengths of some types which would be a pain to work around, easier just to erase and add it all again.

h2zero avatar Feb 13 '25 14:02 h2zero

Thank @h2zero

Mind if I ask what I think are some very basic questions? Sorry, I currently only have very basic C skills.

Using the base or starting advertising data as a template and then copy this into a new Advertising Data, and add the updated setManufacturerData possibility? Think I tried that, but now I am thinking I was getting the current Advertising data and then adding the custom data.

I will try and might have more questions. Thanks for a great library. More implementation documentation could be helpful for newbie like me. The examples help did help.

LeeNX avatar Feb 14 '25 06:02 LeeNX

The recommended way to do this is to call clearData then add all your data back in and update the advertisement.

h2zero avatar Feb 14 '25 14:02 h2zero

Thanks, I will try as soon as I get a chance.

LeeNX avatar Feb 17 '25 09:02 LeeNX

Just for completeness, I finally got this working as follows

// Set custom advertising with HID Service UUID
void setAdvertisingData() {
    NimBLEAdvertisementData adData;

    Serial.println("Clearing old advertisement data...");
    pAdvertising->clearData(); // Important: Clear old advertisement data

    //adData.clearData();
    adData.setAppearance(HID_GAMEPAD);
    adData.setShortName("lgp");
    adData.addTxPower();

    adData.addServiceUUID(hidDevice->getHidService()->getUUID());

    // Add battery level to Manufacturer Data
    uint8_t manufacturerData[10];
    //manufacturer code (0x02E5 for Espressif)
    manufacturerData[0] = 0xff; // manufacturer data value - custom
    manufacturerData[1] = 0xff;
    manufacturerData[2] = 0xa0; // begin sig
    manufacturerData[3] = 0x00;
    manufacturerData[4] = advertiseInterval;    // how often broadcast
    manufacturerData[5] = batteryLevel;         // battery level
    manufacturerData[6] = chargingState;        // charging state
    manufacturerData[7] = uint8_t(internalTempInt);  // temp of SOC
    manufacturerData[8] = uint8_t(internalTempDec);  // temp below decimal
    manufacturerData[9] = 0x00; // end sig

    adData.setManufacturerData(std::string((char *)manufacturerData, sizeof(manufacturerData)));

    // Debug: Check total advertisement data size
    size_t adSize = adData.getPayload().size();
    Serial.printf("Advertisement Data Size: %d bytes (Max: 31 bytes)\n", adSize);
    if (adSize > 31) {
        Serial.println("⚠️ Warning: Advertisement data exceeds 31 bytes!");
    } else {
        Serial.println("✅ Advertisement data is within limits.");
    }

    pAdvertising->setAdvertisementData(adData);
    // clearData resets flags to BLE_HS_ADV_F_DISC_GEN
    pAdvertising->setConnectableMode(BLE_GAP_CONN_MODE_UND);
    pAdvertising->setDiscoverableMode(BLE_GAP_DISC_MODE_GEN);
}

I have two last questions in the quest to understand as much as possible.

First, what does BLE_HS_ADV_F_DISC_GEN stand for? BLE, HS (High Speed?), ADV (Advertisement), F (Function or Full?), GEN (General) - bad guess

Second question, is getPayload, does not include the two control bytes or is this three byte or am I missing something else? The reason I ask, is that I found that things work if the getPayload is 28 bytes, anything else seems to exceed the advertising limit.

Thanks again.

LeeNX avatar Feb 23 '25 11:02 LeeNX

Glad you got it working.

First, what does BLE_HS_ADV_F_DISC_GEN stand for? BLE, HS (High Speed?), ADV (Advertisement), F (Function or Full?), GEN (General) - bad guess

These macros are named by the devs at Apache-Mynewt. This one is BLE Host advertisement flag generally <-> discoverable.

Second question, is getPayload, does not include the two control bytes or is this three byte or am I missing something else? The reason I ask, is that I found that things work if the getPayload is 28 bytes, anything else seems to exceed the advertising limit.

The first 3 bytes are occupied by the mandatory advertisement flags data.

h2zero avatar Feb 24 '25 22:02 h2zero

Glad you got it working.

Thank you, and thanks for your super awesome library!

First, what does BLE_HS_ADV_F_DISC_GEN stand for? BLE, HS (High Speed?), ADV (Advertisement), F (Function or Full?), GEN (General) - bad guess

These macros are named by the devs at Apache-Mynewt. This one is BLE Host advertisement flag generally <-> discoverable.

I would not have guest Host, but now I can see it. Is there a place where one could see what these macros might mean? I really don't like buggy anybody, especially busy people like yourself, that are doing awesome stuff.

Second question, is getPayload, does not include the two control bytes or is this three byte or am I missing something else? The reason I ask, is that I found that things work if the getPayload is 28 bytes, anything else seems to exceed the advertising limit.

The first 3 bytes are occupied by the mandatory advertisement flags data.

Thanks, I did think there was only two bytes, not sure where I saw that. Confirmation also saved my sanity. ;-)

If I could wish for things in regards to NimBLE-Arduino, is a little more resources or documentation on implementation. A low skilled tinker like myself hopefully would not bug the community so often.

LeeNX avatar Feb 26 '25 07:02 LeeNX