17
votes

I just started with the core bluetooth framework for iOS and I'm developing an app that needs to constantly scan for BLE devices so that I can retrieve their RSSI number every minute or so.

Currently I have:

manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[manager scanForPeripheralsWithServices:nil options:options];

this starts my app scanning for BLE devices and calls this delegate method when a device is discovered:

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    NSLog(@"Did discover peripheral. peripheral: %@ rssi: %@, UUID: %@ advertisementData: %@ ", peripheral, RSSI, peripheral.UUID, advertisementData);
    //Do something when a peripheral is discovered.

    rssiLabel.text = [RSSI stringValue];

    [manager retrievePeripherals:[NSArray arrayWithObject:(id)peripheral.UUID]];}

this method gets me the peripheral's RSSI number which i can display. The last line then calls this delegate method:

- (void) centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals {

    NSLog(@"Currently known peripherals :");
    int i = 0;
    for(CBPeripheral *peripheral in peripherals) {
        NSLog(@"[%d] - peripheral : %@ with UUID : %@",i,peripheral,peripheral.UUID);

    }

     NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
     [manager scanForPeripheralsWithServices:nil options:options];

}

This code seems to be working and doing a scan roughly every 1 minute, but I don't exactly know why it working...

The documentation on core bluetooth is pretty sparse so if anyone has any idea on how to do this, or has a better way to do what I'm trying to accomplish I'd appreciate the help!

4
I've just started reading the documentation myself, so you're further along than I. Question, why are you calling scanForPeripheralsWithServices in the delegate method didRetrievePeripherals? You call it already after the CBCentralManager is allocated. This may be causing the repetitive scan that you mentioned.mkr707
Seems to be working... How often is the RSSI updated? EDIT: Once a minute? I think there is a time out when you dont connect, so that it starts the scan over again.chwi
just my two cents for >=7.0: retrievePeripheralsWithIdentifiers needs to used from now on.bass.t

4 Answers

23
votes

Have you tried changing the scan option to YES?

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber  numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[manager scanForPeripheralsWithServices:nil options:options];

If you do this you will get your "didDiscoverPeripheral" callback with every ad packet that is seen by your iPhone, which would normally be about every 100ms (although I see this callback timing varying a lot for the same device). This includes the RSSI of each device it sees.

This should be a lot faster than your ~1 minute update rate.

3
votes

Is far as I can see, this should do what you want.

When you started scanning for peripherals with the original call, your delegate should begin to get calls whenever a BLE device is discovered. This will continue until you stop the scan with a call to

[manager stopScan];

I don't think you actually need the second call to scanForPeripheralsWithServices in your centralManager:didRetrievePeripherals method, since, as far as I know, the scanning doesn't stop until you tell it to. I'm still getting started on this, too, though, and there may be a timeout I have not found, yet.

I'm pretty sure the reason you get a call about once a minute is because the BLE device is only advertising that often. If it advertises more often, like a device in discovery mode, I think you will get the calls more often. I would be interesting if you could confirm that. If the device has a discovery mode, you might try triggering it to see if the notices speed up.

2
votes

You shouldn't do continous scanning as it is very costly for power. Once you discovered devices you have an array of CBPeripheral objects returned to you. On CBPeripheral you can read RSSI and get a callback when RSSI changes. See the following documentation: http://developer.apple.com/library/mac/#documentation/CoreBluetooth/Reference/CBPeripheralDelegate_Protocol/translated_content/CBPeripheralDelegate.html

2
votes

Swift Implementation of @Anders solution:

manager.scanForPeripheralsWithServices(nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey : NSNumber(value: true)])