I have a BLE device that I connect with my application. I have managed to auto-connect to it the first time the application is used and I have also managed to make the application work if the device gets turned off and then on again. BUT the last one works only if the device gets turned off for like less than 20-30 minutes.
If I turn on the device in less than 30 minutes the application will reconnect to it automatically and read its data. But after 30 minutes although when I turn on the device it appears to reconnect to the iPhone, the application does seem to reconnect to it and read data.
Any suggestions, hints or tips? Thank you all in advance.
EDIT: adding some code as requested
/*
Invoked whenever an existing connection with the peripheral is torn down.
Reset local variables
*/
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)aPeripheral error:(NSError *)error
{
self.connected = NO;
if( self.peripheral )
{
[self.peripheral setDelegate:nil];
self.peripheral = nil;
}
[self.centralManager scanForPeripheralsWithServices:#[myService] options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
}
Related
I currently experience issues with Bluetooth reconnects. I am writing an app which uses a BLE device (HID device) to unlock the motorbike. I want the App to reconnect to the device as soon as it comes into range.
The flow the app does:
Scan and bond with device
Communicates with device
When device is out range, call centralManager.connect().
Wait for didConnect or didFailToConnect to be called.
Most of the time, it works well, but there are some cases that the app never get a didConnect or didFailToConnect, and the only way to reconnect to the device is to kill the app and open it again.(so it's not a hardware issue, it works perfectly with android)
What I do:
Keep a strong reference to all peripherals.
Set the delegate of all peripherals to our singleton bluetooth manager
Only connect with one device per time
The first connect always works, but then it randomly can not re-connect
CentralManager is running with a custom queue:
dispatch_queue_t queue = dispatch_queue_create("com.ble.queue", 0);
centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:queue options:options];
In didDisconnect I reconnect to device
(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error
{
[centralManager connectPeripheral:peripheral options:nil];
}
Is there anything I can do to fix it?
I'm trying to connect to Peripherals of a BlueTooth LE device with a simple ( very similar to an Hello World ) OSX App.
I'm following Apple's Guide Lines , but when i try to connect to a Peripheral my app does not work as expected.
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(#"Discovered %#", peripheral.name);
if([peripheral.name isEqualToString:#"BLE-DEVICE"]){
NSLog(#"Found BLE Device!");
[_centralManager stopScan];
NSLog(#"Scanning stopped");
peripheral.delegate = self;
[_centralManager connectPeripheral:peripheral options:nil];
}
}
The problem is that connectPeripheral (last line) does not trigger the centralManager:didConnectPeripheral method of the delegate object, but if i run a step by step debug with a simple break point it does.
Should i add some other scan options? How can i check if connection is rightly performed?
Try to wait for the event that tells you scanning has indeed stopped. Then, connect to the Peripheral. Maybe the iOS BLE stack doesn't have enough time to stop the scanning and when it tries to connect it fails because it has not yet reached "idle" state.
That explains why it works when debugging step by step: after stopScan is executed and before you manually execute connectPeripheral, there's enough time for the LE Controller to process the first command.
Although in a normal stack architecture, the messages should be queued.
EDIT: Alternatively, add a short delay of a few milliseconds between the two stack calls.
I am currently working on an app that gets data from a BLE device – similar to a heart monitor. The app reads the data from the device and then when it gets a specific amount of data, it creates a .csv file and uploads it into a server. Everything works fine, except when the device gets out of the range. The app just stop receiving data and doesn’t recognize that the connection is lost. I don’t get any error message. The app just stops in the middle of the “getting data” loop and keeps waiting for a data that never comes. When the device is back in the range, nothing happens.
I would like to show an alert informing that the BLE device is out of the range. When the device is in the range again, the app should reconnect to it automatically and then continue reading data from the device. How can I implement that? I tried to get the CM state – using the function below – but it didn’t work.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
printf("Status of CoreBluetooth central manager changed %d (%s)\r\n",central.state,[self centralManagerStateToString:central.state]);
}
I’ve even tried to add an if clause inside the loop to check the device state, but it didn’t work also.
I am using the Texas instruments chip CC2540.
As suggested by Paulw11 and SJoshi (Thank you guys), I had to implement the didDisconnectPeripheral method. So, here is how I did it:
.h file:
// will be invoked once disconnected
-(void)centralManager:(CBCentralManager *)central
didDisconnectPeripheral:(CBPeripheral *)peripheral
error:(NSError *)error;
.m file:
-(void) centralManager:(CBCentralManager *)central
didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
[central connectPeripheral:peripheral options:nil];
// you can add whatever you want here.
// will execute when the peripheral loose its connection.
}
I have a BLE device that I am writing an app to pair with. I can discover and connect to the device with no problems. But if I am connected and pull and reinsert the battery on the BLE device I get the didDisconnectPeripheral callback but I never get another didConnectPeripheral even though I'm still scanning. I also tried calling retrieveConnectedPeripheralsWithServices and retrievePeripheralsWithIdentifiers but neither of those return anything.
How can I reliably reconnect after cycling the power on my BLE device?
As soon as the peripheral disconnects you can issue another connect - iOS will automatically reconnect to the device once it is visible again and call your didConnectPeripheral: delegate method
-(void) centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(#"Disconnected from peripheral");
[central connectPeripheral:peripheral options:nil];
}
There is no need to rescan/re-discover the peripheral.
You may want a more comprehensive implementation that updates UI etc.
Here is some sample code that connects to a peripheral and displays the vendor information -
https://github.com/paulw11/BTBackground
I'm working on BLE device named WIRELESS BLOOD PRESSURE WRIST MONITOR.
I've downloaded these application and every thing is working great.
But when I tried to connect to the device from my application, I didn't receive a response.
and my code is straight like the code from developer.apple.com and also this tutorial.
This is my code:
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[_centralManager scanForPeripheralsWithServices:nil options:nil];
I receive notification on the delegate for centralManagerDidUpdateState but I don't receive the didDiscoverPeripheral even if I'm searching with nil in services.
When I go to Setting -> Bluetooth: I can see the device and it is connected and the signal of bluetooth is on. So the iPhone can see the BLE device, So when I used in my code these method
retrieveConnectedPeripheralsWithServices to get the list of connected device it returns 0 object.
So I don't know what is the problem, keeping in mind that the BLE device is working great with there own app so it's Low Energy not classic , and the BLE device display bluetooth signal when opening the app.
So any ideas from the GEEKS :D
Thanks..
There are lots of pieces you need to take care of:
You need to wait for the centralManagerDidUpdateState to indicate CBCentralManagerStatePoweredOn. Anything you do before will either result in error or be ignored. So your call to scanForPeripheralsWithServices is probably ignored. This is true for other APIs, like the retrieveConnectedPeripheralsWithServices you mentioned.
It is also possible that the device turns off advertising after it is connected, so your scanning will not succeed until you disconnect from it.
Scanning in the background has many limitations. You can search the SO questions to find out the details. In the beginning I would advise you to not to try backgrounded operation as it can be really tricky.
Instead of searching immediately after initializing the central manager, try first to wait for update that the power is on.
Try these steps:
In viewDidLoad remove the call to scanForPeripheralsWithServices
Add method scanForPeripherals, that will first check the Central Manager is powered on and also check for the scanning state (see below).
code:
- (void)scanForPeripherals {
if (self.centralManager.state != CBCentralManagerStatePoweredOn) {
NSLog(#"CBCentralManager must be powered to scan peripherals. %d", self.centralManager.state);
return;
}
if (self.scanning) {
return;
}
self.scanning = YES;
[self.centralManager scanForPeripheralsWithServices:nil options:#{ CBCentralManagerScanOptionAllowDuplicatesKey: #YES }];
NSLog(#"Scanning started");
}
In ViewWillAppear call [self scanForPeripherals]
In centralManagerDidUpdateState, call scanForPeripherals only if central manager is powered on.
code:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
if (central.state != CBCentralManagerStatePoweredOn) {
NSLog(#"CBCentralManager not powered on yet");
return;
}
// The state must be CBCentralManagerStatePoweredOn
[self scanForPeripherals];
}
Add BOOL property scanning. Using the scanning propery allows you to safely try and scan before the update callback called. You should handle the scanning state to prevent calling scan twice.