BLE shows connected even when 'didDisconnectPeripheral' is already called

127 views Asked by At

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
[]

But this what I see in the settings app after clean up.

0

There are 0 answers