I'm trying to connect near by bluetooth devices. I'm able to discover but i'm unable to connect them.
this delegate is working but after discovering i'm trying connect with one of the pheripheral
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if let device = (advertisementData as NSDictionary).object(forKey: CBAdvertisementDataLocalNameKey) as? String {
print(device)
if device.contains("BODY") {
self.connectPeripheral = peripheral
self.connectPeripheral.delegate = self
self.manager.connect(connectPeripheral, options: nil)
self.manager.stopScan()
}
}
}
These two delegates methods are not invoking. one of these should be called.
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
//NSLog("Error %#", error.debugDescription)
print(error.debugDescription)
}
You need to maintain a strong reference to the CBPeripheral instance, because once you tell the Central to stop scanning, it will deallocate all its discovered peripherals.
Related
var peripherals = [CBPeripheral]()
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if let _ = peripheral.name {
if !peripherals.contains(peripheral) {
peripherals.append(peripheral)
table.reloadData()
}
}
}
Using the delegate method above, called after centralManager.scanForPeripherals(withServices: nil), I am showing available peripherals(only those with name).
Since some of the available devices are also mine, I am sure that bluetooth is turned off on them.
So why does this method returns them as available? Are they cached somewhere or?
I want to connect with ble peripheral.
But my code doesn't call didConect function
this is my code :
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let device = (advertisementData as NSDictionary)
.object(forKey: CBAdvertisementDataLocalNameKey)
as? NSString
if device?.contains(BEAN_NAME) == true {
print("Did discover peripheral", peripheral)
self.bluetoothManager.stopScan()
self._peripheral = peripheral
self._peripheral.delegate = self
central.connect(peripheral, options: nil)
}
}
func centralManager( central: CBCentralManager, didConnect peripheral: CBPeripheral) { //cant call this
print("connected to \(BEAN_NAME)")
peripheral.discoverServices(nil)
}
Logs :
BLE service is powered on
Did discover peripheral <CBPeripheral: 0x1740eef00, identifier = 4872623B-F872-443A-8A96-F4E1F84D6841, name = GoDoor in :), state = disconnected>
I created a demo project, which scans for Bluetooth LE devices and displays them in a list:
Check it out on github: quickies/BluetoothScanner.ios
Screenshot
I've solved this.
just need to change :
func centralManager(central: CBCentralManager, didConnect peripheral: CBPeripheral)
into this :
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
reference : Swift 3: Can't connect to peripheral via BLE
#IBAction func btnConnect(_ sender: UIButton){
self.appDelegate.bleManager.stopScan()
self.appDelegate.selectPeripheral = self.arrayPeripheral[sender.tag]
self.appDelegate.bleManager.connect(self.selectPeripheral, options: nil)
}
I have a device (named later "scanner") and other devices (named later "stone"). Scanner can scan stones and display their information on build in display. Scanner can send stones information via Bluetooth and I want to read this data and use it in my app. I started code connection implementation but I discovered a problem. Here is my code:
import UIKit
import CoreBluetooth
class BluetoothViewController: UIViewController {
var manager:CBCentralManager!
var peripheral:CBPeripheral!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
}
extension BluetoothViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
central.scanForPeripherals(withServices: nil, options: nil)
}
else {
print("Bluetooth not available.")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("peripheral \(peripheral)")
print("rssi \(RSSI)")
print("advertisementData: \(advertisementData)")
print("--------")
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print(peripheral)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print(peripheral)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print(peripheral)
}
}
extension BluetoothViewController: CBPeripheralDelegate {
}
The problem is scanner doesn't appear in
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
and
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
never call.
Note that my iPhone is connected with a scanner and scanner tell me the connection is working.
What I want to achieve?
I want to create viewcontroller which check if scanner is connected.
if connected then
get scan information
else
find device and connect
get scan information
Please help me. :)
Edit
In LightBlue Explorer app my scanner device doesn't appear.
But with this app works perfectly.
Maybe using CoreBluetooth is a wrong way to do this. What is better. If creators of above app can communicate thee is a possibility to do it.
Thanks #Paulw11's comment I realized my "scanner" uses iPod Accessory Protocol. To make sure I import ExternalAccessory framework and check for devices.
EAAccessoryManager.shared().showBluetoothAccessoryPicker(withNameFilter: nil, completion: nil)
After call this function I saw list of accessory devices and my scanner was there.
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 :)