Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReadRSSI doesn't call the delegate method

I got a problem since the iOS 8 update, right now my app is connected to a BLE device and periodically reads the RSSI thanks to a timer and the ReadRSSI method.

The readRSSI method is called (checked with a breakpoint) so until this point everything is fine.

According to the documentation calling the readRSSI should trigger the callback

- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error

However, this delegate method is not called every time. But when I toggle the phone bluetooth off and on, I get back the RSSI updates. Has anyone already encountered this problem? How can i manage to fix it?

like image 339
M to the K Avatar asked Sep 26 '14 13:09

M to the K


3 Answers

I got the same problem, first thought it might be my fault, but later it turns out to be really weird.

I wrote similar program, using iPhone to connect to a BLE beacon, and use [CBPeripheral readRSSI] to get the signal strength. Everything goes smooth when the BLE beacon is connected to my iPhone for the first time. But if it got disconnected, and reconnect again, the method readRSSI won't get called any more. Only after I restart the bluetooth on my iPhone, the issue will be resolved.

I run the program in debug mode, step by step, to my surprise, I found no problem at all. Even I disconnect for so many times and reconnect again, the method readRSSI can still be called properly.

Hope this may help. I am also waiting for an answer for this strange thing.

like image 79
Tom Ou Avatar answered Sep 20 '22 13:09

Tom Ou


I recently ran into this issue and I had multiple issues that was causing it. Here's the solutions in checklist fashion, from simplest to most complex:

  1. The CBCentralManager won't hold a strong reference to the peripheral, you need to keep it yourself.
  2. Make sure you actually are the peripheral.delegate.
  3. Make sure you're implementing the new method peripheral(peripheral:didReadRSSI:error:) and not the old one.
  4. iOS 8.0.2 introduced issues with the above method, any version after that 8.1, 8.2, 8.3, works without problems (What @Gamma-Point was mentioning).
  5. You can only readRSSI for devices that are connected to your central, so:
    1. For devices that retrieved by discovery, you can pass [CBCentralManagerScanOptionAllowDuplicatesKey : true] when doing scanForPeripheralsWithServices(_:options:). As seen in this answer.
    2. Also, there's a gotcha with the method central.retrieveConnectedPeripheralsWithServices. this method returns "connected" devices, but the readRSSI nor service discovery work until you actually call connectPeripheral(_:options:) on them, so even though they are connected to the iPhone/iPad/AppleWatch, they are not connected to your central, very annoying.

This last one was the big gotcha for me, I was hoping to "pick the closest" connected or discovered device, but couldn't keep the RSSI updated on them. Documentation doesn't say anything either.

What I ended up doing, was to build a big dictionary with all the devices indexed by [UUID : Device] (device being a wrapper for the CBPeripheral). Devices added via discovery get their RSSI updated via de discover method, and the connected ones via a GCD timer on the bluetooth queue that calls readRSSI and update their own RSSI reading.

like image 38
Can Avatar answered Sep 18 '22 13:09

Can


I have 8.0, it's working fine.

-(void) startScanForRSSI{

    timerRSSI = [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(detectRSSI) userInfo:nil repeats:YES];

}

- (void)detectRSSI {

    if (state == ...) {
        peripheral.delegate = self;
        [peripheral readRSSI];
    } else {
        if (timerRSSI && [timerRSSI isValid])  {
            [timerRSSI invalidate];
        }
    }
}



- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error {



    NSLog(@"Got RSSI update: %4.1f", [peripheral.RSSI doubleValue]);


    NSNumber *rssiNum = peripheral.RSSI;
}

Since above is deprecated in iOS 8, trying the other delegate, will report back.

-(void) peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error {
     NSLog(@"Got RSSI update in didReadRSSI : %4.1f", [RSSI doubleValue]);
}

This seems to be an OSX delegate method. Apple will probably add something soon in iOS for RSSI.

In iOS 8.0 didReadRSSI is working. In 8.0.2 documentation it is not listed under iOS.

If I put both methods didReadRSSI gets called in iOS 8 & peripheralDidUpdateRSSI gets called in iOS 7.

So don't update to iOS 8.0.2 until Apples puts something for RSSI.

Did anyone try iOS 8.1 beta?

Looks like when scanning for devices the RSSI can't be read. If the call to [CBCentralManager scanForPeripheralsWithServices...] has been initiated no effect of ReadRSSI occurs (no delegates are called). But if the [CBCentralManager stopScan] is issued the ReadRSSI starts responding.

Also note: the device has to be in connected state to issue commands otherwise you will get: CoreBluetooth[API MISUSE] CBPeripheral can only accept commands while in the connected state.

like image 22
Gamma-Point Avatar answered Sep 20 '22 13:09

Gamma-Point