I am working on a sample project to get list of paired devices (iPhone and Andriod) through Bluetooth.below code is working find for me.but didDiscover method not being called. what is wrong with my code.any help will be appricated
Code :
transferServiceUUID = (CBUUID (string:"180D"))
func centralManagerDidUpdateState(_ central: CBCentralManager) {
guard central.state == .poweredOn else {
return
}
scanDevice()
}
func scanDevice() {
centralManager?.scanForPeripherals(
withServices: [transferServiceUUID!], options: [
CBCentralManagerScanOptionAllowDuplicatesKey : NSNumber(value: true as Bool)
]
)
}
func didReadPeripheral(_ peripheral: CBPeripheral, rssi: NSNumber) {
let name = peripheral.name
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Discovered \(peripheral.name) at \(RSSI)")
// if discoveredPeripheral != peripheral {
discoveredPeripheral = [peripheral]
print("Connecting to peripheral \(peripheral)")
centralManager?.connect(peripheral, options: nil)
// }
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("Failed to connect to \(peripheral). (\(error!.localizedDescription))")
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
centralManager?.stopScan()
peripheral.delegate = self
peripheral.discoverServices([transferServiceUUID!])
}
Related
I am trying to develop bluetooth based application that will provide users the functionality to share data via bluetooth pairing. I am facing issue while pairing the device.
This is my scenario
The user will login the application and will be prompted to enable bluetooth service. This is the code for the same :-
//MARK: - DECLARATIONS
var cbCentralManager : CBCentralManager?
var peripheral : CBPeripheral?
var peripherals: [CBPeripheral] = []
//MARK: - VIEW_METHODS
override func viewDidLoad() {
super.viewDidLoad()
self.setUpView()
}
func setUpView() {
cbCentralManager = CBCentralManager(delegate: self, queue: nil)
}
//MARK: - EXTENSION
extension ViewController : CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Bluetooth is enabled..")
central.scanForPeripherals(withServices: nil, options: nil)
} else {
print("Bluetooth is not enabled..")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard peripheral.name != nil else {return}
print("Sensor Found!")
//stopScan
cbCentralManager?.stopScan()
//connect
cbCentralManager?.connect(peripheral, options: nil)
self.peripheral = peripheral
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
//discover all service
peripheral.discoverServices(nil)
peripheral.delegate = self
}
In the next step, on the click of button, near by BLE devices will be scanned.
func startScan() {
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey:
NSNumber(value: false)]
peripherals = []
print("Now Scanning...")
self.timer.invalidate()
centralManager?.scanForPeripherals(withServices: nil, options: options)
Timer.scheduledTimer(timeInterval: 17, target: self, selector: #selector(self.cancelScan), userInfo: nil, repeats: false)
}
After the user selects a device to be paired from the list of scanned BLE devices, below code will be executed for establishing connection between devices.
func connectToDevice(device:CBPeripheral) {
centralManager = CBCentralManager(delegate: self, queue: .main)
self.blePeripheral = device
self.blePeripheral?.delegate = self
centralManager?.connect(self.blePeripheral!, options: nil)
}
The delegate methods are extended
extension HomeVC : CBPeripheralDelegate {
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
return
}
print("Peripheral manager is running")
}
//Check when someone subscribe to our characteristic, start sending the data
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
print("Device subscribe to characteristic")
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
// bleService = service
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
// bleService = service
}
print("Discovered Services: \(services)")
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
if let error = error {
print("\(error)")
let errorStr = "\(error)"
let alert = UIAlertController(title: "Alert", message: errorStr, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
}
}
I am stuck as I am not getting the alert for pairing devices. Can anyone guide me in this ?
Thanks in advance.
I am creating an app for BLE connection for iOS.
I can connect to the peripheral from central (iPhone6: iOS12.9) and send commands with
I am able to send commands with writevalue.
https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518949-setnotifyvalue
In the above setNotifyValue, there is a description that seems to be accepted by indicate.
The following methods of didUpdateValueFor do not return.
/// When changing the characteristic
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518708-peripheral
If you know how to implement receiving data in indicate, please let me know.
The sample code is shown below.
I'm still working on it, so there may be some garbage code, sorry.
// ViewController.swift
import UIKit
import CoreBluetooth
import os
class ViewController: UIViewController {
/// https://qiita.com/eKushida/items/def628e0eff6c106d467
var serviceUUID : CBUUID!
var characteristicUUID : CBUUID!
var responseCharacteristicUUID : CBUUID!
var centralManager: CBCentralManager!
var peripheral: CBPeripheral!
var writeCharacteristic: CBCharacteristic!
var responsCharacteristic: CBCharacteristic!
var data = Data()
#IBOutlet weak var dispLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
setup()
dispLabel.text = "Startup"
}
/// Initialize the central manager and UUID
private func setup() {
// Create an object representing the UUID.
self.serviceUUID = CBUUID(string: "XXXXX0000-XXXX-XXXX-XXXX-XXXXXXXXXX")
self.characteristicUUID = CBUUID(string: "XXXX2001-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
self.responseCharacteristicUUID = CBUUID(string: "XXXX2000-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
}
/// Pairing process
#IBAction func scan(_ sender: UIButton) {
print("Pairing process")
dispLabel.text = "Pairing process pressed"
self.centralManager = CBCentralManager(delegate: self, queue: nil)
}
/// Communication connection
#IBAction func connect(_ sender: UIButton) {
print("Communication connection")
/// https://qiita.com/MashMorgan/items/32500f158cb08d565786
/// https://knkomko.hatenablog.com/entry/2019/07/16/013443
let message = "**COMMAND**"
let command = message + "\r"
let writeData = Data(command.utf8)
print("writeData:" + String(data: writeData, encoding: .utf8)!)
peripheral.writeValue(writeData, for: writeCharacteristic, type: CBCharacteristicWriteType.withResponse)
}
}
//MARK : - CBCentralManagerDelegate
extension ViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
//wait for power on and scan
case CBManagerState.poweredOn:
let services: [CBUUID] = [serviceUUID] ///serviceUUID
centralManager.scanForPeripherals(withServices: nil, options: nil)
// centralManager.scanForPeripherals(withServices: services, options: nil)
print("isScanning:" + String(centralManager.isScanning))
default:
break
}
}
/// Called when a peripheral is discovered
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any],
rssi RSSI: NSNumber) {
self.peripheral = peripheral
print("peripheral.name:" + String(peripheral.name ? "") + " peripheral.id:" + peripheral.identifier.uuidString)
if "XXXXXXX" == peripheral.name {
//start connection
self.centralManager.connect(self.peripheral, options: nil)
//peripheral is found, stop scanning
centralManager.stopScan()
}
}
/// called when connected
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
print("Connection successful serviceUUID:" + serviceUUID.uuidString)
peripheral.delegate = self
peripheral.discoverServices([serviceUUID])
dispLabel.text = "Peripheral connection successful"
}
/// Called when the connection fails
func centralManager(_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?) {
print("Connection failed")
}
/// When disconnected
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnection: \(String(describing: error))")
}
}
//MARK : - CBPeripheralDelegate
extension ViewController: CBPeripheralDelegate {
/// Called when the characteristic is found
func peripheral(_ peripheral: CBPeripheral,
DidDiscoverCharacteristicsFor service: CBService,
error: Error?) {
if error ! = nil {
print(error.debugDescription)
return
}
guard let serviceCharacteristics = service.characteristics else {
// error handling
return
}
// Processing by characteristic
for characreristic in serviceCharacteristics {
if characreristic.uuid == characteristicUUID
{
// keep the characteristic for writing data
self.writeCharacteristic = characreristic
print("Write characreristic / UUID:" + characreristic.uuid.uuidString)
print("Write characreristic / properties: \(self.writeCharacteristic.properties)")
continue
}
if characreristic.uuid == responseCharacteristicUUID {
peripheral.setNotifyValue(true, for: characreristic)
self.responsesCharacteristic = characreristic
print("Responses characreristic / UUID:" + characreristic.uuid.uuidString)
print("Responses characreristic / properties: \(self.responsesCharacteristic.properties)")
continue
}
print("Other characreristic / UUID:" + characreristic.uuid.uuidString)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverIncludedServicesFor: CBService, error: Error?){
print("peripheral didDiscoverIncludedServicesFor")
}
/// When writing data to the characteristic (called when sending a command)
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
print("peripheral didWriteValueFor")
guard error == nil else {
print("Error when writing characteristic data: \(String(describing: error))")
// failure handling
return
}
print(characteristic.value)
}
func peripheral(peripheral: CBPeripheral,
didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic,
error: NSError?)
{
print("peripheral didUpdateNotificationStateForCharacteristic")
if let error = error {
print("Notify state update failed.... .error: \(error)")
} else {
print("Notify state update succeeded! isNotifying: \(characteristic.isNotifying)")
}
}
func peripheral(peripheral: CBPeripheral,
didUpdateValueForCharacteristic characteristic: CBCharacteristic,
error: NSError?)
{
print("peripheral didUpdateValueForCharacteristic")
if let error = error {
print("Data update notification error: \(error)")
return
}
print("Data update! value: \(characteristic.value)")
}
/// When changing the characteristic
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("peripheral didUpdateValueFor")
guard error == nil else {
print("Error getting/changing characteristic value: \(String(describing: error))")
// failure handling
return
}
guard let data = characteristic.value else {
print("characteristic.value")
// failure process
return
}
// data will be passed to us
print(data)
}
}
I have example iOS projects (Central & Peripheral) which send/receive indications: https://github.com/alexanderlavrushko/BLEProof-collection
setNotifyValue here is called similarly as you do, it should be fine.
I suggest to check the way how the characteristic is created and updated on the Peripheral side, iOS example link.
Also there is a great iOS application LightBlue which can simulate a BLE device, see this guide:
Central - the topic "Subscribing to Characteristics" might be useful
Peripheral - "Adding a New Virtual Peripheral", but use Blank device and configure services/characteristics you need
I am using CoreBluetooth to write an app that subscribes to one characteristic with one property: 'notify' which will allow a Raspberry Pi 3 to send an integer digit to be displayed on the app. I have created the service with this characteristic using Pybleno, a Python direct port of Bleno. I'm able to connect to the service and read its characteristic, but only for 30 seconds - after which the didDisconnect method is fired. On my central I use time.sleep() to alter the frequency at which the data is sent. I noticed that no delay causes the peripheral to disconnect after about 10 seconds, whereas 20-30ms delay causes a disconnect after 30 seconds. Any help would be great! Thank you. (I followed a Core Bluetooth tutorial for reading a Heart Rate monitor)
import UIKit
import CoreBluetooth
let TranslatorServiceCBUUID = CBUUID(string: "16dedcf4-027f-435f-b1e6-22e601276949")
let PredictionCharacteristicCBUUID = CBUUID(string: "16DEDCF4-027F-435F-B1E6-22E601276950")
var raspberryAsPeripheral: CBPeripheral!
class HRMViewController: UIViewController {
#IBOutlet weak var heartRateLabel: UILabel!
var centralManager: CBCentralManager!
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
// Make the digits monospaces to avoid shifting when the numbers change
heartRateLabel.font = UIFont.monospacedDigitSystemFont(ofSize: heartRateLabel.font!.pointSize, weight: .regular)
}
func onDigitReceived(_ digit: Int) {
var predictedNumber : String
if (digit == 16) {
predictedNumber = ""
}
else {
predictedNumber = String(digit)
}
heartRateLabel.text = predictedNumber
print("Predicted digit: \(digit)")
}
}
extension HRMViewController : CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .unknown:
print("central.state is .unknown")
case .resetting:
print("central.state is .resetting")
case .unsupported:
print("central.state is .unsupported")
case .unauthorized:
print("central.state is .unauthorized")
case .poweredOff:
print("central.state is .poweredOff")
case .poweredOn:
print("central.state is .poweredOn")
centralManager.scanForPeripherals(withServices: [TranslatorServiceCBUUID])
}
}
func centralManager(_ central : CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
print(peripheral)
raspberryAsPeripheral = peripheral
raspberryAsPeripheral.delegate = self
centralManager.stopScan()
centralManager.connect(raspberryAsPeripheral)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("you connected with the raspberry pi")
raspberryAsPeripheral.discoverServices([TranslatorServiceCBUUID])
}
}
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 peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
guard let characteristics = service.characteristics else { return }
for characteristic in characteristics {
print(characteristic)
if characteristic.properties.contains(.read) {
print("\(characteristic.uuid): properties contains .read")
peripheral.readValue(for: characteristic)
}
if characteristic.properties.contains(.notify) {
print("\(characteristic.uuid): properties contains .notify")
peripheral.setNotifyValue(true, for: characteristic)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic,
error: Error?) {
switch characteristic.uuid {
case PredictionCharacteristicCBUUID:
let whichNumber = predictedValue(from: characteristic)
onDigitReceived(whichNumber)
default:
print("Unhandled Characteristic UUID: \(characteristic.uuid)")
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("DISSSCONNNNECCCTEDDDDD")
}
private func predictedValue(from characteristic: CBCharacteristic) -> Int {
guard let characteristicData = characteristic.value else { return -1 }
let byteArray = [UInt8](characteristicData)
return Int(byteArray[0])
/*
let firstBitValue = byteArray[0] & 0x01
if firstBitValue == 0 {
// Heart Rate Value Format is in the 2nd byte
return Int(byteArray[1])
} else {
// Heart Rate Value Format is in the 2nd and 3rd bytes
return (Int(byteArray[1]) << 8) + Int(byteArray[2])
}
*/
}
}
I would like to get data from BLE device which is offering two services and among them, one is offering 3 characteristics and another one is offering 2 characteristics.
Could you please explain how to retrieve data from device in Swift.
Please have a look give proper code
extension PeripheralConnectedViewController: CBPeripheralDelegate {
func centralManager(_ central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {
if let error = error {
print("Error connecting peripheral: \(error.localizedDescription)")
}
}func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
print("Error discovering services: \(error.localizedDescription)")
}
peripheral.services?.forEach({ (service) in
services.append(service)
tableView.reloadData()
peripheral.discoverCharacteristics(nil, for: service)
})
}func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let error = error {
print("Error discovering service characteristics: \(error.localizedDescription)")
}
service.characteristics?.forEach({ characteristic in
if let descriptors = characteristic.descriptors {
print(descriptors)
}
print(characteristic.properties)
})
for newChar: CBCharacteristic in service.characteristics!{
peripheral.readValue(for: newChar)
peripheral.setNotifyValue(true, for: newChar)
}
}
func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
switch RSSI.intValue {
case -90 ... -60:
rssiLabel.textColor = .btOrange
break
case -200 ... -90:
rssiLabel.textColor = .btRed
break
default:
rssiLabel.textColor = .btGreen
}
rssiLabel.text = "\(RSSI)dB"
}func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if var enableValue = Character("?").asciiValue{
let enablyBytes = NSData(bytes: &enableValue, length: MemoryLayout<UInt8>.size)
self.peripheral.writeValue(enablyBytes as Data, for: characteristic, type: CBCharacteristicWriteType.withResponse)
}
print(characteristic)
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
}
I have gone and set up my CBCentralManager to search for devices and have the basic structure ready to receive and check on updated info.
I just cant seem to grasp on how to make a CBPeripheralManager ViewController and how to send my CBCentral data from the separate app on the press of a button. Simplest way being to send some string.
Here is my CBCentralManager ViewController.
class ViewController: NSViewController, CBCentralManagerDelegate,CBPeripheralDelegate {
let TRANSFER_SERVICE_UUID = "FB694B90-F49E-4597-8306-171BBA78F846"
let TRANSFER_CHARACTERISTIC_UUID = "EB6727C4-F184-497A-A656-76B0CDAC633A"
var centralManager: CBCentralManager?
var discoveredPeripheral: CBPeripheral?
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
// Do any additional setup after loading the view.
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if (central.state != .poweredOn) {
return
}
else{
let serviceUUID:[CBUUID] = [CBUUID(string: self.TRANSFER_SERVICE_UUID)]
centralManager!.scanForPeripherals(withServices: serviceUUID, options: nil)
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Discovered a peripheral")
print(peripheral.identifier)
print(peripheral.name!)
print(RSSI)
if(discoveredPeripheral != peripheral){
discoveredPeripheral = peripheral
centralManager?.stopScan()
print("Connection to peripheral")
centralManager?.connect(peripheral, options: nil)
}
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print(error!.localizedDescription)
centralManager?.cancelPeripheralConnection(peripheral)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Connected")
peripheral.delegate = self
let serviceUUIDS:[CBUUID] = [CBUUID(string: self.TRANSFER_SERVICE_UUID)]
peripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if error != nil{
centralManager?.cancelPeripheralConnection(peripheral)
}
for service:CBService in peripheral.services as [CBService]!{
peripheral.discoverCharacteristics(nil, for: service)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if error != nil{
centralManager?.cancelPeripheralConnection(peripheral)
}
for characteristic:CBCharacteristic in service.characteristics as [CBCharacteristic]!{
if characteristic.uuid.isEqual(CBUUID(string:self.TRANSFER_CHARACTERISTIC_UUID)){
peripheral.setNotifyValue(true, for: characteristic)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
let stringFromData:String = String(data: characteristic.value!, encoding: String.Encoding.utf8)!
//if
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
Is this done by doing the exact opposite?
I want to make sure I am looking at this in the right direction.
UPDATE
Inside the other application I am trying to begin this process like so:
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheralManager?.state != .poweredOn {
return
} else {
let serviceUUId:CBUUID = CBUUID(string:self.TRANSFER_SERVICE_UUID)
let mutable:CBMutableService = CBMutableService(type: serviceUUId, primary: true)
peripheralManager?.add(mutable)
}
}
Is the next step to start advertising?