Bluetooth UUID for car handsfree devices - swift

Can anyone help me with the UUID for car handsfree peripheral connections, so I can call scanForPeripherals withServices: [SOME UUID] instead of nil, and only return handsfree. Is there a UUID or CBUUID for this? I hope this can be done at a service level and does not need to look at characteristics. Thanks in advance if you can help me.
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
self.centralManager.scanForPeripherals(withServices: [UUID HERE] , options: nil)
} else {
print("central not powered on")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("peripheral discovered")
peripheralLabel.text = peripheral.name
}

Handsfree devices implement the Bluetooth Hands Free Protocol (HFP). This is not a Bluetooth Low Energy GATT service and so does not have a service UUID. They cannot be discovered using Core Bluetooth.

Related

How to scan multiple BLE devices on iOS

I‘m developing a swift iOS app in which I need BLE scanning between multiple devices. Suppose I have 3 devices (A, B, and C). If all three devices are in the background, each device will only scan one other device and will stop scanning after. For example, A will only scan B, B will only scan A, and C will only scan A. After this initial background scan, no other devices will be scanned by any of the devices. However, I need A to scan both B and C, B to scan both A and C, and C to scan both A and B. I'm not sure how to approach this problem. Is there a way in which I can have an iOS device scan multiple devices in the background?
For Bluetooth peripheral and central, I used these codes from Apple's documentation:
https://developer.apple.com/documentation/corebluetooth/transferring_data_between_bluetooth_low_energy_devices
Also here is my code for setting up the central manager.
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
//this makes it so it connects and ensures it only works if both devices have ther app
//start sending message code
os_log("Discovered %s at %d", String(describing: peripheral.name), RSSI.intValue)
peripherals.append(peripheral)
if myPeripheral != peripheral {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it.
myPeripheral = peripheral
// And finally, connect to the peripheral.
print("Connecting to perhiperal %#", peripheral)
myCentralManager.connect(peripheral, options: nil)
}
//end of messaging code
print("\nName : \(peripheral.name ?? "(No name)")")
print("RSSI : \(RSSI)")
currentRssi = Int(truncating: RSSI)
for ad in advertisementData {
print("AD Data: \(ad)")
}
}
func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
print("will restore state central scene")
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
os_log("Perhiperal Disconnected")
myPeripheral = nil
// We're disconnected, so start scanning again
if connectionIterationsComplete < defaultIterations {
retrievePeripheral()
} else {
print("Connection iterations completed")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Peripheral Connected")
// Stop scanning
myCentralManager.stopScan()
print("Scanning stopped")
// set iteration info
connectionIterationsComplete += 1
writeIterationsComplete = 0
// Clear the data that we may already have
data.removeAll(keepingCapacity: false)
// Make sure we get the discovery callbacks
peripheral.delegate = self
// Search only for services that match our UUID
peripheral.discoverServices([ServiceID])
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
os_log("Perhiperal Disconnected")
myPeripheral = nil
// We're disconnected, so start scanning again
if connectionIterationsComplete < defaultIterations {
retrievePeripheral()
} else {
print("Connection iterations completed")
}
}
private func retrievePeripheral() {
let connectedPeripherals: [CBPeripheral] = (myCentralManager.retrieveConnectedPeripherals(withServices: [CovtraceID]))
print("Found connected Peripherals with transfer service: %#", connectedPeripherals)
if let connectedPeripheral = connectedPeripherals.last {
print("Connecting to peripheral %#", connectedPeripheral)
self.myPeripheral = connectedPeripheral
myCentralManager.connect(connectedPeripheral, options: nil)
} else {
// We were not connected to our counterpart, so start scanning
myCentralManager.scanForPeripherals(withServices: [CovtraceID],
options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
}
}

My Corebluetooth framework is connecting to multiple device

I'm working on a project with corebluetooth framework.When my central manager starts scanning for peripherals it connects to a single peripheral after sometime maybe one minute it starts connecting to multiple peripherals with same UUID.
Is there a way to tell the device to stick to one peripheral which is connected initially?
Variables
public var centralManager: CBCentralManager? = nil
public let baseLayerServices = [SkiinUUID(string: SkiinPeripheral.baseLayerService)]
#Published public var peripherals: AllPeripherals = AllPeripherals()
Did update state
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("state: \(self.getStateString())")
if central.state == .poweredOn {
self.showStateAlert = false
if let connectedPeripherals = self.centralManager?.retrieveConnectedPeripherals(withServices: self.baseLayerServices), connectedPeripherals.count > 0 {
print("Already connected: \(connectedPeripherals.map{$0.name}), self.peripherals: \(self.peripherals)")
self.centralManager?.stopScan()
}
else {
print("scanForPeripherals")
self.centralManager?.scanForPeripherals(withServices: self.baseLayerServices, options: nil)
}
}
else {
self.showStateAlert = true
}
}
didDiscover Peripheral Code
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard peripheral.state != .connected else {
return
}
print("didDiscover: \(peripheral.name ?? peripheral.identifier.uuidString)")
self.peripherals.baseLayer.top.add(cbPeripheral: peripheral)
self.centralManager?.connect(peripheral, options: nil)
self.observe(peripheral: self.peripherals.baseLayer.top)
}
When this code discovers a peripheral, it tries to connect to it. I don't see anywhere that it stops scanning, and it doesn't avoid connecting just because it's connected.
If you don't want to keep scanning after you discover something, call stopScanning(). If you don't want to connect when you're already connected (or connecting), then don't call connect() in those cases.

Unable to read user define characteristics in bluetooth services (BLE) using iOS application

I am developing iOS app in that I'm using core BLE services and characteristics for read and write data.
Here I'm using service having unique CBUUID and this service having two default characteristics, I can able to read and write that characterisitcs but when we add another charecteristics in that service I'm unable to read that newly added characteristics.
Please check code as follows
For scan peripheral device
var centralManager: CBCentralManager!
centralManager = CBCentralManager(delegate: self, queue: nil)
After discover peripheral connect to particular device using following delegate methods
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any], rssi RSSI: NSNumber)
{
if(peripheral.name == "myBLE")
{
centralManager.stopScan()
centralManager.connect(myPeripheral)
}
}
After connecting bluetooth device, discover services
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
{
//centralManager.stopScan()
peripheral.discoverServices(nil) // For all services
}
We get services in following delegate methods
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
{
guard let services = peripheral.services else { return }
for service in services
{
peripheral.discoverCharacteristics(nil, for: service)
}
}
We get charecteristics in following delegate methods
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
{
guard let characteristics = service.characteristics else { return }
for characteristic in characteristics
{
print(characteristic)
//Here we get only default characteristics, but not getting newly added characteristics
if characteristic.properties.contains(.read)
{
peripheral.readValue(for: characteristic)
}
if characteristic.properties.contains(.notify)
{
peripheral.setNotifyValue(true, for: characteristic)
}
}
}
Here I am unable to read newly added characteristics, is there any solution please let me know.

iOS - Swift Bluetooth - does not discover Android device

I am trying to write an app in Swift that discovers a Android phone (pixel 2). However, it is not showing up in the results. I can however find the pixel in the regular bluetooth settings of the iphone (it's an iphone 8).
My code to discover the Android phone:
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if (central.state == .poweredOn) {
print("Powered on, starting scan")
self.centralManager?.scanForPeripherals(withServices: nil, options: nil)
} else {
print("BT not powered on")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print(peripheral)
}
It shows me other BT devices but not the Android phone. I also did write an Android app to explicitly enable BT discoverability just in case. But still not showing up.
As #Paulw11 has mentioned, I had to create a BLE GATT service to detect it.
Just look at this example here: https://github.com/androidthings/sample-bluetooth-le-gattserver If you implement the Android app in that way, the iOS app will discover the service.

Cant search for custom CBUUID

I have an app that works (so far so good) in connecting my iOS device to a bluetooth arduino, as of now this has been mostly for practice, but now I received the real thing that I'm supposed to connect to.
The problem is that I can't find it! (when I search for it).
If I do scanwithservices: nil, I can see the device and connect to it. However if i scanwithservices: [device'sCBUUID] then I don't get anything.
I double/triple/quatrupled checked the CBUUID using other apps, using my own app and looking at the device documentation, however no matter what I can't find it.
It has a custom CBUUID, from what I've read that's not standard, the CBUUID is:
BLETPodService = CBUUID(string: "4D494B45-414c-5741-5953-524F434B5321")
Searching for this yields nothing, however if I scan for nil I find it and if i check it's characteristics using the Bluefruit app (from Adafruit) I can see it's services and characteristics ID and they match that string I posted in here!
I told a friend and he said it's a BLE bug thats been there for ages (regarding custom CBUUIDs), is this true? is there really no fix for this?
EDIT adding the full scanning code just FYI:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
var statusMessage = ""
switch (central.state)
{
case .unsupported:
statusMessage = "Bluetooth Low Energy is not supported!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .unauthorized:
statusMessage = "Bluetooth Low Energy is not authorized!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .unknown:
statusMessage = "Bluetooth Low Energy is unknown!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .poweredOff:
statusMessage = "Bluetooth Low Energy is powered off!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .resetting:
statusMessage = "Bluetooth Low Energy is resetting!"
displayStatusAlert(localmsg: statusMessage)
print(statusMessage)
case .poweredOn:
statusMessage = "BLE is ready!" //If BLE is ready then start scanning right away!
peripheralsFoundNames.removeAll()
peripheralsFoundCB.removeAll()
peripheralsFoundRSSIs.removeAll()
peripheralsFoundData.removeAll() //Remove previous data from previous scans
central.scanForPeripherals(withServices: nil, options: nil)
}
}
//What happens when you discover a peripheral
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
//What to do when it discovers a peripheral, add it to the array list
print("Peripheral found: " + (peripheral.name ?? "Unknown Name"))
peripheralsFoundNames.append((peripheral.name ?? "Unknown Name"))
peripheralsFoundData.append((advertisementData.description ))
peripheralsFoundCB.append(peripheral)
peripheralsFoundRSSIs.append(RSSI)
}
I happen to be working on both BLE firmware and iOS App at the same time.
I had the same issue that the filter not working.
The reason that iOS couldn't find the device with the UUID is that the device doesn't include the UUID when it is advertising.
I had to change the device firmware to add service UUID in the advertising data packet. With device advertising the UUID, UUID filter worked as expected.
I also had this problem, but I've found some tricky way.
You can try to match UUIDs (string value) directly in didDiscoverPeripheral func:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
if let services = peripheral.services {
for service in services {
if service.uuid.uuidString.lowercased() == "4D494B45-414c-5741-5953-524F434B5321".lowercased() {
if !peripheralsFoundCB.contains(peripheral) {
peripheralsFoundCB.append(peripheral)
}
}
}
}
}
If this way doesn't work for you I have one more:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
peripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let services = peripheral.services {
for service in services {
if service.uuid.uuidString.lowercased() == "4D494B45-414c-5741-5953-524F434B5321".lowercased() {
if !peripheralsFoundCB.contains(peripheral) {
peripheralsFoundCB.append(periphera
}
}
}
}
}
Of course you should use
scanwithservices: nil
Swift 3:
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
self.selectPeripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
let services = peripheral.services as [CBService]!{
for service in services{
if service.uuid.uuidString == "4D494B45-414c-5741-5953-524F434B5321"{
print("service found")
}
}
}
}
I am having exactly the same issue. Currently I might do the same solution suggested by the folks here! But I think its a problem from the hardware side.
I believe what is happening that your EE is not broadcasting the service UUID! What I mean by that if you printed the advertisedInfo you will not see the the following key-value pair in the info:
"kCBAdvDataServiceUUIDs": <__NSArrayM 0x14e6f3b0>("Your CBUUID")
You might see the name key-value and other stuff but definitely not the one I specified.
For that reason if he can do his part by broadcasting the service UUID's then you will be able to scan for that using the following method.
scanForPeripherals(withServices: ["Your CBUUID"], options: nil)
And you will see it :)