I am a new in Bluetooth connection and I want to add second device in my iOS project. I already have one device, and the new device is very similar with first one, but little bit deferent. I have one process for the two devices, and I did not change a lot of code, just created all value for the new device. My all devices have different name and identifier, first device is working fine.
For creating UUID values, I used UUID generator (https://www.guidgenerator.com/online-guid-generator.aspx).
class BleConstants: NSObject {
let deviceTwoServiceUUID = “59DE3994-6A63-4654-8FF0-F85C5163B2F5”
let deviceTwoFirstCharacteristicUUID = “59DE3994-6A63-4654-8FF0-F85C5163B2F6”
let deviceTwoSecondCharacteristicUUID = “59DE3994-6A63-4654-8FF0-F85C5163B2F7”
let deviceOneServiceUUID = “A6AF4483-E210-457B-B9D6-B8A621513D1D”
let deviceOneFirstCharacteristicUUID = “A6AF4483-E210-457B-B9D6-B8A621513D2D”
let deviceOneSecondCharacteristicUUID = “A6AF4483-E210-457B-B9D6-B8A621513D2D”
}
class BleManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
#objc private(set) static var sharedInstance = BleManager()
var cbManager : CBCentralManager? = nil
var currentPeripheral : CBPeripheral? = nil
var secondService : CBService? = nil
var firstService : CBService? = nil
var secondFirstCharacteristic : CBCharacteristic!
var secondSecondCharacteristic : CBCharacteristic!
var firstFirstCharacteristic : CBCharacteristic!
var firstSecondCharacteristic : CBCharacteristic!
func initCentralManager() {
if cbManager == nil {
cbManager = CBCentralManager(delegate: self, queue: nil, options: [CBCentralManagerOptionRestoreIdentifierKey : “MyApp”, CBCentralManagerOptionShowPowerAlertKey: true])
}
func deinitCentralManager() {
cbManager = nil
}
func isBluetoothAvailable() -> Bool {
return cbManager?.state == CBManagerState.poweredOn
}
func scan() {
if (cbManager != nil && (cbManager?.isScanning)!) {
return
}
discoveredPeripherals.removeAll()
let serviceUUIDs = [CBUUID(string: BleConstants.deviceTwoServiceUUID), CBUUID(string: BleConstants.deviceOneServiceUUID)]
cbManager?.scanForPeripherals(withServices: serviceUUIDs,
options: [CBCentralManagerScanOptionAllowDuplicatesKey : 1])
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if(!discoveredPeripherals.contains(peripheral)) {
discoveredPeripherals.append(peripheral)
}
}
func stopScan() {
if cbManager != nil && (cbManager?.isScanning)! {
cbManager?.stopScan()
}
}
func connect(peripheral: CBPeripheral) {
if cbManager?.state == CBManagerState.poweredOn {
if currentPeripheral == nil || currentPeripheral?.state != CBPeripheralState.connected {
cbManager?.connect(peripheral, options: nil)
} else {
cbManager?.cancelPeripheralConnection(peripheral)
}
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
Device.savePeripheralString(peripheral: peripheral.identifier.uuidString)
AutoConnect.stop()
DeviceUpdate.updateProgress = .None
Device.isDongleConnected = true
currentPeripheral = peripheral
currentPeripheral?.delegate = self
currentPeripheral?.discoverServices(nil)
disableSleep()
}
func disableSleep() {
UIApplication.shared.isIdleTimerDisabled = true
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if error != nil {
return
}
if let services = peripheral.services {
for service in services {
if service.uuid.uuidString == BleConstants.deviceTwoServiceUUID {
Device.dongleType = port.second
secondService = service
peripheral.discoverCharacteristics(nil, for: service)
}
if service.uuid.uuidString == BleConstants.deviceOneServiceUUID {
Device.dongleType = port.first
firstService = service
peripheral.discoverCharacteristics(nil, for: service)
} else {
Log.bt("didDiscoverServices for peripheral not found \(peripheral.identifier.uuidString)")
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic in service.characteristics! {
if characteristic.uuid.uuidString == BleConstants.deviceOneFirstCharacteristicUUID {
firstCharacteristic = characteristic
}
else if characteristic.uuid.uuidString == BleConstants.deviceOneSecondCharacteristicUUID {
firstSecondCharacteristic = characteristic
else if characteristic.uuid.uuidString == BleConstants.deviceTwoFirstCharacteristicUUID {
secondFirstCharacteristic = characteristic
} else if characteristic.uuid.uuidString == BleConstants.deviceTwoSecondCharacteristicUUID {
secondSecondCharacteristic = characteristic
} else {
Log.bt("didDiscoverCharacteristics not found \(characteristic.uuid.uuidString)")
}
}
if Device.dongleType == .deviceTwo {
openPortDeviceTwo()
} else {
openPortDeviceOne()
}
}
}
Data from logs:
For first device:
isBluetoothAvailable()
scan()
CentralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) (peripheral <CBPeripheral: 0x267hg5670, identifier = 98HG761CE-56C3-K767-26HJ-E51BA678Gh56, name = DeviceOne, state = disconnected)
CentralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
scan()
CentralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) (peripheral <CBPeripheral: 0x267hg5670, identifier = FJ1478HJ-EH8J-6709-1FH0-1456HGJ0BC901, name = SecondDevice, state = disconnected>)
stopScan()
connect(peripheral: CBPeripheral) (currentPeripheral nil, currentPeripheral nil)
CentralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral
centralManager(_:didConnect:) - didConnectPeripheral FJ1478HJ-EH8J-6709-1FH0-1456HGJ0BC901 Second device
savedPeripheralString FJ1478HJ-EH8J-6709-1FH0-1456HGJ0BC901 Second device
Bluetooth stop() currentPeripheral Optional(<CBPeripheral: 0x2jk875fe0, identifier = FJ1478HJ-EH8J-6709-1FH0-1456HGJ0BC901, name = SecondDevice, state = connected>)
disableSleep()
peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
peripheral(_:didDiscoverServices:) - didDiscoverServices for peripheral FJ1478HJ-EH8J-6709-1FH0-1456HGJ0BC901
peripheral(_:didDiscoverServices:) - didDiscoverServices for peripheral.services Optional([<CBService: 0x2jkki2dc0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5>, <CBService: 0xhj67c240, isPrimary = YES, UUID = Device Information>])
[<CBService: 0x5678f2dc0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5>, <CBService: 0x28186c240, isPrimary = YES, UUID = Device Information>], peripheral.services is Optional([<CBService: 0xhjy62dc0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5>, <CBService: 0x2hju7240, isPrimary = YES, UUID = Device Information>]))
service.uuid.uuidString is 59DE3994-6A63-4654-8FF0-F85C5163B2F5 and services is [<CBService: 0xhj7892dc0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5>, <CBService: 0xhjk678340, isPrimary = YES, UUID = Device Information>]
peripheral(_:didDiscoverServices:) - didDiscoverServices SecondDevice 59DE3994-6A63-4654-8FF0-F85C5163B2F5
peripheral(_:didDiscoverServices:) - didDiscoverServices for peripheral not found FJ1478HJ-EH8J-6709-1FH0-1456HGJ0BC901
For second device:
isBluetoothAvailable()
scan()
CentralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) (peripheral <CBPeripheral: 0xh6789a40, identifier = 98HG761CE-56C3-K767-26HJ-E51BA678Gh56, name = DeviceOne, state = disconnected)
scan()
CentralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) (peripheral <CBPeripheral: 0x678jhs0, identifier = H56KIL35-7835-7JKL-2B11-HJKLIYTAA400, name = ThirdDevice, state = disconnected)
CentralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
stopScan()
connect(peripheral: CBPeripheral) currentPeripheral nil, currentPeripheral nil
CentralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral
centralManager(_:didConnect:) - didConnectPeripheral H56KIL35-7835-7JKL-2B11-HJKLIYTAA400
savedPeripheralString H56KIL35-7835-7JKL-2B11-HJKLIYTAA400
Bluetooth stop() - currentPeripheral Optional(<CBPeripheral: 0x78jkl680, identifier = H56KIL35-7835-7JKL-2B11-HJKLIYTAA400, name = ThirdDevice, state = connected>)
disableSleep()
peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
peripheral(_:didDiscoverServices:) - didDiscoverServices for peripheral H56KIL35-7835-7JKL-2B11-HJKLIYTAA400
**peripheral(_:didDiscoverServices:) - didDiscoverServices for peripheral.services Optional([<CBService: 0xlki8901c0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5 - same like for secondDevice>, <CBService: 0x281111180, isPrimary = YES, UUID = Device Information>])
services is [<CBService: 0x2827444c0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5 - same like for secondDevice>, <CBService: 0x282744580, isPrimary = YES, UUID = Device Information>], peripheral.services is Optional([<CBService: 0xlki8901c0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5 - same like for secondDevice>, <CBService: 0x281111180, isPrimary = YES, UUID = Device Information>]))
service.uuid.uuidString is 59DE3994-6A63-4654-8FF0-F85C5163B2F5 - same like for secondDeviceand services is [<CBService: 0x27893kdc0, isPrimary = YES, UUID = 59DE3994-6A63-4654-8FF0-F85C5163B2F5 - same like for secondDevice>, <CBService: 0x679kh8580, isPrimary = YES, UUID = Device Information>]
peripheral(_:didDiscoverServices:) - didDiscoverServices ThirdDevice 59DE3994-6A63-4654-8FF0-F85C5163B2F5 - same like for secondDevice
peripheral(_:didDiscoverServices:) - didDiscoverServices for peripheral not found H56KIL35-7835-7JKL-2B11-HJKLIYTAA400**
Based on logs information for second device in 16th step app connected to my first service UUID and first characteristic UUID, that is wrong!
Do you have idea, Did I create UUIDs correct?
P.S:
Android app works fine with both devices.
Thanks a lot!
Receiving the same service and characteristic UUID for multiple BLE devices is perfectly normal and only means that all the devices offer exactly the same service.
For example:
If you have two devices which measure the heart rate of a person, e.g. a smartwatch, both devices might offer the heart rate service with the same UUID.
If you want to differentiate between the device you can use the identifier which you received in step 3 of your provided log.
How Can I convert a CBUUID to UINT16?
I want to procure the device information in the advertisement data as UINT16.
I am getting the error
Could not cast value of type 'CBUUID' (0x1d2715e68) to 'NSNumber' (0x1d25c9db0).
2019-12-04 14:17:18.731697-0500 ProjectName[717:125723] Could not cast value of type 'CBUUID' (0x1d2715e68) to 'NSNumber' (0x1d25c9db0).
My Advertisement Data in terminal
["kCBAdvDataTxPowerLevel": 0,"kCBAdvDataIsConnectable": 1, "kCBAdvDataTimestamp": 597179838.727399, "kCBAdvDataServiceUUIDs": <__NSArrayM 0x281252e20>(
22043200-9530-4EA8-9D21-04146852E51F
)
, "kCBAdvDataServiceData": {
"Device Information" = {length = 6, bytes = 0x010000020004};
}, "kCBAdvDataLocalName": base0]
I have highlighted the information which I need in Bold.
I have the following code below.
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard peripheral.state != .connected else {
return
}
let advertisementDataService = advertisementData[CBAdvertisementDataServiceDataKey]
let deviceInformation = advertisementDataService as! Dictionary<UInt16,AnyObject>
}
Thank You!!!
As per [the documentation[(https://developer.apple.com/documentation/corebluetooth/cbadvertisementdataservicedatakey), the dictionary associated with CBAdvertisementDataServiceDataKey is of type <CBUUID,Data>. Having retrieved the dictionary you can then subscript it using the appropriate CBUUID instance (0x180A is the Device Information service).
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard peripheral.state != .connected else {
return
}
if let deviceInformation = advertisementData[CBAdvertisementDataServiceDataKey] as? Dictionary<CBUUID,Data>,
let data = deviceInformation[CBUUID(string:"0x180A")] {
// Do something with the data
}
}
I have bluetooth hearing aid. They have different device name and same service UUID.
I want to my app can connect them at the same time. How should I do?
My code just can connect one peripheral.
My code:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Find device: \(String(describing: peripheral.name))")
guard peripheral.name != nil else {
return
}
guard peripheral.name?.range(of: "HD100-5201000") != nil else {
return
}
guard peripheral.name?.range(of: "HD100-5200526") != nil else {
return
}
central.stopScan()
if peripheral.name?.range(of: "HD100-5201000") != nil {
connectPeripheral = peripheral
connectPeripheral.delegate = self
centralManager.connect(connectPeripheral, options: nil)
}
if peripheral.name?.range(of: "HD100-5200526") != nil {
connectPeripheral = peripheral
connectPeripheral.delegate = self
centralManager.connect(connectPeripheral, options: nil)
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
charDictionary = [:]
peripheral.discoverServices(nil)
}
I tried but i didn't get any device list near by me.
below code i tried.I apperciate your answer and please help me.Thank you in advance.
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
let option:[String:Any] = [CBCentralManagerScanOptionAllowDuplicatesKey:true]
self.manager.scanForPeripherals(withServices: nil, options: option)
}
else {
print("Bluetooth is not available")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("peripheral:=\(peripheral.name)")
if let device = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
print("peripheral_ UUID:=\(peripheral.services)")
if let service = peripheral.services {
BEAN_SERVICE_UUID = service[0].uuid
let idstr = service[0].characteristics![0].uuid
BEAN_SCRATCH_UUID = idstr
print("BEAN_SERVICE_UUID:=\(BEAN_SERVICE_UUID)")
}
manager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
manager.connect(self.peripheral, options: nil)
}
else {
print("device not Found")
}
}
I'm studying Core Bluetooth framework and I did a test project about it for learning:
class ViewController: UIViewController,CBCentralManagerDelegate,CBPeripheralDelegate {
var centralManager: CBCentralManager = CBCentralManager()
var peripheral: CBPeripheral? = nil
override func viewDidLoad()
{
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
func centralManagerDidUpdateState(_ central: CBCentralManager)
{
central.scanForPeripherals(withServices: nil, options: nil)
}
#available(iOS 5.0, *)
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
{
let device = (advertisementData as NSDictionary)
.object(forKey: CBAdvertisementDataLocalNameKey)
as? NSString
let isMyIphone = device?.contains("iPhone")
}
}
For starting I would like to see Bluetooth name around me, for this reason I have 2 iPhone.
One I use for execute this 'app' for scanning and I would like to see the name of the other iPhone (in Bluetooth setting is name is 'iPhone'), but when I start scanning the method 'didDiscover' is called but the device constant is nil.
Why? What I wrong?
is better if you use
peripheral.name
instead
let device = (advertisementData as NSDictionary)
.object(forKey: CBAdvertisementDataLocalNameKey)
as? NSString