How to get UUID from LE Bluetooth chip? - ios

I have a chip, working on LE Bluetooth and transmitting it's UUID.
I need to discover it from IOS app and get it's UUID.
I know how to establish a connection between two IOS devices, but not with another chips.
Thanks!

You should check out Apple's CoreBluetooth Temperature Example.
First you will use the CBCentralManager to find the available Bluetooth Peripherals with the UUID you are looking for. It's a lengthy process that requires delegates and I can't easily give you code snippets to do this. It will look something like this.
.h file will have these. Remember to add the CoreBluetooth Framework.
#import <CoreBluetooth/CoreBluetooth.h>
CBCentralManager * manager;
CBPeripheral * connected_peripheral;
(Change your UUID accordingly):
NSArray * services=[NSArray arrayWithObjects:
[CBUUID UUIDWithString:#"0bd51666-e7cb-469b-8e4d-2742f1ba77cc"],
nil
];
[manager scanForPeripheralsWithServices:services options: [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey]];
[manager connectPeripheral:peripheral options:nil];
From there you know you have the right peripheral, but you still need to select it and stop the CBManager from continuing to scan for new devices.
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
[manager stopScan];
NSArray *keys = [NSArray arrayWithObjects:
[CBUUID UUIDWithString:#"0bd51666-e7cb-469b-8e4d-2742f1ba77cc"],
nil];
NSArray *objects = [NSArray arrayWithObjects:
#"My UUID to find",
nil];
serviceNames = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
[connected_peripheral setDelegate:self];
[connected_peripheral discoverServices:[serviceNames allKeys]];
}
Now that you have told your peripheral to advertise what services it has, you'll have a delegate for parsing those services.
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
CBService *bluetoothService;
for (bluetoothService in connected_peripheral.services) {
if([bluetoothService.UUID isEqual:[CBUUID UUIDWithString:#"0bd51666-e7cb-469b-8e4d-2742f1ba77cc"]])
{
NSLog(#"This is my bluetooth Service to Connect to");
}
}
I wish this process was easier to explain. The best way to figure it out is to download Apple's Temperature Example and run it on your iPhone or iPad (it won't work in the simulator). Even though you probably aren't broadcasting temperature it will find your Bluetooth LE device and will parse through the services it is broadcasting. Placing breakpoints in the LeDiscovery.m file of that project should show you the steps needed to discover your Bluetooth LE chip from an iOS app.
Hope this helps!

Related

BLE background reconnect

I want to reconnect to BLE device after device is moved out/terminated by user or system/reboted in background mode.
I know that it's possible : - see this question with description
Question - How can i setup centralManager for automatically reconnect to peripheral in background mode if app was terminated? Can someone describe step-by-step how it can be done?
Few word about current implementation:
I create centralManager with options like:
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:#{
CBCentralManagerOptionRestoreIdentifierKey: #"myCentralManagerIdentifier",
CBCentralManagerRestoredStatePeripheralsKey : #YES,
CBCentralManagerRestoredStateScanServicesKey : #YES,
CBCentralManagerRestoredStateScanOptionsKey : #YES
}];
After that i start to scan for BLE device
[self.centralManager scanForPeripheralsWithServices:[self discoverableCharacteristics] options:nil];
in - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI i connect to peripheral:
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
[self.centralManager stopScan];
peripheral.delegate = self;
[self.centralManager connectPeripheral:peripheral options: #{
CBConnectPeripheralOptionNotifyOnNotificationKey : #YES
}];
After that i can discover services and characteristics - all looks like ok. When i discover characteristic and read/write data i cancelPeripheralConnection
in didDisconnect i reconnect to device
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error
{
[central connectPeripheral:peripheral options:nil];
}
i also implement centralManager:willRestoreState: like:
NSArray *peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey];
for (CBPeripheral *peripheral in peripherals) {
[central connectPeripheral:peripheral options:nil];
peripheral.delegate = nil;
}
In plist. added required key App communicates using CoreBluetooth.
Currently if i connected to device and terminate it - it relaunch automatically and connect to device - all it's ok, but if it's terminated again - nothing is happening.
Also if i moved out from peripheral and that come back - nothing happened.
Update
regarding point 5 - my fall - should use this key with connectPeripheral
in WillRestoreState:
NSArray *peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey];
if (!peripherals.count) {
peripherals = [central retrievePeripheralsWithIdentifiers:[self discoverableCharacteristics]];
}
if (peripherals.count) {
for (CBPeripheral *peripheral in peripherals) {
[central connectPeripheral:peripheral options:#{
CBCentralManagerRestoredStatePeripheralsKey : #YES,
CBCentralManagerRestoredStateScanServicesKey : #YES,
CBCentralManagerRestoredStateScanOptionsKey : #YES
}];
}
} else {
[self startScanning];
}
Current result - app will relaunched if it not swiped out from tray. I use my mac as a peripheral, so some times when i not launch app that make role of peripheral central can connect to mac itself not to required service.
Another question - are it's good option to reconnect to peripheral while lost connection for keeping connection like:
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error
{
[central connectPeripheral:peripheral options:#{
CBCentralManagerRestoredStatePeripheralsKey : #YES,
CBCentralManagerRestoredStateScanServicesKey : #YES,
CBCentralManagerRestoredStateScanOptionsKey : #YES
}];
}
Also try to change notify characteristic on peripheral and read it on device. If all done in foreground - all works perfect, but in case connection was done in background some times didUpdateValueForCharacteristic not called at all, but didUpdateNotificationStateForCharacteristic is called with no error - this mean (i think) that something was done wrong by my side. Maybe u can advice where problem can be
And one more question - is there is some restriction in writing data to characteristics? because in apple sample it's setuped to 20 bytes.
First off I wanna start by saying that I have been working with CoreBluetooth for about two years now and from what I have noticed CoreBluetooth State Preservation and Restoration does not work reliably at all. You can get it working sort of "ok", but you will never get it to reconnect reliably unless Apple fixes it some day.
Having said that, I want to note a few things on your setup.
1) In centralManager:willRestoreState: you can only retrieve peripherals that has done any communication while the app was terminated. This means that you should also implement centralManagerDidUpdateState: and if the state is CBCentralManagerStatePoweredOn then you can use the retrievePeripheralsWithIdentifiers: method to retrieve the other peripheral and reset their delegate as well. This of course means that you have to stor the peripheral identifiers somewhere in your app somewhere. Also remember to reset pending connections here as well.
2) You set the delegate to nil in centralManager:willRestoreState:! So even if it does connect then you will not know about it i:P
3) Your app will only get relaunched if the app was terminated by the system. It will not get relaunched if you manually swipe-kill it from the application list. Neither will it get relaunched if the device is rebooted, unfortunately.
4) The CBConnectPeripheralOptionNotifyOnConnectionKey is not necessary when using the bluetooth-central background mode and is just annoying for a user so I would not use it.
5) CBCentralManagerRestoredStatePeripheralsKey, CBCentralManagerRestoredStateScanServicesKey, CBCentralManagerRestoredStateScanOptionsKey are not valid initialisation options so I don’t get why you are using those..
5) If the bluetooth switches state while the app is terminated then all pending connections will be lost and you will not be relaunched to know about it. This on its own effectively means that State Restoration is rather useless.
Anyhow, I am sad to say it, but if you are developing an app that must rely on the peripheral being reconnected in the background then I wold not recommend doing it. You will be frustrated. I could probably write an essay about all the bugs in Core Bluetooth that Apple does not want to fix. Even more frightening is that you can pretty easily ruin the bluetooth connectivity globally on the device from one single app so that no app can use bluetooth until the device is rebooted. This is pretty bad since it goes against Apples own Sandboxing principle.
If you need any more help, just let me know!
/A

iPhone can't communicate to paired bluetooth low energy device

I have got an iPhone problem. Step by step my problem:
I discover, connect and pair (bond) my iPhone to BLE device.
After some characteristic communication I manually leave the app and disconnect.
PROBLEM. When I try to pair and communicate again it is impossible because iPhone shows "connected" or either "not
connected" to device in "my devices" section in settings. When I try
to search for devices in app iPhone can't find anything because
iPhone acts like the device is already found.
How to solve this problem? Because now the only way is to forget the device in settings (delete from "my devices" manually) and only then it is possible to pair and connect..
EDIT:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
if (central.state == CBCentralManagerStatePoweredOn) {
[self scanForPeripherals];
}
}
- (int)scanForPeripherals {
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], CBCentralManagerScanOptionAllowDuplicatesKey,
nil];
//NSLog(#"%#",#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]);
[self.centralManager scanForPeripheralsWithServices:nil options:options];
return 0;
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(#"didConnectPeripheral");
// Clear the data
[self.data setLength:0];
// Discover callbacks
peripheral.delegate = self;
[peripheral discoverServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
}

Bluetooth Low Energy Peripheral communicate with iPhone SDK

I have one Bluetooth LE device, I need to scan it only, that I have done with Core Bluetooth Framework in iPhone SDk.
Below is sample code,
manager is object of CBCenterManager which writes in the init method:
manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
scanning process:
- (void)startScan
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
manager.delegate = self;
[manager scanForPeripheralsWithServices:nil options:options];
}
Now I got that device in delegate methods,
- (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);
}
**Here I have write only few lines of code,
This is not enough data for me to show in interface. Because peripheral.UUID is unique for each device, if I change device to discover BLE, it will be changed.
So I want unique address of Bluetooth LE device which I got same in every iOS devices.
Like peripheral.UUID is 1FE639DB-3C54-B5A8-74A4-3D9FBFCAD074
I had discover same thing in android got address like C8:4D:93:78:98:AE this.
and its unique for all android devices,
So I am searching for the same thing in iPhone SDK.
Is it possible to get same unique address of Bluetooth LE in iPhone SDK?
Thanks for your time to read questions.

How to get list of available Bluetooth devices?

I'm currently creating an iPhone app (Xcode 4.3.1, IOS 5) that could use Bluetooth devices! Main goal of this application is indoor navigation (GPS inside buildings isn't really accurate).
The only solution I see here (to keep my app on AppStore) is to try scan for available bluetooth devices!
I tried to use CoreBluetooth framework, but I don't get list of available devices!
Maybe I don't use these functions correctly
#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
#interface AboutBhyperView : UIViewController <CBPeripheralDelegate, CBCentralManagerDelegate>
{
CBCentralManager *mgr;
}
#property (readwrite, nonatomic) CBCentralManager *mgr;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
mgr = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog([NSString stringWithFormat:#"%#",[advertisementData description]]);
}
-(void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals{
NSLog(#"This is it!");
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
NSString *messtoshow;
switch (central.state) {
case CBCentralManagerStateUnknown:
{
messtoshow=[NSString stringWithFormat:#"State unknown, update imminent."];
break;
}
case CBCentralManagerStateResetting:
{
messtoshow=[NSString stringWithFormat:#"The connection with the system service was momentarily lost, update imminent."];
break;
}
case CBCentralManagerStateUnsupported:
{
messtoshow=[NSString stringWithFormat:#"The platform doesn't support Bluetooth Low Energy"];
break;
}
case CBCentralManagerStateUnauthorized:
{
messtoshow=[NSString stringWithFormat:#"The app is not authorized to use Bluetooth Low Energy"];
break;
}
case CBCentralManagerStatePoweredOff:
{
messtoshow=[NSString stringWithFormat:#"Bluetooth is currently powered off."];
break;
}
case CBCentralManagerStatePoweredOn:
{
messtoshow=[NSString stringWithFormat:#"Bluetooth is currently powered on and available to use."];
[mgr scanForPeripheralsWithServices:nil options:nil];
//[mgr retrieveConnectedPeripherals];
//--- it works, I Do get in this area!
break;
}
}
NSLog(messtoshow);
}
I'm not sure about this line, how to pass correct parameters?
[mgr scanForPeripheralsWithServices:nil options:nil];
I took a look into apple reference .. and I still don't understand what's that CBUUID ???
Every device has some bluetooth id? where can I find it?
- (void)scanForPeripheralsWithServices:(NSArray *)serviceUUIDs options:(NSDictionary *)options;
Parameters
serviceUUIDs - An array of CBUUIDs the app is interested in.
options - A dictionary to customize the scan, see CBCentralManagerScanOptionAllowDuplicatesKey.
Is there any other way to use Bluetooth on IOS? I mean, older frameworks that don't use BLE 4.0!
any advice would be appreciated!
thanks!
This guide looks promising for Bluetooth 3.0. Remember that the CoreBluetooth framework is ONLY for Bluetooth Low Energy (4.0). At bluetooth.com's dev-pages you can see some examples of globally defined services, and as Guan Yang mentionen, you can see that the heart rate service is 0x180D. UUID`s of the unit is defined by the manufacturer.
Here's a code snippet to maybe help you along the way.
// Initialize a private variable with the heart rate service UUID
CBUUID *heartRate = [CBUUID UUIDWithString:#"180D"];
// Create a dictionary for passing down to the scan with service method
NSDictionary *scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
// Tell the central manager (cm) to scan for the heart rate service
[cm scanForPeripheralsWithServices:[NSArray arrayWithObject:heartRate] options:scanOptions]
in Bluetooth, there are "Services". A device publishes 1..N services, and each service has 1..M characteristics. Each service has an unique identifier, called UUID.
For example, a heart rate Bluetooth Sensor that offers the service "heart rate", publishes a service with UUID 0x180D.
(more services here)
So when you perform a search, you must provide a UUID as the criteria, telling which service to search.
You should take a look at one of the examples. Here’s the relevant line:
[manager scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:#"180D"]] options:nil];
(I know this is a Mac OS X example, but the iOS CoreBluetooth API is very similar.)
CBUUID identifies services you are interested in, not devices. Standard services have a 16-bit UUID, in this case 0x180d for the heart rate monitor or perhaps 0x180a for device information, while proprietary services have a 128-bit UUID (16 bytes).
Most devices implement the device information service, so if you are just looking for any device, you could try [CBUUID UUIDWithString:#"180A"].
Try giving this while you are scanning for devices
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.centralManager scanForPeripheralsWithServices:nil options:options];
you will be able to get the list of devices at didDiscoverPeripheral delegate method
Keep calm and use https://github.com/l0gg3r/LGBluetooth
All you need to do
[[LGCentralManager sharedInstance] scanForPeripheralsByInterval:4
completion:^(NSArray *peripherals) {
}];

Core Bluetooth - constant RSSI updates of in-range devices

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!
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.
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.
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
Swift Implementation of #Anders solution:
manager.scanForPeripheralsWithServices(nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey : NSNumber(value: true)])

Resources