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

Switching BLE client (ios/android) on the same ESP ... and can't reconnect without re-bonding

Open Koxx3 opened this issue 3 years ago • 21 comments

Hello

I have a large project with ESP-DF (4.4.1) and Ardunio (2.0.3). I use Nimble-Arduino (1.4.0).

My ESP32 act as server and clients (phones) alternativly connect on the ESP32.

Currently, once android is the last peered device (then disconnected), the iphone will never be able to reconnect (his ble stack says "Peer removed pairing information"). The user has to manualy remove it from ios peered devices... not very user friendly.

I've found some posts about "BLE_HOST_BASED_PRIVACY" option. But it seems it's forced to '1' in my ESP-IDF configuration.

esp_nimble_cfg.h

#if CONFIG_IDF_TARGET_ESP32
#define MYNEWT_VAL_BLE_HOST_BASED_PRIVACY (1)
#else
#ifndef MYNEWT_VAL_BLE_HOST_BASED_PRIVACY
#define MYNEWT_VAL_BLE_HOST_BASED_PRIVACY (CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY)
#endif
#endif

Is there any solution ? found nothing in the documentation.

Thanks !

Koxx3 avatar Aug 09 '22 16:08 Koxx3

My init sequence is this :

    NimBLEDevice::init(bleName);

    NimBLEDevice::setMTU(BLE_MTU);
    NimBLEDevice::setPower(ESP_PWR_LVL_P9);

    /////
    NimBLEDevice::setSecurityAuth(true, true, true);
    NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
    // NimBLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
    NimBLEDevice::setSecurityCallbacks(new BLESecurityCallback());
    /////

    int mtu = BLEDevice::getMTU();
    Serial.print(F("BLH - MTU : "));
    Serial.println(mtu);

    // Serial.printf ("__PRETTY_FUNCTION__ = %s\n", __PRETTY_FUNCTION__);

    // Create the BLE Server
    pServer = BLEDevice::createServer();
    pServer->setCallbacks(new BLEServerCallback());

...


    NimBLEDevice::setSecurityPasskey(pinCode);
    pSecurity->setStaticPIN(pinCode);
    pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
    pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);

Koxx3 avatar Aug 09 '22 16:08 Koxx3

Host based privacy is required for the esp32 to support bonding with phones, this is not the issue you're having.

It sounds like what you need is to increase the number of bonds that can be stored. You can set this with CONFIG_BT_NIMBLE_MAX_BONDS by default it is set to 3.

h2zero avatar Aug 09 '22 16:08 h2zero

ok thanks. i'll try right now 👍 3 in not enought for a 2 client devices competition ?

Koxx3 avatar Aug 09 '22 17:08 Koxx3

nope ... same issue.

by the way, I tried many solutions to increease nimble log levels, but it's not working : -DBLE_HS_LOG_LVL=0 -DMYNEWT_VAL_BLE_HS_LOG_LVL=0 -DCONFIG_BT_NIMBLE_LOG_LEVEL=0

Koxx3 avatar Aug 09 '22 17:08 Koxx3

Please try erasing the esp32 flash before uploading and try again.

h2zero avatar Aug 09 '22 18:08 h2zero

same same. I erased the flash, and reflashed all.

I've set with build flags : -DCONFIG_BT_NIMBLE_MAX_BONDS=7 -DMYNEWT_VAL_BLE_STORE_MAX_BONDS=7

confirmed to be taken into account by log traces

Koxx3 avatar Aug 09 '22 19:08 Koxx3

my test : 1/ remove peering from ios & android phone 2/ launch android app, peering (with pin code), read datas, disconnect => all good 3/ launch ios app, peering (with pin code), read datas, disconnect => all good 4/ launch android app, it request for a new peering, disconnect => wrong 5/ launch ios app, it fails at connection => "peer removed" ios bt stack trace

if I manually remove the peering from ios, then I can peer it again and it works. but very dirty

Koxx3 avatar Aug 09 '22 20:08 Koxx3

Thanks, I'm not sure what is happening in the case.

Could you try with the secure server example and let me know if you have the issue? I will need to reproduce this to debug so it would be helpful to confirm with common code.

h2zero avatar Aug 09 '22 20:08 h2zero

not so easy (flash encryption, lot of scripts, have to replicate a part of the phone apps), but I'll try.

Koxx3 avatar Aug 09 '22 20:08 Koxx3

it works with the example with the same envrionnement (same IDF, arduino, lib ...). I've posted most of my code above for the BLE. what could be wrong. I also scan almost continously. could it be related ?

Koxx3 avatar Aug 09 '22 21:08 Koxx3

Thanks for checking that. So if it works fine with the example code there must be something else going on in your code or environment that is different, There isn't much I can suggest as the code you've provided does not present any obvious faults.

I would recommend however to remove the use of NimBLESecurity class in your code, this might (shouldn't) be part of the issue, however, it has been deprecated for some time and now removed in the master branch and will not be in the next releases.

h2zero avatar Aug 09 '22 23:08 h2zero

ok, thanks for the advise & help. I close the issue ;)

Koxx3 avatar Aug 10 '22 07:08 Koxx3

still trying to test the example and understand. it seems as soon I increase the number of characteristics on my services, the issue happen.

Koxx3 avatar Aug 10 '22 21:08 Koxx3

1 service with 6 chrac + 1 service with 1 charac => OK 1 service with 14 chrac + 1 service with 1 charac => KO !

Koxx3 avatar Aug 10 '22 21:08 Koxx3

Here is the full test code.

#include <Arduino.h>
#include <NimBLEDevice.h>

#define ENABLE_ALL_CHARAC 0
#define ENABLE_ALL_SERVICE_AND_CHARAC 1

#define SERVICE_MAIN_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define SERVICE_FIRMWARE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914c"
#define SERVICE_SETTINGS_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914d"
#define SERVICE_VESC_UUID "6e400001-b5a3-f393-e0a9-e50e24dcca9e"

#define MEASUREMENTS_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a0"
#define MEASUREMENTS2_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a1"
#define FIRMWARE_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a3"
#define COMMANDS_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a5"
#define BTLOCK_STATUS_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a6"
#define ERROR_HISTORY1_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a7"
#define CALIB_ORDER_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26ad"
#define SWITCH_TO_OTA_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26ae"
#define LOGS_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26af"
#define DISTANCE_RST_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26b5"
#define ADC_DAC_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26b6"
#define ACTION_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26fe"
#define SETTINGS_DATA_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26ff"
#define SETTINGS_VERSION_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26fc"
#define DATE_TIME_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26b7"
#define TPMS_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define VESC_CHARACTERISTIC_UUID_RX_UUID "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
#define VESC_CHARACTERISTIC_UUID_TX_UUID "6e400003-b5a3-f393-e0a9-e50e24dcca9e"

NimBLECharacteristic *pCharacteristicMeasurements;
NimBLECharacteristic *pCharacteristicMeasurements2;
NimBLECharacteristic *pCharacteristicBtlockStatus;
NimBLECharacteristic *pCharacteristicErrorHistory1;
NimBLECharacteristic *pCharacteristicCalibOrder;
NimBLECharacteristic *pCharacteristicOtaSwitch;
NimBLECharacteristic *pCharacteristicLogs;
NimBLECharacteristic *pCharacteristicDistanceRst;
NimBLECharacteristic *pCharacteristicCommands;
NimBLECharacteristic *pCharacteristicAdcDac;
NimBLECharacteristic *pCharacteristicSettingsVersion;
NimBLECharacteristic *pCharacteristicVescTx;
NimBLECharacteristic *pCharacteristicVescRx;
NimBLECharacteristic *pCharacteristicDateTime;
NimBLECharacteristic *pCharacteristicTpms;
NimBLECharacteristic *pCharacteristicSettingsGen;
NimBLECharacteristic *pCharacteristicSettingsAction;
NimBLECharacteristic *pCharacteristicFirmware;

void setup()
{
  Serial.begin(921600);

  Serial.println("\nBoot");

  NimBLEDevice::init("Smart-00");
#ifdef ESP_PLATFORM
  NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
#else
  NimBLEDevice::setPower(9); /** +9db */
#endif

  NimBLEDevice::setSecurityAuth(true, true, true);
  NimBLEDevice::setSecurityPasskey(147258);
  NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
  NimBLEServer *pServer = NimBLEDevice::createServer();

  BLEService *pServiceMain = pServer->createService(BLEUUID(SERVICE_MAIN_UUID));
  BLEService *pServiceFirmware = pServer->createService(BLEUUID(SERVICE_FIRMWARE_UUID));
#if ENABLE_ALL_SERVICE_AND_CHARAC
  BLEService *pServiceSettings = pServer->createService(BLEUUID(SERVICE_SETTINGS_UUID));
  BLEService *pServiceVesc = pServer->createService(BLEUUID(SERVICE_VESC_UUID));
#endif

  // Create a BLE Characteristic

  //-------------------
  // services firmware

  pCharacteristicFirmware = pServiceFirmware->createCharacteristic(
      FIRMWARE_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  //-------------------
  // services main

  pCharacteristicCommands = pServiceMain->createCharacteristic(
      COMMANDS_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN |
          NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  pCharacteristicBtlockStatus = pServiceMain->createCharacteristic(
      BTLOCK_STATUS_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN |
          NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  pCharacteristicDateTime = pServiceMain->createCharacteristic(
      DATE_TIME_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);

  pCharacteristicErrorHistory1 = pServiceMain->createCharacteristic(
      ERROR_HISTORY1_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  pCharacteristicSettingsVersion = pServiceMain->createCharacteristic(
      SETTINGS_VERSION_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  pCharacteristicTpms = pServiceMain->createCharacteristic(
      TPMS_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);


#if ENABLE_ALL_CHARAC

  pCharacteristicMeasurements = pServiceMain->createCharacteristic(
      MEASUREMENTS_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  pCharacteristicMeasurements2 = pServiceMain->createCharacteristic(
      MEASUREMENTS2_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  pCharacteristicCalibOrder = pServiceMain->createCharacteristic(
      CALIB_ORDER_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);

  pCharacteristicOtaSwitch = pServiceMain->createCharacteristic(
      SWITCH_TO_OTA_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);

  pCharacteristicLogs = pServiceMain->createCharacteristic(
      LOGS_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);

  pCharacteristicDistanceRst = pServiceMain->createCharacteristic(
      DISTANCE_RST_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);

  pCharacteristicAdcDac = pServiceMain->createCharacteristic(
      ADC_DAC_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN |
          NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

#endif

//-------------------
// VESC settings
#if ENABLE_ALL_SERVICE_AND_CHARAC
  // Create a BLE Characteristic for VESC TX
  pCharacteristicVescTx = pServiceVesc->createCharacteristic(
      VESC_CHARACTERISTIC_UUID_TX_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN);

  // Create a BLE Characteristic for VESC RX
  pCharacteristicVescRx = pServiceVesc->createCharacteristic(
      VESC_CHARACTERISTIC_UUID_RX_UUID,
      NIMBLE_PROPERTY::READ |
          NIMBLE_PROPERTY::READ_ENC |
          NIMBLE_PROPERTY::READ_AUTHEN |
          NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);

  //-------------------
  // services settings

  pCharacteristicSettingsGen = pServiceSettings->createCharacteristic(
      SETTINGS_DATA_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::INDICATE |
          NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);

  pCharacteristicSettingsAction = pServiceSettings->createCharacteristic(
      ACTION_CHARACTERISTIC_UUID,
      NIMBLE_PROPERTY::NOTIFY |
          NIMBLE_PROPERTY::INDICATE |
          NIMBLE_PROPERTY::WRITE |
          NIMBLE_PROPERTY::WRITE_ENC |
          NIMBLE_PROPERTY::WRITE_AUTHEN);
#endif


  pServiceMain->start();
  pServiceFirmware->start();
#if ENABLE_ALL_SERVICE_AND_CHARAC
  pServiceVesc->start();
  pServiceSettings->start();
#endif

  pCharacteristicFirmware->setValue("sd_vesc_35v2");
  uint8_t data[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  pCharacteristicCommands->setValue(data);

  NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_MAIN_UUID);
  pAdvertising->addServiceUUID(SERVICE_FIRMWARE_UUID);

#if ENABLE_ALL_SERVICE_AND_CHARAC
  pAdvertising->addServiceUUID(SERVICE_VESC_UUID);
  pAdvertising->addServiceUUID(SERVICE_SETTINGS_UUID);
#endif

  pAdvertising->start();
}

void loop()
{

  vTaskDelay(10 / portTICK_PERIOD_MS);
}

Koxx3 avatar Aug 10 '22 21:08 Koxx3

if I set ENABLE_ALL_CHARAC to 1, it doesn't work anymore.

Koxx3 avatar Aug 10 '22 21:08 Koxx3

platformio config :

[env]
platform = https://github.com/tasmota/platform-espressif32/releases/download/v.2.0.3/platform-espressif32-v.2.0.3.zip
framework = arduino, espidf
board = esp32dev

lib_deps = 
	h2zero/[email protected]

board_build.partitions = partition6.csv
board_upload.offset_address = 0xb000

build_flags =
	-DESP32=1
	-DARDUINO_ARCH_ESP32=1
	-DARDUINO=100
	-Wformat-contains-nul
	-Wno-format-overflow
	-Wno-error=format-truncation
	-Wno-cast-function-type
	-Wno-misleading-indentation
	-Wignored-qualifiers
	-ftrack-macro-expansion=0
	-DUSE_PGM=1
	-DCONFIG_BT_NIMBLE_MAX_BONDS=7
	-DMYNEWT_VAL_BLE_STORE_MAX_BONDS=7
	;-fno-diagnostics-show-caret 
    ;-std=c++17
; only use C++17 now not GNU++17. This is an either-or relation.
    -std=gnu++17
build_unflags =
	-Werror=all
    -std=gnu++11

partition6.csv


# Name,   Type, SubType,  Offset,   Size,  Flags
nvs, data, nvs, 0xC000, 0x5000
otadata, data, ota, 0x11000, 0x2000
spiffs, data, spiffs, 0x13000, 0x2D000

ota_0, app, ota_0, 0x40000, 0x1D8000
ota_1, app, ota_1, 0x220000, 0x1D8000

# nvs_key,  data, nvs_keys, ,        0x1000

firmware / partitions encryption is enabled

Koxx3 avatar Aug 10 '22 21:08 Koxx3

1 service with 8 chrac + 1 service with 1 charac => fail

Koxx3 avatar Aug 10 '22 21:08 Koxx3

same issue with : 1 service with 1 charac

  • 1 service with 6 charac
  • 1 service with 2 charac
  • 1 service with 2 charac

==> so i doesn't seems related to the numbers of characteristics per service but more to a global number of characteristics. could it be related to NVS storage size ?

Koxx3 avatar Aug 10 '22 22:08 Koxx3

holly crap ! I increase the nuber of stored CCCDs... and it works now ! -DMYNEWT_VAL_BLE_STORE_MAX_CCCDS=20

I could be interesting to add a bit more of documentation on build options ;)

Koxx3 avatar Aug 10 '22 22:08 Koxx3

I was just about to respond when you typed that, but yes that is certainly the issue. Glad you figured it out :smile:, yes more documentation around these is certainly a good idea, though it is documented here: https://h2zero.github.io/NimBLE-Arduino/md__command_line_config.html

 CONFIG_BT_NIMBLE_MAX_CCCDS

Sets the maximum number of CCCD subscriptions to store

    Default value is 8 

h2zero avatar Aug 10 '22 22:08 h2zero