WrightsCS WrightsCS - 4 months ago 24
iOS Question

CoreBluetooth connect to only nearest RSSI (BLE)

I am looking for a way to connect to only the nearest peripheral based on the RSSI. My goal is to leave other peripherals listed but only have the closest peripheral connect.

Since RSSI is only available while the device is connected, would it make sense to wait till all the devices are connected then determine the closest peripheral based on the RSSI then disconnect the rest?


- (void) connectToPeripheral:(CBPeripheral *)peripheral
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE],CBConnectPeripheralOptionNotifyOnDisconnectionKey,nil];
[myCBCentralManager connectPeripheral:peripheral options:options];

Delegates used

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral;


* @property RSSI
* @discussion While connected, the RSSI of the link in decibels.
@property(retain, readonly) NSNumber *RSSI;


This is what worked best for me. I initially scanned for Peripherals and then just selected the one with the highest RSSI. (Yes, this DOES report back the RSSI for every device. You do NOT need to be connected to it first).

However, I found this to be unreliable. There were just too much fluctuations in the RSSI value. So I did the following instead.

I used:

NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];//allow duplicates with YES
[self.CM scanForPeripheralsWithServices:uuidArray options:options]; 

The callback is:

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI 

This will continue to report the RSSI of every peripheral until you call the method:

[self.CM stopScan];

The "didDiscoverPeripheral" you will be called for every ad packet that the Central (your iPhone) sees. Add a routine in this callback to average the RSSI for each unique peripheral found. My experience was that a 1 second scan time was sufficient, but it depends on how often your peripheral is advertising (i.e. its advertising interval)