I'm trying to mesure RSSI indicator on iOS (6 with BLE) from several bluetooth peripheral.
I can get RSSI with scanForPeripheral :
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[_manager scanForPeripheralsWithServices:nil
options:options];
coupled with:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
this works but I have no control on the rate of packets receive and the result seems uncertain.
I've read : https://stackoverflow.com/a/12486927/270209 but my rate is not close to 100ms at all (more 1~2 seconds)
If I'm connected to the device the result with readRSSI seems more reliable.
I'm looking for a way to "stimulate" peripherals for more frequents updates in scan mode or a way to connect to more than one peripheral at a time.
Thanks
Edit : I've also tried to start / stop scan quickly, it seems that at start scan detects more devices and updates are more frequent
I'm sure you've already figured this out but just in case someone comes across this (like I just did) looking for other info, if you're not using other iOS devices with coreLocation you need to call the peripheralDidUpdateRSSI:
delegate using [self.myPeripheral readRSSI];
.
You can call for RSSI data updates in didUpdateValueForCharacteristic:
as often as you like once in the updateValue delegate.
You don't need this in viewDidLoad:
NSDictionary *options = etc...
This NSDictionary is created in the didDiscoverPeripheral:
delegate.
So the overall flow would be:
Check that you are receiving RSSI in the NSLog where you obtained the RSSI data...
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if ([localName length] > 0){
NSLog(@"Discovered: %@ RSSI: %@", peripheral.name, RSSI);
// your other needs ...
}
Call peripheralDidUpdateRSSI:
here since this is where updates will occur continuously if you've set notify value to YES [peripheral setNotifyValue:YES forCharacteristic:characteristic];
- (void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
//Call the peripheralDidUpdateRSSI delegate ..
[self.myPeripheral readRSSI];
// do all of your other characteristic value updates here
}
readRSSI
will call the delegate where you perform your RSSI updates on your UILabel (or whatever you're using) every time you update the previous characteristics values:
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error;
{
_rssiLabel.text = [self.myPeripheral.RSSI stringValue];
NSLog(@"RSSI Method”);
}
If you don't need characteristic values for your app just run a loop in there with whatever timing you need the RSSI value to refresh.
(Assuming you're on an iOS device:) CoreBluetooth is likely deliberately limiting the rate at which it's active on the antenna. Bluetooth LE, Bluetooth Classic, and Wi-Fi are all on the same antenna on iOS devices, so the radios try to keep unnecessary chatter to a minimum. You could try filing a bug on CoreBluetooth to add an option or way to control the update frequency, but I don't imagine they'll implement it, as their primary design goals are to: 1. Not drain the device's battery unnecessarily and 2. Co-exist with the other antenna's radios. (They've also said in posts on the Apple devforums that, for example, if you want a higher data rate than the iOS BTLE implementation, you should use Bluetooth Classic or something that's been designed for it. BTLE is meant to be low-power first and foremost, and they've taken that to its logical end.)
Indeed, the delay between peripheral.readRSSI()
and peripheralDidUpdateRSSI
is like a second!
I think the best way is to read the RSSI value on the BLE device itself and send it to the iOS device.
The peripheral advertises based on the firmware of the peripheral. This can be set from as low at 100ms to almost as high as 2 seconds.
When using an iOS device as a Bluetooth Peripheral, I have found no way of changing it.
Here is Apples documentation: Look in section 3.5...
https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf