I need to get the list of paired bluetooth devices(iOS Devices) as same as the list in 'Bluetooth' section in iOS settings as shown in below picture.
Is it possible?
Have you seen any apps doing this type of functionality?
I have tried the following:
link1, link2, link3, link4, link5, link6
But nothing helped me clearly to get the exact list. I hope there should be a way to achieve this. Please help me by sharing your experience.
Thank you.
It's not possible to retrieve list of paired peripherals from iOS. Neither it's possible to check if specific peripheral is paired.
Retrieving peripheral which is paired
There are two cases which you need to consider:
Peripheral may be already connected in the system (iOS connects automatically with some peripherals in order to for example display battery level). In this case peripheral won't be broadcasting and detection using scanForPeripherals won't work.
Peripheral is paired, but disconnected. In this case retrieveConnectedPeripherals(withServices:) won't work.
Therefore to retrieve your peripheral you need to combine both things. First you need to check if it's in peripherals returned from retrieveConnectedPeripherals(withServices:). If not you should scanForPeripherals.
If you want to retrieve peripheral which is out of range, you can try to use retrievePeripherals(withIdentifiers:), however it may return also not paired devices and it relies on peripheral's UUID which you have to save after pairing.
Detecting if peripheral is paired
There is one way to detect if the specific peripheral is paired. You need to try to read from protected characteristic (which requires encryption - bonding). If you receive expected data, it means that user accepted pairing request. Otherwise you will receive empty response or none.
References
You can read more about Bluetooth in my articles:
Original answer
Swift – Bluetooth Low Energy communication using Flow Controllers
How to communicate with Bluetooth Low Energy devices on iOS
Bluetooth Low Energy – background mode on iOS
You can use ShowBluetoothAccessoryPicker if you are using the Classic Bluetooh into an MFi device.
https://developer.apple.com/documentation/externalaccessory/eaaccessorymanager/1613913-showbluetoothaccessorypicker
The code below is a C# but you can easily convert it into the IOS (object c your swift)
EAAccessoryManager.SharedAccessoryManager.ShowBluetoothAccessoryPicker(null, completion: ((Foundation.NSError error) => {
Console.WriteLine("My callback");
if (error != null && (uint)error.Code != (uint)EABluetoothAccessoryPickerError.AlreadyConnected)
{
Console.WriteLine(String.Format("Error code: {0} Desc: {1}", error.Code, error.DebugDescription));
Console.WriteLine("Failed? " + EABluetoothAccessoryPickerError.Failed.ToString());
Console.WriteLine("Failed? " + Convert.ToInt64(EABluetoothAccessoryPickerError.Failed));
}
}));
You need to find the service UUID in which you are interested, in my case it works perfectly,
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.centralManager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:SERVICE_UUID]]
options:options];
and when it will find any device which advertise same service UUID, then it will appear in the screen which you have pointed above.
handle didDiscoverperipherel in this way:
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
_discoveredPeripheral = peripheral;
if(![self.mRemoteDevices containsObject:_discoveredPeripheral])
{
NSArray *peripherels = [self.centralManager retrievePeripheralsWithIdentifiers:#[_discoveredPeripheral.identifier]];
[self.mRemoteDevices addObject:[peripherels objectAtIndex:0]];
}
}
Related
I have a fitness app that can connect to Bluetooth LE heart rate monitors. I've had no problem with it for the last few years. Now I'm updating it for iOS 10, and something strange is happening. If I scan for peripherals like this...
- (id)init {
self.heartRateService = #"180D";
self.heartRateKey = #"2A37";
self.allServices = [NSArray arrayWithObjects:[CBUUID UUIDWithString:self.heartRateService], nil];
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)startScanning {
if (self.centralManager.state == CBCentralManagerStatePoweredOn) {
[self.centralManager scanForPeripheralsWithServices:self.allServices options:nil];
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
DLog(#"found peripheral: %#", peripheral);
DLog(#"advertisementData: %#", advertisementData);
DLog(#"RSSI: %#", RSSI);
}
...it can't find the heart rate monitor -- the scan starts but didDiscoverPeripheral is never called. If I try competitor app #1, it finds and displays data from the HRM, but if I quit it and return to my app, my app still can't find the HRM. If I try competitor app #2, it finds and displays data from the HRM, and if I quit it and return to my app, then my app connects immediately and works as expected. It seems like competitor app #1 has a different way to find the HRM, while competitor app #2 does something to not only find the HRM, but let my app find it afterwards. Although this scenario seems strange, it is 100% reproducible.
I can make two guesses about what's happening:
1) Competitor app #2 enables some setting on the HRM that allows it to be found. But I don't think this is possible because I think communication with a BTLE accessory is one way.
2) iOS 10 has some kind of privacy setting that is disabled by default, but competitor app #2 enables it, allowing my app to see the HRM afterwards.
Does this make any sense, or does anyone have a theory about what's wrong?
How to can I get all available features from my device using Core Bluetooth.
I figured that before get any information we need to observe all devices via low energy bluetooth.
So the first step is scan for all peripheral devices scanForPeripheralsWithServices via CBCentralManager. In the delegate callback:
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI
we can save peripheral identifier and save peripheral to handle it in future like change some characteristics, switch off/on and etc.
But my question how to get description of this function, for example I got some characteristic, but I don't know how to use. Where to find info about this future.
Let me describe situation. For example I have sound player with some options where I can handle volume of sound via bluetooth.
So I need to get peripheral first, then detect service and then discover characteristic to find volume "property", but how can I find it, how should I understand which is min/max amount of volume where to find this information. For example we can pass 0 as min volume amount and 1 as a max. But it also could be in range from 0 to 1000 or any other. How to detect this information?
You can't be sure to find the "documentation" for each characteristics, like what are the possible values, etc.
If the Services & the Characteristics follow the documentation of Bluetooth, and are per se "documented", it just follow the doc, it's here. In theory, theses "well known" services and characters should have an UUID like "0x0000".
Example: Battery service is 0x180F, Battery Level is 0x2A19 and the possible values have a defined protocol.
For other custom services/characteristics, it's more difficult. Each one has their own documentation, and the UUID is longer (if it's developed respecting the rules).
If set, you can read the CBDescriptor to get more info.
In all case, you have to either refer to the Bluetooth Low Energy Documentation, or if it's custom to the manufacturer. Either wise, it's all about reverse-engeenering.
You can refer this Demo Project here.
With the following snippet you can get all characteristics, services associated with any iOS supported peripheral.
BabyBluetooth *objBluetooth = [BabyBluetooth shareBabyBluetooth];
objBluetooth.scanForPeripherals().begin();
You can set Delegate call-backs in this manner.
-(void)babyDelegate{
//If any peripheral discovered
[objBluetooth setBlockOnDiscoverToPeripherals:^(CBCentralManager *central, CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) {
NSLog(#"搜索到了设备:%#",peripheral.name);
}];
//Set the filtration criteria for the bluetooth peripherals
[objBluetooth setFilterOnDiscoverPeripherals:^BOOL(NSString *peripheralName, NSDictionary *advertisementData, NSNumber *RSSI) {
//if ([peripheralName hasPrefix:#"Pxxxx"] ) {
// return YES;
//}
//return NO;
if (peripheralName.length >1) {
return YES;
}
return NO;
}];
//and so on.
}
Once peripheral filtered , you can get it from the array and then use this:
objBluetooth.having(peripheralFromArray).then.connectToPeripherals().discoverServices().discoverCharacteristics().begin();
[_channelForaD40 setBlockOnDiscoverCharacteristics:^(CBPeripheral *peripheral, CBService *service, NSError *error) {
//get your characteristics description here
}];
[_channelForaD40 setBlockOnReadValueForCharacteristic:^(CBPeripheral *peripheral, CBCharacteristic *characteristics, NSError *error) {
//Read the values of your characteristics here
}];
then, you can finally compare your characteristics with Bluetooth standards.
I have been reading a lot of posts here on the forum and I saw quite a few relating to my case. However I still don't have the clarity that I was looking for.
I want to connect to two CBPeripherals and to write data to both of them. From what I have read, I have the idea that before connecting to a second device I have to disconnect the current peripheral. Okay, so suppose I were to write a command onto one of the peripherals and then I want to write another command to the other one, will I have to disconnect from the current peripheral? If I did disconnect to connect to the other, will the previous command still hold effect? What are the best practises for this on iOS?
my bluetooth friend, first of all it isn't necessary to disconnect current Peripheral to connect another if u want to send both messages. But many apps limit number of connected devices(CBPeripheral) to 5 - 10, because more than 5-10 connected devices, can spontaneously be lost, I know about it a little (I worked only with 4 devices). For example:
[[RKCentralManager sharedManager] scanForPeripheralsWithServices:nil options:#{CBCentralManagerScanOptionAllowDuplicatesKey:#NO} onUpdated:^(RKPeripheral *peripheral)
{
//first of all u should start a scan
[[RKCentralManager sharedManager] connectPeripheral: peripheral options:nil onFinished:^(RKPeripheral * connectedperipheral, NSError *error)
{
//after u can connect to Peripheral immediately
[connectedperipheral discoverServices:nil onFinish:^(NSError *error)
{
// services - a collection of data and associated behaviors for accomplishing a function or feature of a device
[connectedperipheral discoverCharacteristics:nil forService: [connectedperipheral.services lastObject] onFinish:^(CBService *service, NSError *error)
{
//after u should take a characteristic - Represents a service's characteristic
CBCharacteristic * characteristic = service.characteristics[0];
//and at last u can write value in characteristic in which you are going to write down something
NSData * data = [NSData dataWithHexString: newstring];
CBCharacteristicWriteType type = CBCharacteristicWriteWithoutResponse;
[connectedperipheral writeValue:data forCharacteristic:characteristic type:type onFinish:nil];
}];
}];
}];
}];
The approximate scheme of sending the message for bluetooth device, it isn't obligatory to do an investment of methods, they can be distributed on actions.
You shouldn't worry about connection and sendings data
to several devices because it is work for CBCentralManager, if U use it correctly.
CBCentralManager objects are used to manage discovered or connected remote peripheral devices (represented by CBPeripheral objects), including scanning for, discovering, and connecting to advertising peripherals.
You can connect at once some devices and send them messages, and all be ok.
If you have questions, will try to answer.
This is good example, u can see how its work : https://github.com/ruiking/ble
About max count of devices https://stackoverflow.com/a/17282862/4912496
I have to access heart rate from Fitbit Surge Device , its give four services are with -
UUID - 180a (work fine for Device Information)
UUID - 180f (work fine for Battery)
UUID - 558dfa00 4fa84105 9f024eaa 93e62980
UUID - adabfb00 6e7d4601 bda2bffa a68956ba
I have to set [peripheral setNotifyValue:YES forCharacteristic:c], with [CBUUID UUIDWithString:#"ADABFB01-6E7D-4601-BDA2-BFFAA68956BA"] didUpdateNotification: are <CBCharacteristic: 0x17dc6bb0, UUID = ADABFB01-6E7D-4601-BDA2-BFFAA68956BA, properties = 0x12, value = (null), notifying = YES>.
But value is nil.
Please help me or any suggestion .
I know it's been a few months since you asked, but in case you're still wondering (or anyone else is), you're probably receiving a nil because Fitbit does not expose its data over Bluetooth. There's a discussion stating this on the Fitbit developers forum here: https://community.fitbit.com/t5/Web-API/Where-is-the-Bluetooth-SDK-Can-my-app-communicate-directly-with-the-Fitbit/td-p/324384
If you scroll through the posts, you'll see that Fitbit still does not have plans to expose data over Bluetooth, because they believe it will adversely affect the battery.
I'm trying to mesure RSSI indicator on iOS (6 with BLE) from several bluetooth peripheral.
I can get RSSI with scanForPeripheral :
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[_manager scanForPeripheralsWithServices:nil
options:options];
coupled with:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
this works but I have no control on the rate of packets receive and the result seems uncertain.
I've read : https://stackoverflow.com/a/12486927/270209 but my rate is not close to 100ms at all (more 1~2 seconds)
If I'm connected to the device the result with readRSSI seems more reliable.
I'm looking for a way to "stimulate" peripherals for more frequents updates in scan mode or a way to connect to more than one peripheral at a time.
Thanks
Edit : I've also tried to start / stop scan quickly, it seems that at start scan detects more devices and updates are more frequent
I'm sure you've already figured this out but just in case someone comes across this (like I just did) looking for other info, if you're not using other iOS devices with coreLocation you need to call the peripheralDidUpdateRSSI: delegate using [self.myPeripheral readRSSI];.
You can call for RSSI data updates in didUpdateValueForCharacteristic: as often as you like once in the updateValue delegate.
You don't need this in viewDidLoad:
NSDictionary *options = etc... This NSDictionary is created in the didDiscoverPeripheral: delegate.
So the overall flow would be:
Check that you are receiving RSSI in the NSLog where you obtained the RSSI data...
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if ([localName length] > 0){
NSLog(#"Discovered: %# RSSI: %#", peripheral.name, RSSI);
// your other needs ...
}
Call peripheralDidUpdateRSSI: here since this is where updates will occur continuously if you've set notify value to YES [peripheral setNotifyValue:YES forCharacteristic:characteristic];
- (void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
//Call the peripheralDidUpdateRSSI delegate ..
[self.myPeripheral readRSSI];
// do all of your other characteristic value updates here
}
readRSSI will call the delegate where you perform your RSSI updates on your UILabel (or whatever you're using) every time you update the previous characteristics values:
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error;
{
_rssiLabel.text = [self.myPeripheral.RSSI stringValue];
NSLog(#"RSSI Method”);
}
If you don't need characteristic values for your app just run a loop in there with whatever timing you need the RSSI value to refresh.
(Assuming you're on an iOS device:) CoreBluetooth is likely deliberately limiting the rate at which it's active on the antenna. Bluetooth LE, Bluetooth Classic, and Wi-Fi are all on the same antenna on iOS devices, so the radios try to keep unnecessary chatter to a minimum. You could try filing a bug on CoreBluetooth to add an option or way to control the update frequency, but I don't imagine they'll implement it, as their primary design goals are to: 1. Not drain the device's battery unnecessarily and 2. Co-exist with the other antenna's radios. (They've also said in posts on the Apple devforums that, for example, if you want a higher data rate than the iOS BTLE implementation, you should use Bluetooth Classic or something that's been designed for it. BTLE is meant to be low-power first and foremost, and they've taken that to its logical end.)
Indeed, the delay between peripheral.readRSSI() and peripheralDidUpdateRSSI is like a second!
I think the best way is to read the RSSI value on the BLE device itself and send it to the iOS device.
The peripheral advertises based on the firmware of the peripheral. This can be set from as low at 100ms to almost as high as 2 seconds.
When using an iOS device as a Bluetooth Peripheral, I have found no way of changing it.
Here is Apples documentation: Look in section 3.5...
https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf