I'm not sure why this code is failing to build and the error message seems quite cryptic.
Code:
var centralManager: CBCentralManager!;
var nrf8001Peripheral: CBPeripheral!;
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// initialize centralManager
self.centralManager = CBCentralManager(delegate: self, queue: nil);
// start scanning for device
self.centralManager.scanForPeripheralsWithServices([UART_SERVICE_UUID], options:nil);
}
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData advertisementData: [NSObject : AnyObject]!, RSSI RSSI: NSNumber) {
//print out the name of the scanned peripheral
print("Discovered \(peripheral.name)")
//print out the UUID of the scanned peripheral
print("NSUUID string \(peripheral.identifier.UUIDString)")
//stop scanning when found
self.centralManager.stopScan()
//connect when found
self.centralManager.connectPeripheral(peripheral, options:nil);
}
And the error I receive from the XCode compiler is:
"Objective-C method 'centralManager:didDiscoverPeripheral:advertisementData:RSSI:' provided by method 'centralManager(:didDiscoverPeripheral:advertisementData:RSSI:)' conflicts with optional requirement method 'centralManager(:didDiscoverPeripheral:advertisementData:RSSI:)' in protocol 'CBCentralManagerDelegate'"
From looking through the CoreBluetooth documentation it seems as if the method syntax and parameters are correct, and the optionality of the parameters is copied directly from the spec sheet: https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBCentralManagerDelegate_Protocol/#//apple_ref/occ/intfm/CBCentralManagerDelegate/centralManager:didDiscoverPeripheral:advertisementData:RSSI:
Any help would be appreciated! Thank you
Per the comments:
Using XCode 7 beta
When I change the function declaration to:
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData advertisementData: [NSObject : AnyObject], RSSI RSSI: NSNumber)
I still get the same build error.
My centralManagerDidUpdateState:method is
func centralManagerDidUpdateState(central: CBCentralManager) {
print("centralManagerDidUpdateState:");
switch (central.state) {
case .PoweredOff:
print("CBCentralManagerStatePoweredOff");
case .Resetting:
print("CBCentralManagerStateResetting");
case .PoweredOn:
print("CBCentralManagerStatePoweredOn");
//scan for peripheral devices
self.centralManager.scanForPeripheralsWithServices([UART_SERVICE_UUID], options:nil);
case .Unauthorized:
print("CBCentralManagerStateUnauthorized");
case .Unsupported:
print("CBCentralManagerStateUnsupported");
default:
print("CBCentralManagerStateUnknown");
}
}
Thank you for the suggestions; I ended up finding the answer through the XCode 7 documentation. The XCode 6 syntax for the following functions was as follows:
func centralManagerDidUpdateState(central: CBCentralManager!) {}
func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData advertisementData: [NSObject : AnyObject]!, RSSI RSSI: NSNumber) {}
func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) {}
func centralManager(central: CBCentralManager!, didDisconnectPeripheral peripheral: CBPeripheral!, error: NSError!) {}
func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) {}
func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) {}
func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {}
func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {}
However, these functions will conflict with the XCode 7 CoreBluetooth library declarations.
Note the differing uses of optionals as well as data types.
(XCode 6) error:NSError! vs. (XCode 7) error:NSError?
(XCode 6) advertisementData : [NSObject : AnyObject]! vs. (XCode 7) advertisementData [String : AnyObject]
The appropriate function declarations for XCode 7 beta are actually the following:
func centralManagerDidUpdateState(central: CBCentralManager) {}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {}
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {}
func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {}
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {}
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {}
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {}
func peripheral(peripheral: CBPeripheral, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic, error: NSError?) {}
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {}
Hope this is helpful to others having the same issues!
Related
I have a bluetooth device. When i fired device, IOS app receive fire event from it in func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) method in advertisementData["kCBAdvDataLocalName"] But when i connect BLE bluetooth device with my app through centralManager.connect(heartRatePeripheral) method it did not receive fire event in any of the CBPeripheralDelegate methods. Please help me how to get event after connecting BLE device with IOS app. Below is my full code.
import UIKit
import CoreBluetooth
let heartRateServiceCBUUID = CBUUID(string: "FFC2")
class HRMViewController: UIViewController {
#IBOutlet weak var heartRateLabel: UILabel!
#IBOutlet weak var bodySensorLocationLabel: UILabel!
var centralManager: CBCentralManager!
var heartRatePeripheral: CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
heartRateLabel.font = UIFont.monospacedDigitSystemFont(ofSize:
heartRateLabel.font!.pointSize, weight: .regular)
}
func onHeartRateReceived(_ heartRate: Int) {
heartRateLabel.text = String(heartRate)
print("BPM: \(heartRate)")
}
}
extension HRMViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
}
func centralManager(_ central: CBCentralManager, didDiscover
peripheral: CBPeripheral, advertisementData: [String : Any], rssi
RSSI: NSNumber) {
if advertisementData["kCBAdvDataLocalName"] as? String ==
"SPS026A" {
print(advertisementData["kCBAdvDataLocalName"])
let data =
advertisementData[CBAdvertisementDataManufacturerDataKey]
print("data ==\(data)")
heartRatePeripheral = peripheral
centralManager.connect(heartRatePeripheral)
}
}
func centralManager(_ central: CBCentralManager, didConnect
peripheral: CBPeripheral) {
print("Connected!")
heartRatePeripheral.discoverServices([])
heartRatePeripheral.delegate = self
}
}
extension HRMViewController: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices
error: Error?) {
guard let services = peripheral.services else { return }
for service in services {
print(service)
peripheral.discoverCharacteristics(nil, for: service)
}
}
func peripheralDidUpdateName(_ peripheral: CBPeripheral) {
}
func peripheral(_ peripheral: CBPeripheral,
didDiscoverCharacteristicsFor service: CBService, error: Error?)
{
guard let characteristics = service.characteristics else {
return }
for characteristic in characteristics {
if characteristic.properties.contains(.read) {
print("\(service): service : \ .
(characteristic.uuid): properties contains .read")
peripheral.readValue(for: characteristic)
}
if characteristic.properties.contains(.notify) {
print("\(service): service : \
(characteristic.uuid): properties contains
.notify")
peripheral.setNotifyValue(true, for:
characteristic)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didOpen channel:
CBL2CAPChannel?, error: Error?) {
}
func peripheralIsReady(toSendWriteWithoutResponse peripheral:
CBPeripheral) {
}
func peripheral(_ peripheral: CBPeripheral,
didUpdateNotificationStateFor characteristic: CBCharacteristic,
error: Error?) {
print("Unhandled Characteristic UUID: \(characteristic)")
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor
characteristic: CBCharacteristic, error: Error?) {
print("Unhandled Characteristic UUID: \(characteristic)")
}
}
To discover all of the peripheral's services, you should pass nil to discoverServices, not an empty array.
heartRatePeripheral.discoverServices(nil)
By passing an empty array you are saying that you don't want to discover any services.
i try to write app with connect to bluetooth and send some data and get response, but got error when try to set: setNotifyValue
I start search with
self.centralManager?.scanForPeripherals(withServices: [serviceUUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey : true])
after i connect to peripheral
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
self.discoveredPeripheral = peripheral
self.discoveredPeripheral!.delegate = self
self.centralManager?.stopScan()
self.centralManager?.connect(self.discoveredPeripheral!, options: nil)
}
after connect i discover services
public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
self.discoveredPeripheral!.discoverServices([serviceUUID])
}
after discover charachteristic
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let services = peripheral.services{
for service in services {
if service.uuid.isEqual(serviceUUID) {
self.discoveredPeripheral!.discoverCharacteristics(nil, for: service)
}
}
} else{
print("errors")
}
}
after i save characteristic and try setNotifyValue to true
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let charachteristics = service.characteristics {
for charactiristic in charachteristics {
if charactiristic.uuid.isEqual(readCharacteristicUUID) {
self.readCharacteristic = charactiristic
} else if charactiristic.uuid.isEqual(writeCharacteristicUUID) {
self.writeCharacteristic = charactiristic
peripheral.setNotifyValue(true, for: charactiristic)
}
}
}
}
but in i got error:
public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("didUpdateNotification")
if error != nil {
print((error!.localizedDescription))
}
}
The request is not supported.
in android it possible to connect with response
does anyone ideas, what is wrong and how fix this ?
I try restart phone: CBCentralManager setNotifyValue: not working
but it doesn't help
I'm trying to create an app that print via bluetooth with a printer
on xcode, i'm able to connect the printer, and also to see the services and the uuid's, but the problem is that when i try to see the characteristic of the services i found nil
do anyone have a idea about that problem ?
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
print("Service \(service)\n")
print("Discovering Characteristics for Service : \(service.uuid)")
print(service.characteristics)
}
}
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if #available(iOS 10.0, *){
switch (central.state) {
case CBManagerState.poweredOff:
print("CBCentralManagerState.PoweredOff")
case CBManagerState.unauthorized:
print("CBCentralManagerState.Unauthorized")
break
case CBManagerState.unknown:
print("CBCentralManagerState.Unknown")
break
case CBManagerState.poweredOn:
print("CBCentralManagerState.PoweredOn")
centralManager.scanForPeripherals(withServices: nil, options: nil)
centralManager.scanForPeripherals(withServices: nil, options: nil)
case CBManagerState.resetting:
print("CBCentralManagerState.Resetting")
case CBManagerState.unsupported:
print("CBCentralManagerState.Unsupported")
break
}}else{
switch central.state.rawValue{
case 0:
print("CBCentralManagerState.Unknown")
break
case 1:
print("CBCentralManagerState.Resetting")
case 2:
print("CBCentralManagerState.Unsupported")
break
case 3:
print("This app is not authorised to use Bluetooth low energy")
break
case 4:
print("Bluetooth is currently powered off.")
case 5:
print("Bluetooth is currently powered on and available to use.")
self.centralManager.scanForPeripherals(withServices: nil, options: nil)
break
default:
break
}}}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("name : \(peripheral.name )")
let device = (advertisementData as NSDictionary)
.object(forKey: CBAdvertisementDataLocalNameKey)
as? NSString
if device?.contains(BEAN_NAME) == true {
self.centralManager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
print("peripheral: \(self.peripheral)")
centralManager.connect(peripheral, options: nil)
print("peripheral: \(self.peripheral)")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print(error)
for characteristic in service.characteristics! {
print(anything)
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
print("Sent")
}
You are missing an important step in your didDiscoverServices - you need to call discoverCharacteristics:for: -
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
print("Service \(service)\n")
print("Discovering Characteristics for Service : \(service.uuid)")
print(service.characteristics)
}
}
You will then get a call to your peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) delegate method
I am trying to connect to a MacBook Pro from an iPad with CoreBluetooth.
Here is my delegation for CBCentralManagerDelegate:
extension MasterViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Scanning for peripherals")
central.scanForPeripherals(withServices: nil, options: nil)
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.stopScan), userInfo: nil, repeats: true)
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Did discover peripheral", peripheral)
central.connect(peripheral, options: nil)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Did connect to ", peripheral)
peripheral.delegate = self
self.remotePeripheral.append(peripheral)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {}
}
But when I scan I get this error in the log:
<Error>: [CoreBluetooth] API MISUSE: Cancelling connection for unused peripheral
Why does this happen?
Not sure why this worked, but I found that it works if I assign the peripherals delegate to self, and add the peripheral to an array before I connect to it.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Did discover peripheral", peripheral)
peripheral.delegate = self
self.remotePeripheral.append(peripheral)
central.connect(peripheral, options: nil)
}
I was seeing this error and for those who also are facing the same issue, my suggestion is that I wasn't storing the CBPeripheral device in my helper class. That seems unnecessary to do but for some reason it needs to be bounded internally I believe.
Well, Here's what I did:-
class BLEHelper: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate{
#Published var pairedDevice:CBPeripheral?=nil
...
and then in your didDiscover function:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
pairedDevice=peripheral
peripheral.delegate=self
myCentral.connect(peripheral, options:nil)
myCentral.stopScan()
}
This line here does the trick:- pairedDevice=peripheral
I would like to discover BLE devices in my area and store their current RSSI value. The discovering works but I'm note sure, if my func didDiscoverPeripheral is really save... I think that I should wait for the didReadRSSI func before I leave the didDiscoverPeripheral. But how can I realize that in an easy way and is my opinion right?
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
CBperipheral = [peripheral]
peripheral.readRSSI()
}
func peripheral(peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: NSError?)
{
//Store the peripheral specific RSSI, Name and identifier
}
I would suggest something like this -
var peripherals = Set<CBPeripheral>
var peripheralRSSIs = Dictionary<CBPeripheral,NSNumber>()
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
self.peripherals.insert(peripheral)
self.peripheralRSSIs[peripheral]=RSSI
central.connectPeripheral(peripheral,options:nil) // Connect if you want to be able to retrieve additional RSSI values
}
func centralManager(_ central: CBCentralManager,
didConnectPeripheral peripheral: CBPeripheral)
{
peripheral.delegate=self
peripheral.readRSSI()
}
func peripheral(peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: NSError?)
{
if (error != nil) {
print(error)
} else {
self.peripheralRSSIs[peripheral]=RSSI
}
}
I solved the problem like this:
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
CBperipheral = [peripheral]
myStrings.append(StringPair("\(peripheral.name!)", "\(peripheral.name!)", "\(RSSI)"))
//Coose the right peripheral and connect!
}
I don't need very up-to-date values for the RSSI, only some guiding values. So I hope this code is conform with IOS 8 and later.
But it would be nice, if you could tell me the handling with the callback to my didReadRSSI for other problems like this.
btw. I have to write this: CBperipheral = [peripheral] to call my didConnectPeripheral after the call of CBmanager.connectPeripheral :)