BLE with multiple identical devices - how to choose?

I'm starting to work on BLE and would like some advice on best practices or what to look out for if any one has been down this route.


For example, if 3 people are wearing the same Polar Bluetooth HRM (i.e., in a Gym) when the app starts up and scans for perifierials & services how can I choose which device to select?

CBCentralManagerScanOptionAllowDuplicatesKey is off by default, to avoid battery drain.


Will the closest HRM (strongest signal) appear in the CBPeripheral didDiscoverServiceslist first?

Is there a way for the user to 'save' their device? - since there is no pairing option or specific UID available that I am aware of.


Thanks...

Replies

Anyone?


The approach I'm taking is


(1) To only scan for devices I need


     // https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.asp
     let BATTERY_SERVICE_UUID        = "180F"
     let DEVICE_INFO_SERVICE_UUID    = "180A"
     let HRM_HEART_RATE_SERVICE_UUID = "180D"

    func centralManagerDidUpdateState(central: CBCentralManager) {

        switch (central.state) {
   
        case .Unsupported:  print("CoreBluetooth BLE hardware is unsupported on this platform")
        case .Unauthorized: print("CoreBluetooth BLE state is unauthorized")
        case .Unknown:      print("CoreBluetooth BLE state is unknown")
        case .Resetting:    print("CoreBluetooth BLE is resetting")
        case .PoweredOff:   print("CoreBluetooth BLE hardware is powered off")
   
        case .PoweredOn:
   
                print("CoreBluetooth BLE hardware is powered on and ready")
                print("Scanning perifierals for services that I want")
       
                let services = [CBUUID(string: BATTERY_SERVICE_UUID),
                                CBUUID(string: DEVICE_INFO_SERVICE_UUID),
                                CBUUID(string: HRM_HEART_RATE_SERVICE_UUID)]
     
                central.scanForPeripheralsWithServices(services, options: nil)
   
        }
    }


(2) Then find the first valid device that contains a local name, stop scanning and use it


    func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {

        // Check to make sure that the device has a non-empty local name //
        if let localName = advertisementData[CBAdvertisementDataLocalNameKey] {
     
            print("Found Heart rate Monitor: \(localName)")
            self.centralManager.stopScan()                                          // Stop Scanning


            self.hrmPeripheral = peripheral;                                        // Store the peripheral

            peripheral.delegate = self                                              // Add the delegate

            self.centralManager.connectPeripheral(peripheral, options: nil)         // Connect to the peripheral

        }
    }



But perhaps I should scan for a few seconds and place all peripherals into an array along with their RSSI. Then after I stop scanning, loop through that array to find the one with the highest RSSI and set that periferial as the hrmPeripheral?


Does anyone do it this way?

I know this is a very old post, but has anyone tried this method?

I implemented a 3-second scan approach and it works quite well with our hardware. Devices are advertising 2-4 times per second. iOS scans for 3 seconds (with service filter) and stores all responses along with RSSI. When timer expires I pick the device with the best RSSI and connect to it. It is the user's responsibility to hold the phone closest to the device they want to connect to, so if they fail to do this the algorithm will not work. Note: While scanning you will get many responses for the same device. We compare the RSSI value for all responses and store the best RSSI value received for each device. This way the user has a few seconds to move the phone close to the preferred device.


Once connected I also save the UUID of the connected device in persistent storage. Later I use this UUID to connect to the prefered device. This method is not perfect because the UUID is generated by iOS and cached and iOS does not guarentee the UUID will not change in the future. You have two options here to deal with this. iOS will ask the user to pair the device if your device has at least one BLE servce/characteristic that requires security. If the user chooses to paid (they are not required to do so) then iOS will keep the UUID until the user unpairs the device. Another option for using the cached UUID is to implement a timeout while trying to connect to the cached UUID. If the timer expires you throw away the UUID and go back to scanning.

It's a bummer Apple does not provide more support for this common issue but your approach is the cleanest I have found in my research. Thanks mate.