Search code examples
iosswiftbluetooth-lowenergycore-bluetooth

How to detect when a peripheral stops advertisement Date so that i can remove that peripheral form discovered device list?


When you connect to the Bluetooth Central Manager (CM) and start scanning for a device that has particular services, the CM will let you know when it finds a device.

func centralManager(
    central: CBCentralManager, 
    didDiscoverPeripheral peripheral: CBPeripheral, 
    advertisementData: [String : AnyObject], 
    RSSI: NSNumber)

However, there’s no corresponding “didUndiscoverPeripheral” type of function. In the case of my app, I needed to show an instruction screen, detect when the device was turned on (discovered), show a list of discovered devices and let the user select it. If the device timed out or was turned off(stops broadcasting advertisement Date), I needed to remove the device from the discovered device list.

It will be better if you can explain it with a working example.


Solution

  • Set the CBCentralManagerScanOptionAllowDuplicatesKey to true before the scan starts so that the didDiscover peripheral callBack method will execute every time when an advertisement packet is received.

    create a dictionary and a timer to keep track of the discovered device list. The key of the dictionary is peripheral identifier and value is counter initially set to 5 when the peripheral is discovered first time after that when an advertisement packet from the peripheral is received we keep on updating the counter value to 5 in didDiscover peripheral callback method.

        var discoveredPeripherals : [String: Int] = [String: Int]()
        var discoveryTimer : Timer =  Timer()
    

    ScheduledTimer when scan is starts :

        discoveryTimer =  Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateDiscoveredDevices), userInfo: nil, repeats: true)
    

    stop the timer when scan stops.

        discoveryTimer.invalidate()
    

    if the device stops advertisement and it is not connected then remove the device after 5 sec from the discovered device list.

    @objc func updateDiscoveredDevices() {
            peripherals.forEach{
                if discoveredPeripherals.index(forKey: $0.identifier.uuidString) != nil
                {
                    if discoveredPeripherals[$0.identifier.uuidString]! != 0
                    {
                        discoveredPeripherals[$0.bleDeviceGetId()]! -= 1
                    }
                    else{
                        if $0.state != CBPeripheralState.connected
                        {
                            removeDevice($0)
                        }
                    }
                }
            }
        }
    

    Thanks to @Paulw11 for suggesting this approach.