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?
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.
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:
- The
CBCentralManager
won't hold a strong reference to the peripheral
, you need to keep it yourself.
- Make sure you actually are the
peripheral.delegate
.
- Make sure you're implementing the new method
peripheral(peripheral:didReadRSSI:error:)
and not the old one.
- 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).
- You can only
readRSSI
for devices that are connected to your central, so:
- For devices that retrieved by discovery, you can pass
[CBCentralManagerScanOptionAllowDuplicatesKey : true]
when doing scanForPeripheralsWithServices(_:options:)
. As seen in this answer.
- 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.
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.