NimBLE-Arduino: BLE working in Android, but not showing up in iOS

The below code (refactored BLE_server_multiconnect example with added security) works great on both Android 8.1 and Android 11 phones. No problems.

However, iPhone 10 and iPhone 11 phones aren’t even detecting the existence of NimBLE.

What am I doing wrong here?

#include <NimBLEDevice.h>

BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"


/**  None of these are required as they will be handled by the library with defaults. **
 **                       Remove as you see fit for your needs                        */  
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      BLEDevice::startAdvertising();//adding this line allows for multiple simultaneous BLE connections
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
  /***************** New - Security handled here ********************
  ****** Note: these are the same return values as defaults ********/
    uint32_t onPassKeyRequest(){
      Serial.println("Server PassKeyRequest");
      return 123456; 
    }

    
    void onPassKeyNotify(uint32_t passkey) {
      Serial.println("Passkey Notify");
    }
    
    bool onConfirmPIN(uint32_t pass_key){
      Serial.print("The passkey YES/NO number: ");Serial.println(pass_key);
      return true; 
    }


    void onAuthenticationComplete(ble_gap_conn_desc* desc) {
     if(desc->sec_state.encrypted){
        if(!desc->sec_state.encrypted) {
            Serial.println("Encrypt connection failed - disconnecting");
            /** Find the client with the connection handle provided in desc */
            NimBLEDevice::getClientByID(desc->conn_handle)->disconnect();
            vTaskDelay(5000);//bruteforce protection, 5s
            return;
          }
       }
    }
  /*******************************************************************/
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {
        Serial.print("Received Value: ");
        for (int i = 0; i < rxValue.length(); i++)
          Serial.print(rxValue[i]);

        if(rxValue.find("F") != -1)
          Serial.println("do stuff");
        }
    }
};


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

  // Create the BLE Device
  NimBLEDevice::init("NimBLE");
  NimBLEDevice::setPower(ESP_PWR_LVL_P9);

  NimBLEDevice::setSecurityAuth(true, true, true);
  NimBLEDevice::setSecurityPasskey(123456);
  NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
  
  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
                                        CHARACTERISTIC_UUID_TX,
                                        NIMBLE_PROPERTY::NOTIFY
                                       );

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
                                            CHARACTERISTIC_UUID_RX,
                                            NIMBLE_PROPERTY::WRITE
                                            );

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {

    if (deviceConnected) {
      pTxCharacteristic->setValue('c'); // Sending bluetooth message    
      pTxCharacteristic->notify();
      delay(500);
   }
   
    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("start advertising");
        oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
        // do stuff here on connecting
        oldDeviceConnected = deviceConnected;
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 34 (16 by maintainers)

Most upvoted comments

iOS seems to only show classic bluetooth capable devices. NimBLE is BLE only so iOS does not show it natively. The original library has both functionalities which is why it would show up then.

Turns out the iOS app was caching BLE improperly. So, problem solved.

The solution was to add this single line: pAdvertising->addServiceUUID((uint16_t)0x1101);

From my understanding it’s only the iOS built in BT scanner that ignores BLE devices and that was intentional as to connect to BLE devices it is expected that there would be a separate app to perform that function. Which makes sense because many BLE devices only advertise data and the iOS scanner will not report this, instead it only shows it in a list. So that leaves it up to the app developers to deal with BLE at the app level, which makes sense because every BLE device is different and could be non-standard while classic bluetooth services are more defined and easily supported by the OS.

As the name NimBLE implies, there is not and probably should not be any support for classic bluetooth, however you might be able to play with the advertised flags to fake BR/EDR capability.