is it possible to configure a bluetooth-device in a way that my app automatically connects to it when near - without pairing etc.?
The device will be custom built and the app will be written by me, I first have to define some specs. It would be great if there's an option in the device that as soon as it's near my (opened) app that both are connected automatically without any setup process.
Sure you can. If the device will be custom made and you know its characteristics
Code below (TRANSFER_SERVICE_UUID - GUID of your device):
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// You should test all scenarios
if (central.state != CBCentralManagerStatePoweredOn) {
[self stop];
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
// Scan for devices
[_centralManager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
NSLog(#"Scanning started");
if(_delegate)
{
if([_delegate respondsToSelector:#selector(CB_changedStatus:message:)])
{
[_delegate CB_changedStatus:CBManagerMessage_ScanningStarted message:#"Scanning started"];
}
}
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered %# at %#", peripheral.name, RSSI);
if (_discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
_discoveredPeripheral = peripheral;
// And connect
NSLog(#"Connecting to peripheral %#", peripheral);
if(_delegate)
{
if([_delegate respondsToSelector:#selector(CB_changedStatus:message:)])
{
[_delegate CB_changedStatus:CBManagerMessage_ConnectingToPeripheral message:[NSString stringWithFormat:#"Connecting to peripheral %#", peripheral]];
}
}
[_centralManager connectPeripheral:peripheral options:nil];
}
}
Related
I am building an iOS application which connects to a Bluetooth device to turn some lights on and off. For these actions, I need to be paired with the device. There is also a battery service for which I do not. The situation where I connect the device for the first time (not paired before) it works like it supposed to work. I can connect when the device is in pairing mode, get a pair request and read/write the values. When I connect the device to an other device (Android in this case, but I don't think it matters much) and try to run the iOS application, it can connect to a device, discover services and the characteristics for those services, but it can't read/write those values.
The method [peripheral readValueForCharacteristic:characteristic]; isn't called when I try to read all characteristics. I also tried using the setNotifyValue method with no success. When I try to read only the battery service, it works, but when the other services are enabled (which I need to be paired for) it doesn't.
When I remove the device from the Bluetooth settings and run the application again, it works like the first time and does all the things it should. Even reconnecting the devices the next day.
The question is, how can I read/write those values again without removing the device in the settings screen? Can I remove the device in the application without requiring the user to go to the Bluetooth settings? Or is it something that has to be changed on the firmware of the device?
This is (part) of my Bluetooth logic:
- (void)changeState:(BluetoothState)state { if ([[self delegate] respondsToSelector:#selector(bluetoothChangedState:)]) [[self delegate] bluetoothChangedState:state]; }
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
switch ([central state]) {
case CBCentralManagerStateUnknown: { NSLog(#"centralManagerDidUpdateState:CBCentralManagerStateUnknown"); break; }
case CBCentralManagerStateResetting: { NSLog(#"centralManagerDidUpdateState:CBCentralManagerStateResetting"); break; }
case CBCentralManagerStateUnauthorized: { NSLog(#"centralManagerDidUpdateState:CBCentralManagerStateUnauthorized"); break; }
case CBCentralManagerStatePoweredOff: { [self changeState:BluetoothStateOff]; break; }
case CBCentralManagerStateUnsupported: { [self changeState:BluetoothStateUnsupported]; break; }
case CBCentralManagerStatePoweredOn: { [self changeState:BluetoothStateOn]; [central scanForPeripheralsWithServices:nil options:nil]; break; }
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
if ([[peripheral name] isEqualToString:#"Glasses"]) { // #TODO better check for glasses.
[[self bluetoothManager] stopScan];
[peripheral setDelegate:self];
[self setPeripheral:peripheral];
[[self bluetoothManager] connectPeripheral:peripheral options:nil];
}
return;
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
[peripheral setDelegate:self];
[peripheral discoverServices:nil];
[self setConnected:peripheral.state == CBPeripheralStateConnected];
if ([self isConnected]) [[self delegate] bluetoothDidConnect];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
for (CBService *service in [peripheral services]) {
[peripheral discoverCharacteristics:nil forService:service];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if ([[service UUID] isEqual:[CBUUID UUIDWithString:UID]]) {
for (CBCharacteristic *characteristic in [service characteristics]) {
if (![[characteristic UUID] isEqual:[CBUUID UUIDWithString:UID_UNKNOWN]]) {
[peripheral readValueForCharacteristic:characteristic];
}
}
} else if ([[service UUID] isEqual:[CBUUID UUIDWithString:BAS]]) {
for (CBCharacteristic *characteristic in [service characteristics]) {
[peripheral readValueForCharacteristic:characteristic];
//[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(#"peripheral didUpdateValueForCharacteristic:%#", [characteristic UUID]);
if ([[characteristic UUID] isEqual:[CBUUID UUIDWithString:UID_ENABLED_LEDS]]) [self getEnabledLEDs:characteristic];
else if ([[characteristic UUID] isEqual:[CBUUID UUIDWithString:BAS_BATTERY_LEVEL]]) [self getBatteryLevel:characteristic];
}
I have a bluetooth bracelet which connects to my iPhone 5s via Bluetooth; it comes with an App called Zeroner. Now I want to obtain the information from the connected and paired up bracelet without using the App. Here is what I attempted to do:
Setup CBCentralManager
Use retrieveConnectedPeripheralsWithServices: to obtain connected devices
Here is the code:
CBConnectedDevicesVC.h
#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import SERVICE_ID #"FB694B90-F49E-4597-8306-171BBA78F846"
#interface CBConnectedDevicesVC : UIViewController <CBCentralManagerDelegate, CBPeripheralDelegate>
#property (strong, nonatomic) CBCentralManager *centralManager;
#property (strong, nonatomic) CBPeripheral *discoveredPeripheral;
#end
CBConnectedDevicesVC.m
#import "CBConnectedDevicesVC.h"
#implementation CBConnectedDevicesVC
- (void)viewDidLoad {
[super viewDidLoad];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
NSArray* connectedDevices = [_centralManager retrieveConnectedPeripheralsWithServices:#[[CBUUID UUIDWithString:SERVICE_UUID]]];
for (CBUUID *uuid in connectedDevices) {
NSLog(#"Device Found. UUID = %#", uuid);
}
}
}
#end
For the above codes, I have to specify the service ID in SERVICE_UUID, which I don't know what the value of the bracelet is. Is there any alternatives to obtain the information from the connected bracelet?
UPDATE about test result of LightBlue App
After unpaired from Zeroner App and "Forget this Device" in Settings > Bluetooth > choose the device named "Bracelet-0366", LightBlue App discovers the device (finally!).
Here is the result screenshot:
I got several values here, but I'm not sure which values I should use.
Further Test Results:
If I put the UUID (starts with 4EFF) found in LightBlue into SERVICE_ID, no delegate is called with the above codes.
Another piece of code I tried is (obtained from Tut+ tutorial):
NSArray *serviceID;
#implementation CBCentralManagerViewController
- (void)viewDidLoad {
[super viewDidLoad];
serviceID = #[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
_data = [[NSMutableData alloc] init];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// You should test all scenarios
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
// Scan for devices
[_centralManager scanForPeripheralsWithServices:serviceID options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
NSLog(#"Scanning started");
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered %# at %#", peripheral.name, RSSI);
if (_discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
_discoveredPeripheral = peripheral;
// And connect
NSLog(#"Connecting to peripheral %#", peripheral);
[_centralManager connectPeripheral:peripheral options:nil];
}
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(#"Failed to connect");
[self cleanup];
}
- (void)cleanup {
// See if we are subscribed to a characteristic on the peripheral
if (_discoveredPeripheral.services != nil) {
for (CBService *service in _discoveredPeripheral.services) {
if (service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
if (characteristic.isNotifying) {
[_discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic];
return;
}
}
}
}
}
}
[_centralManager cancelPeripheralConnection:_discoveredPeripheral];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(#"Connected");
[_centralManager stopScan];
NSLog(#"Scanning stopped");
[_data setLength:0];
peripheral.delegate = self;
[peripheral discoverServices:serviceID];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:#[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service];
}
// Discover other characteristics
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (error) {
[self cleanup];
return;
}
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (error) {
NSLog(#"Error");
return;
}
NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
// Have we got everything we need?
if ([stringFromData isEqualToString:#"EOM"]) {
[_textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
[_centralManager cancelPeripheralConnection:peripheral];
}
[_data appendData:characteristic.value];
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
return;
}
if (characteristic.isNotifying) {
NSLog(#"Notification began on %#", characteristic);
} else {
// Notification has stopped
[_centralManager cancelPeripheralConnection:peripheral];
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
_discoveredPeripheral = nil;
//
[_centralManager scanForPeripheralsWithServices:serviceID options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #YES }];
}
With the above code, there are 2 constants defined TRANSFER_SERVICE_ID and TRANSFER_CHARACTERISTIC_ID. From the tutorial, the TRANSFER_SERVICE_ID should be set to the one starts with 4EFF and the TRANSFER_CHARACTERISTIC_ID should be set to 0xFF20 or FF20. However, this piece of code does not detect the bracelet at all, even though the bracelet is unpaired & disconnected. What did I miss this time?
Don't worry about the UUID that starts with 4EFF - this is the UUID of the device and will be different for each one.
The service id is FF20 - You can use this in scanForPeripheralsWithServices - this is SERVICE_ID in your code above.
Then you have two characteristics- FF21 and FF22
You can write to FF21 using the writeValue method on your CBPeripheral instance.
With FF22 that you can subscribe to notifications using the setNotify CBPeripheral method. You will then get a call to the didUpdateValueForCharacteristic CBPeripheralDelegate method whenever the device changes the value.
There are 2 types of bluetooth devices you can work with:
BLE devices - no need (often can't) to pair them with iPhone
"standard" bluetooth devices - you need to pair them with iPhone before use
Those two types are managed independently - from the way you described it I expect your bracelet to fall into "standard" category, and CoreBluetooth can only be used for BLE.
For working with already paired external accessories you should use ExternalAccessory framework
I have a connected & paired up Bluetooth LE bracelet (Service ID: FF20), which have 2 characteristics:
0xFF21 : Write without Response
0xFF22 : Notify
Now I try to write data via CoreBluetooth Framework to 0xFF21 with the following code:
I defined 2 constants at header file:
#define TRANSFER_SERVICE_UUID #"FF20"
#define TRANSFER_SERVICE_CHARACTERISTIC_UUID #"FF21"
.m
- (void)viewDidLoad {
[super viewDidLoad];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
NSArray* connectedDevices = [_centralManager retrieveConnectedPeripheralsWithServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
for (CBPeripheral *peripheral in connectedDevices) {
NSLog(#"Device Found. CBPeripheral = %#", peripheral);
peripheral.delegate = self;
if(peripheral.services.count == 0) {
NSLog(#"No service found");
}
for (CBService *service in peripheral.services) {
if(service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) {
// check notifying ?
NSData *data = [#"Testing" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
} else {
NSLog(#"Specific Characteristic Not found");
}
}
} else {
NSLog(#"Characteristic is NULL");
}
}
}
}
}
The log appears:
Device Found. CBPeripheral = <CBPeripheral: 0x1740f5080, identifier = 4EFF694C-017A-536F-9301-2EB2CC316CBE, name = Bracelet-0366, state = disconnected>
No service found
What did I miss?
You need to issue a connect to the discovered peripheral and get a call to your didConnectPeripheral delegate method before you can issue read/write requests.
When you reach the poweredOn state you should issue a scanForDevicesWithServices call, wait for the call back to your delegate, then connect, discover the service and characteristics, then you can issue a write.
-(void) centralManagerDidUpdateState:(CBCentralManager *)central {
switch (central.state) {
case CBCentralManagerStatePoweredOn:
[central scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] options:nil];
break;
}
}
-(void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(#"Discovered peripheral %# (%#)",peripheral.name,peripheral.identifier.UUIDString);
if (self.connectedPeripheral == nil) {
[central connectPeripheral:peripheral options:nil];
}
}
-(void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
self.connectedPeripheral=peripheral;
NSLog(#"Connected to %#(%#)",peripheral.name,peripheral.identifier.UUIDString);
peripheral.delegate=self;
[peripheral discoverServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]];
}
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
for (CBService *service in peripheral.services) {
NSLog(#"Discovered service %#",service.description);
[peripheral discoverCharacteristics:nil forService:service];
}
}
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
for (CBCharacteristic *characteristic in service.characteristics ) {
NSLog(#"Discovered characteristic %#(%#)",characteristic.description,characteristic.UUID.UUIDString);
if ([characteristic.UUID.UUIDString isEqualToString:TRANSFER_SERVICE_CHARACTERISTIC_UUID) {
NSData *data = [#"Testing" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
}
}
}
Note, that from your previous question the characteristic only supports write without response, so you can't use CBCharacteristicWriteWithResponse
I want to use BLE device for IOS which has on/off lights & coloured lights. I am connecting bluetooth using core bluetooth framework.
Now i want on/off or change colour of lights. How to do this from central as app to peripheral as bluetooth device, what are all methods required to do this function ?
1) Scan with nil service id (if you are using in background you would need service id)
2) Scan
[self.centralManager scanForPeripheralsWithServices:nil
options:nil];
3) You would get devices in this delegate method
- (void) centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI {
// check advertisementData for service UUID
[self.centralManager connectPeripheral:peripheral options:nil];
}
4) on successful Connection
- (void) centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral {
[peripheral discoverServices:nil];
}
5) on services discoverd
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
if (error) {
NSLog(#"Error discovering services: %#", [error localizedDescription]);
return;
}
// Discover the characteristic we want...
// Loop through the newly filled peripheral.services array, just in case there's more than one.
for (CBService *service in peripheral.services) {
[peripheral discoverCharacteristics:nil forService:service];
}
}
6) on retrieving charactesicts
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
// Deal with errors (if any)
if (error) {
NSLog(#"Error discovering characteristics: %#", [error localizedDescription]);
return;
}
// Again, we loop through the array, just in case.
for (CBCharacteristic *characteristic in service.characteristics) {
// And check if it's the right one
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:#"FFF1"]]) {
scannedcharacteristic = characteristic;
NSString *str = writeValue.length == 0 ? #"z" : writeValue;
DDLogVerbose(#"Writing value %#", str);
NSData *expectedData = [str dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:expectedData forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
// [peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
I try to make program to detect uncertain Bluetooth device at iOS.
The device scanning work well but it could not detect any device. However in the basic option in Ipad, the bluetooth devices were detected well. Bellow show the my code. Please advise to fix some problem.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//CB setup
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// You should test all scenarios
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
if (central.state == CBCentralManagerStatePoweredOn) {
_scan_state = 1;
}
[self deviceScan];
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
NSLog(#"dicovered: %#", peripheral.name);
if(![self.BTNames containsObject:peripheral]){
[self.BTNames addObject:peripheral];
}
_num_cell = self.BTNames.count;
[self.BTList reloadData];
}
- (void) deviceScan{
if(_scan_state){
/* [_centralManager scanForPeripheralsWithServices:nil options:#{ CBCentralManagerScanOptionAllowDuplicatesKey : #NO }];*/
[_centralManager scanForPeripheralsWithServices:nil options:nil];
NSLog(#"Scan Starting");
}
}