如何解决 [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?