如何解决 [CoreBluetooth] 警告:对于具有多个设备连接的外围设备来说,这不是一个有效的特征

Posted

技术标签:

【中文标题】如何解决 [CoreBluetooth] 警告:对于具有多个设备连接的外围设备来说,这不是一个有效的特征【英文标题】:How to solve [CoreBluetooth] WARNING: is not a valid characteristic for peripheral with multiple device connection 【发布时间】:2019-05-12 19:10:32 【问题描述】:

我正在我的 ios 应用程序和我自己生产的几个 BLE 设备之间建立连接。仅连接一个设备时我没有问题,但是当两个设备都连接时,我收到其中一个错误:

[CoreBluetooth] 警告:,通知 = NO> 不是外围设备的有效特征

两台设备具有相同的服务名称和特征,但它们具有不同的名称和标识符,我使用该名称来识别其中一台或另一台设备。

如果只连接一个设备,相同的代码也可以正常工作。

我给你看我的代码:

//BLE starts here
extension BTManager: CBCentralManagerDelegate 
    func centralManagerDidUpdateState(_ central: CBCentralManager) 
        switch central.state 
        case .unknown:
            print("central.state is .unknown")
            connectionStatus = -5
        case .resetting:
            print("central.state is .resetting")
            connectionStatus = -4
        case .unsupported:
            print("central.state is .unsupported")
            connectionStatus = -3
        case .unauthorized:
            print("central.state is .unauthorized")
            connectionStatus = -2
        case .poweredOff:
            print("central.state is .poweredOff")
            connectionStatus = -1
        case .poweredOn:
            print("central.state is .poweredOn and searching mode")
            connectionStatus = 0
            //Scan
            if (!centralManager.isScanning)
                centralManager.scanForPeripherals(withServices: [insoleServiceCBUUID])
            
        
    

//Some peripheral found
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
                        advertisementData: [String : Any], rssi RSSI: NSNumber) 

        if(isInsolePresentInUserDefaults())

            let insolesDictionary = UserDefaults.standard.dictionary(forKey: "AriaSmartInsole") as! [String : String]

            if (peripheral.name! == insolesDictionary["leftInsole"])

                leftDevicePeripheral = peripheral
                leftDevicePeripheral.delegate = self
                centralManager.connect(leftDevicePeripheral)

            

            if (peripheral.name! == insolesDictionary["rightInsole"])

                rightDevicePeripheral = peripheral
                rightDevicePeripheral.delegate = self
                centralManager.connect(rightDevicePeripheral)

            

        //ELSE record couple devices
        else

                if (peripheral.name!.contains("Aria") && peripheral.name!.count > 8)

                    if (dispositiviTrovati.count > 1)

                        var dispositiviTrovatiArray: [CBPeripheral] = Array(Set(dispositiviTrovati))


                        for (index, element) in dispositiviTrovatiArray.enumerated()

                            let nextElement = index + 1

                            if (nextElement < dispositiviTrovatiArray.count)

                                let nomePrimoDevice: String = dispositiviTrovatiArray[index].name!
                                let primoDevice: CBPeripheral = dispositiviTrovatiArray[index]
                                let nomeSuccessivoDevice: String = dispositiviTrovatiArray[nextElement].name!
                                let successivoDevice: CBPeripheral = dispositiviTrovatiArray[nextElement]
                                let latoPrimoDevice: Character = nomePrimoDevice[nomePrimoDevice.index(nomePrimoDevice.startIndex, offsetBy: 5)]
                                let latoSuccessivoDevice: Character = nomeSuccessivoDevice[nomeSuccessivoDevice.index(nomeSuccessivoDevice.startIndex, offsetBy: 5)]

                                //HERE I SEARCH FOR LEFT DEVICE AND RIGHT DEVICE OF A COUPLE 
                                if (nomePrimoDevice.suffix(8) == nomeSuccessivoDevice.suffix(8) && latoPrimoDevice != latoSuccessivoDevice)

                                    var deviceDictionary: [String:String] = [:]
                                    var deviceSinistro: CBPeripheral?
                                    var deviceDestro: CBPeripheral?

                                    if(latoPrimoDevice == "S")
                                        deviceDictionary["leftInsole"] = nomePrimoDevice
                                        deviceSinistro = primoDevice
                                    else if(latoPrimoDevice == "D")
                                        deviceDictionary["rightInsole"] = nomePrimoDevice
                                        deviceDestro = primoDevice
                                    

                                    if(latoSuccessivoDevice == "S")
                                        deviceDictionary["leftInsole"] = nomeSuccessivoDevice
                                        deviceSinistro = successivoDevice
                                    else if(latoSuccessivoDevice == "D")
                                        deviceDictionary["rightInsole"] = nomeSuccessivoDevice
                                        deviceDestro = successivoDevice
                                    

                                    //BINGO
                                    if(deviceDictionary.count == 2)

                                        print(deviceDictionary.description)

                                        UserDefaults.standard.set(deviceDictionary, forKey: "AriaSmartInsole")

                                        //ASK FOR CONNECTION COUPLE OF DEVICE
                                        for device in dispositiviTrovati

                                            if (device.name! == UserDefaults.standard.dictionary(forKey: "AriaSmartInsole")!["leftInsole"] as! String)

                                                leftDevicePeripheral = deviceSinistro
                                                print(leftDevicePeripheral.name ?? "")
                                                leftDevicePeripheral.delegate = self
                                                centralManager.connect(leftDevicePeripheral)

                                            else if(device.name! == UserDefaults.standard.dictionary(forKey: "AriaSmartInsole")!["rightInsole"] as! String)

                                                rightDevicePeripheral = deviceDestro
                                                print(rightDevicePeripheral.name ?? "")
                                                rightDevicePeripheral.delegate = self
                                                centralManager.connect(rightDevicePeripheral)

                                            

                                        

                                    

                            

                        

                    

                

            

        

    

//CONNECTED TO DEVICES
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) 

        if (peripheral.name! == leftDevicePeripheral.name!)

            leftDevicePeripheral.isConnected = true
            leftDevicePeripheral.discoverServices([insoleServiceCBUUID])
            self.connectionStatus = 1

        else if(peripheral.name! == rightDevicePeripheral.name!)

            rightDevicePeripheral.isConnected = true
            rightDevicePeripheral.discoverServices([insoleServiceCBUUID])
            self.connectionStatus = 1

        

        if (leftDevicePeripheral.isConnected == true && rightDevicePeripheral.isConnected == true)

            self.connectionStatus = 2
            centralManager.stopScan()//Safe power

        

    


extension BTManager: CBPeripheralDelegate 

    //SERVICES FOUND
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) 

        if (error != nil)

            print("didDiscoverServices ERROR: ", error.debugDescription);

            return;

        

        var insoleServiceIsFound: Bool = false;

        for service in peripheral.services! 

            //FOUND MY SERVICE
            if (service.uuid == insoleServiceCBUUID)

                if (peripheral.name! == leftDevicePeripheral.name)

                    leftDevicePeripheral.insoleService = service
                    leftDevicePeripheral.discoverCharacteristics(nil, for: leftDevicePeripheral.insoleService)
                    insoleServiceIsFound = true;

                else if (peripheral.name! == rightDevicePeripheral.name)

                    rightDevicePeripheral.insoleService = service
                    rightDevicePeripheral.discoverCharacteristics(nil, for: rightDevicePeripheral.insoleService)
                    insoleServiceIsFound = true;

                

            

        

        if (!insoleServiceIsFound)

            print("didDiscoverServices: ARIA SERVICE NOT FOUND");

        

    

//CHARACTERISTIC OF MY SERVICE FOUND
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) 

        if (error != nil)

            print("didDiscoverCharacteristicsFor ERROR: ", error.debugDescription)
            return
        

        guard let characteristics = service.characteristics else 

            print("NO CHARACTERESTICS FOUND")
            return

        

        if (peripheral.name! == leftDevicePeripheral.name)

            for characteristic in characteristics 

                switch characteristic.uuid 

                case userEnableCBUUID:

                    leftDevicePeripheral.temperatureEnableCharacteristic = characteristic

                    if characteristic.properties.contains(.read) 
                        print("\(characteristic.uuid): properties contains .read")
                        leftDevicePeripheral.readValue(for: leftDevicePeripheral.temperatureEnableCharacteristic)
                    

                case batteryLevelCBUUID:

                    leftDevicePeripheral.batteryLevelCharacteristic = characteristic

                    if characteristic.properties.contains(.read) 
                        print("\(characteristic.uuid): properties contains .read")
                        leftDevicePeripheral.readValue(for: leftDevicePeripheral.batteryLevelCharacteristic)

                    
                default:
                    print("Unhandled Characteristic UUID: \(characteristic.uuid)")
                

            

        else if (peripheral.name! == rightDevicePeripheral.name)

            for characteristic in characteristics 

                switch characteristic.uuid 

                case userEnableCBUUID:

                    rightDevicePeripheral.temperatureEnableCharacteristic = characteristic

                    if characteristic.properties.contains(.read) 
                        print("\(characteristic.uuid): properties contains .read")
                        rightDevicePeripheral.readValue(for: rightDevicePeripheral.temperatureEnableCharacteristic)
                    

                case batteryLevelCBUUID:

                    rightDevicePeripheral.batteryLevelCharacteristic = characteristic

                    if characteristic.properties.contains(.read) 
                        print("\(characteristic.uuid): properties contains .read")
                        rightDevicePeripheral.readValue(for: rightDevicePeripheral.batteryLevelCharacteristic)
                    

                default:
                    print("Unhandled Characteristic UUID: \(characteristic.uuid)")
                

            

        

    

    //DATA RECEIVED
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) 

        print("Nome: \(peripheral.name ?? "")")

        if (error != nil)

            print("didUpdateValueFor ERROR: ", error.debugDescription)
            return

        


        if (peripheral.name! == leftDevicePeripheral.name)

            //Assegno valori prelevati alle caratteristiche
            switch characteristic.uuid 

            case userEnableCBUUID:

                print("userEnableValue: ", characteristic.value?[0] ?? "no value")
                //print("userTemp: ", characteristic.value?[0] ?? "no value")
                var data = characteristic.value
                var values = [UInt8](repeating:0, count:(data?.count)!)
                data?.copyBytes(to: &values, count:(data?.count)!)

                if(Int(values[0]) == 1)
                    leftDevicePeripheral.isThermalEnabled = true
                else if(Int(values[0]) == 0)
                    leftDevicePeripheral.isThermalEnabled = false
                
                print("LEFT userEnableValue for \(peripheral.description) in delegate:", leftDevicePeripheral.isThermalEnabled)
                print("\n")


            case batteryLevelCBUUID:

                //print("Battery level: ", characteristic.value?[0] ?? "no value")
                let data = characteristic.value
                var byte:UInt8 = 0
                data?.copyBytes(to: &byte, count: 1)
                leftDevicePeripheral.batteryLevel = Int(byte)
                print("BATTERY level: ", leftDevicePeripheral.batteryLevel)


            default:

                print("Unhandled Characteristic UUID: \(characteristic.uuid)")

            

        else if (peripheral.name! == rightDevicePeripheral.name)

            //Assegno valori prelevati alle caratteristiche
            switch characteristic.uuid 

            case userEnableCBUUID:

                print("RIght userEnableValue: ", characteristic.value?[0] ?? "no value")
                //print("userTemp: ", characteristic.value?[0] ?? "no value")
                var data = characteristic.value
                var values = [UInt8](repeating:0, count:(data?.count)!)
                data?.copyBytes(to: &values, count:(data?.count)!)

                if(Int(values[0]) == 1)
                    rightDevicePeripheral.isThermalEnabled = true
                else if(Int(values[0]) == 0)
                    rightDevicePeripheral.isThermalEnabled = false
                
                print("RIGHT userEnableValue for \(peripheral.description) in delegate:", leftDevicePeripheral.isThermalEnabled)
                print("\n")

            case batteryLevelCBUUID:

                //print("Battery level: ", characteristic.value?[0] ?? "no value")
                let data = characteristic.value
                var byte:UInt8 = 0
                data?.copyBytes(to: &byte, count: 1)
                let battLevel = Int(byte)
                print("BATTERY level: ", battLevel)


            default:

                print("Unhandled Characteristic UUID: \(characteristic.uuid)")

            

        

    

//FUNC THAT I CALL
func enableThermal(forDevice: String)

        //Se c'è connessione
        if(self.checkConnessione() > 0)

            var val = UInt8(1)
            let data = NSData(bytes: &val, length: MemoryLayout<UInt8>.size)

            print("Val: \(val)")
            print("Data: \(data.description)")

                if((forDevice == "left" || forDevice == "both") && leftDevicePeripheral.temperatureEnableCharacteristic != nil)

                    leftDevicePeripheral.writeValue(data as Data, for: leftDevicePeripheral.temperatureEnableCharacteristic, type: CBCharacteristicWriteType.withResponse)


                

                if((forDevice == "right" || forDevice == "both") && rightDevicePeripheral.temperatureEnableCharacteristic != nil)

                    rightDevicePeripheral.writeValue(data as Data, for: rightDevicePeripheral.temperatureEnableCharacteristic, type: CBCharacteristicWriteType.withResponse)



                

        //Error msg + Ritenta connessione
        else

            print("NO CONNECTION")

        

    

//Here I save my custom peripheral (left and right)

import Foundation
import CoreBluetooth

extension CBPeripheral

    struct Holder 

        static var insoleService: CBService!

        static var temperatureEnableCharacteristic: CBCharacteristic? 
        static var batteryLevelCharacteristic: CBCharacteristic?

        static var isConnected: Bool = false
        static var isThermalEnabled: Bool = false
        static var batteryLevel: Int = 0
        static var userTemperature: Double = 0
        static var topTemperature: Double = 0
        static var midTemperature: Double = 0
        static var bottomTemperature: Double = 0
        static var steps: Int = 0

    

    var insoleService: CBService 
        get 
            return Holder.insoleService
        
        set(newValue) 
            Holder.insoleService = newValue
        
    

    var temperatureEnableCharacteristic: CBCharacteristic 
        get 
            return Holder.temperatureEnableCharacteristic!
        
        set(newValue) 
            Holder.temperatureEnableCharacteristic = newValue
        
    


我希望在两台设备上都写,第一个,如果两者都连接,然后另一个。

谢谢。 爱神。

【问题讨论】:

您能否显示您发现特征并设置设备对象的代码。问题似乎就在那里。 完成。谢谢。 您的didDiscoverCharacteristics 代码如果它不是左侧外围设备,则不会执行任何操作。此外,如果您有“已保存”的外围设备,最好存储它们的identifiers 而不是它们的名称。这样您就可以使用retrievePeripheralsWithIdentifiers 并直接转到connect 并跳过设备发现。 (一旦连接,您仍然需要特征发现) 为了简化,我避免了其余代码。感谢您的建议,但它们并不能帮助我解决问题。 我看不出你显示的代码有问题,所以一定是你没有显示的代码。 【参考方案1】:

对于那些仍然坚持这一点的人:- 当您尝试订阅其不属于的外围设备上的特性时,就会发生这种情况。我看到了同样的问题并通过意识到我有特征列表来解决它,我将所有特征都附加到该列表中,因此当您要订阅外围设备不属于的特征时,通常会出现这样的问题发生。此外,我正在存储外围设备,然后在最近连接的设备上为这些特征订阅 notify 功能。这是导致该问题的另一个原因。

底线是,确保:- 您的特征被订阅到正确的外围设备

【讨论】:

以上是关于如何解决 [CoreBluetooth] 警告:对于具有多个设备连接的外围设备来说,这不是一个有效的特征的主要内容,如果未能解决你的问题,请参考以下文章

CoreBluetooth [警告] 未知错误:311 在 iOS 中使用 CoreBluetooth 框架重复连接和断开连接时发生

从字节中获取字符串(Corebluetooth,Swift)

如何获取/查找 CoreBluetooth.Framework?

如何仅使用 CoreBluetooth 扫描信标

XCode 错误/警告问题/如何对 XCode 缓存进行核对

CoreBluetooth 和 MFi