I am trying to disconnect from a BLE device (raspberry-pi3), the delegates for disconnection are being triggered and upon checking explicitly if the peripheral is disconnected it shows that the peripheral is indeed disconnected. But, when I see in the settings app, I still see the device is connected.
Following is what I am trying:
Setup CBCentralManager as I come to the page.
func setupBLE() {
lblStatus.text = "Establising connection to the Scrubport"
self.manager = CBCentralManager(delegate: self, queue: .main)
}
Handle any state change if any
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
self.dismissAlert()
self.showLoader()
self.timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: false, block: { _ in
// No device found. Stop scanning.
})
self.manager?.scanForPeripherals(withServices: [SERVICE_UUID])
return
}
else if central.state == .unauthorized {
// Permission handlers here:
return
}
// Handle all other cases.
}
Upon find the device try connecting
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
self.peripheral = peripheral
connect()
}
func connect() {
guard let peripheral = peripheral else {
// Making sure we got the peripheral.
return
}
lblStatus.text = "Connecting..."
self.manager?.connect(peripheral)
}
Upon connection discover the service
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
lblStatus.text = "Connected, preparing device for transfer..."
self.timer.invalidate()
central.stopScan()
peripheral.delegate = self
peripheral.discoverServices([SERVICE_UUID])
}
Find the characteristics next
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let services = peripheral.services {
for service in services {
if service.uuid == SERVICE_UUID {
peripheral.discoverCharacteristics([CHARACTERISTICS_UUID], for: service)
}
}
}
}
Request notification
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let characteristics = service.characteristics {
for characteristic in characteristics {
if characteristic.uuid == self.CHARACTERISTICS_UUID {
self.characteristic = characteristic
peripheral.setNotifyValue(true, for: characteristic)
}
}
}
}
Upon getting an update for notification change I do the write and it is all successful.
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
if characteristic.isNotifying {
self.stopLoader()
lblStatus.text = "Notifying now.."
} else {
print("Un-notified")
print("Trying disconnection")
manager?.cancelPeripheralConnection(peripheral)
}
}
At the end I want to disconnect, or handle if app is closed or pressed back mid way
Trying clean up using following code:
fileprivate func cleanup() {
print("CLEANING")
guard let manager = manager else {
return
}
print("Check scan.")
if manager.isScanning {
print("Stopping scan.")
manager.stopScan()
}
// Don't do anything if we're not connected
// self.discoveredPeripheral.isConnected is deprecated
print("Checking peripheral connection")
guard peripheral?.state == .connected else {
print("No peripheral connected.")
return
}
// See if we are subscribed to a characteristic on the peripheral
print("Checking services")
guard let services = peripheral?.services else {
print("No services connection found.")
cancelPeripheralConnection()
return
}
print("Looping services")
for service in services {
print("Checking characteristics")
guard let characteristics = service.characteristics else {
print("No characteristics")
continue
}
print("Looping characteristics")
for characteristic in characteristics {
print("Comparing characteristics UUID is notifying")
if characteristic.uuid.isEqual(CHARACTERISTICS_UUID) && characteristic.isNotifying {
print("Un-notifying")
peripheral?.setNotifyValue(false, for: characteristic)
} else {
print("Nope not the one.", characteristic.isNotifying)
}
}
}
}
fileprivate func cancelPeripheralConnection() {
print("Remove peripheral connection")
guard let manager = manager, let peripheral = peripheral else {
print("Manager or peripheral not found!")
return
}
print("Cancelling peripheral connection.")
// If we've got this far, we're connected, but we're not subscribed, so we just disconnect
manager.cancelPeripheralConnection(peripheral)
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("SERVICE INFO: didDisconnectPeripheral", peripheral.name ?? "Unknown")
print("Was there an error?", error ?? "No error")
self.peripheral = nil
let peripherals = central.retrieveConnectedPeripherals(withServices: [])
let _peri = central.retrievePeripherals(withIdentifiers: [peripheral.identifier])
_peri.forEach { per in
print(per.state == .connected, "connected")
print(per.state == .connecting, "connecting")
print(per.state == .disconnected, "disconnected")
print(per.state == .disconnecting, "disconnecting")
}
print(peripherals)
}
Following are the logs that get printed on cleanup()
:
CLEANING
Check scan.
Checking peripheral connection
Checking services
Looping services
Checking characteristics
Looping characteristics
Comparing characteristics UUID is notifying
Un-notifying
Un-notified
Trying disconnection
SERVICE INFO: didDisconnectPeripheral raspberrypi-cm3
Was there an error? No error
false connected
false connecting
true disconnected
false disconnecting
[]