首页 > 解决方案 > 快速将 BLE 特征值转换为字符串

问题描述

我遇到了一个毫无意义的问题。我认为我所做的一切对于 BLE 来说都是非常标准的。无论如何,我有一个 BLE 模块,我正在向 iOS 应用程序发送字符串数据,并且我在界面上显示这些数据。由于这是我第一次在 iOS 应用程序上使用 BLE 代码,我使用 adafruit 的教程作为指南,可以在此处找到:Adafruit 教程

正如我所说,非常标准的东西。这里没什么特别的。我编写的代码能够执行所有 BLE 步骤。但是,当它获取数据时,数据是/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0. 起初,我认为发送端的来源不正确。但是我打开了另一个测试应用程序,它可以让我看到发送的 BLE 数据,并且输入的数据格式正确。这一定是我的代码的问题。我不确定为什么会发生这种情况或问题是什么。我真的可以用另一双眼睛来看看我的代码是否有任何问题:

我的代码初始化代码:

required init(parent: ViewController) {

        self.parent = parent

        self.bluetoothOn = false;

        bodyTemperature = 0
        airPressure = 0
        lightLevel = 0
        fanSpeed = 0
        Humidity = 0
        otherBatteryLevel = 0
        wifiStatus = "Good"

        super.init()

        self.centralManager = CBCentralManager(delegate: self, queue: nil)
        //   self.periphal = CBPeripheralManager(delegate: self, queue: nil)
    }

我的 didupdateState 代码:

func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if #available(iOS 10.0, *) {
            if centralManager.state == CBManagerState.poweredOn{
                bluetoothOn = true
                self.centralManager.scanForPeripherals(withServices: [ATP_SERVICE_UUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
            }
        } else {
            // Fallback on earlier versions
        }
    }

我的 didDiscover 代码:

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        stopScan()
        self.blePeripheral = peripheral
        self.RSSI = RSSI
        self.blePeripheral.delegate = self
        centralManager?.connect(blePeripheral, options: nil)
        print("Found BLE module")
   //     blePeripheral.discoverServices([ATP_SERVICE_UUID])


    }

我的 didConnect 代码:

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        print("Connected to BLE device")
        centralManager?.stopScan()
        blePeripheral.delegate = self
        blePeripheral.discoverServices([ATP_SERVICE_UUID])
    }

我的 didDiscoverServices 代码:

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        guard let services = peripheral.services else{
            return
        }

        for service in services{
            peripheral.discoverCharacteristics([ATP_UART_WRITE14_UUID, ATP_UART_READ13_UUID, ATP_NOTIFY_UUID], for: service)
        }

        print("Discovered Services: \(services)")
    }

我的 didDiscoverCharacteristics 代码:

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        guard let characteristics = service.characteristics else{
            return
        }

        print ("Found \(characteristics.count) characteristics")

        for characteristic in characteristics{
            if characteristic.uuid.isEqual(ATP_UART_READ13_UUID){
                readCharacteristic = characteristic
              //  blePeripheral.setNotifyValue(true, for: readCharacteristic!)
                blePeripheral.readValue(for: characteristic)
                print("Rx Characteristic: \(characteristic.uuid)")

            }

            if(characteristic.uuid.isEqual(ATP_UART_WRITE14_UUID)){
                writeCharacteristic = characteristic
                print("Tx characteristic: \(characteristic.uuid)")

            }
        }
    }

我的 didupdateNotificationState 代码:

func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
        if(error != nil){
            print("Error changing notification state:\(String(describing: error?.localizedDescription))")

        } else {
            print("Characteristic's value subscribed")
        }

        if(characteristic.isNotifying){
            print("Subscribed. Notification has begun for: \(characteristic.uuid)")
        }
    }

最后,我的 didUpdateValueFor:

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        if characteristic == readCharacteristic{
       //     let ASCIIString = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue)

            var stringFromData = String(data: characteristic.value!, encoding: String.Encoding.ascii)
            if stringFromData != "" {
                let textArray = stringFromData!.components(separatedBy: "\n\r")

                for line in textArray{
                    if line.hasPrefix("bodyTemperature:") {
                        var splitString = line.characters.split(separator: ":").map(String.init)
                        bodyTemperature = Float(splitString[1])!
                        self.delegate?.PQEData(didRecieveData: bodyTemperature)
                    } else if line.hasPrefix("enclosurePressure:") {
                        var splitString = line.characters.split(separator: ":").map(String.init)
                        airPressure = Float(splitString[1])!
                        self.delegate?.PQEData(didRecieveData: airPressure)
                    } else if line.hasPrefix("lightLevel:") {
                        var splitString = line.characters.split(separator: ":").map(String.init)
                        lightLevel = Float(splitString[1])!
                        self.delegate?.PQEData(didRecieveData: lightLevel)
                    } else if line.hasPrefix("humidity:") {
                        var splitString = line.characters.split(separator: ":").map(String.init)
                        Humidity = Float(splitString[1])!
                        self.delegate?.PQEData(didRecieveData: Humidity)
                    } else if line.hasPrefix("BATT:") {
                        var splitString = line.characters.split(separator: ":").map(String.init)
                        otherBatteryLevel = Float(splitString[1])!
                        self.delegate?.PQEData(didRecieveData: otherBatteryLevel)
                    } else if line.hasPrefix("fanSpeed:") {
                        var splitString = line.characters.split(separator: ":").map(String.init)
                        fanSpeed = Int(splitString[1])!
                        self.delegate?.PQEData(didRecieveData: fanSpeed)
                    } else if line.hasPrefix("wifiStatus:") {
                        var splitString = line.characters.split(separator: ":").map(String.init)
                        wifiStatus = splitString[1]
                        self.delegate?.PQEData(didRecieveData: wifiStatus)
                    }
                }
            }
        }
    }

补充说明:

1)在 didDiscoverCharaceristics 函数中,我已经注释掉了对blePeripheral.setNotifyValue函数的调用。那是因为在呼叫peripheral.discoverCharacteristics呼叫​​的线路上,我已经发现了 NOTIFY 特征。我还使用未注释的 setNotifyValue 进行了测试,结果是相同的。

2) 我有一个名为 blePeriphal 的局部变量,它存储对 ble 设备外围设备的引用。同样适用于 writeCharacteristic 和 readCharacteristic

3) 当blePeripheral.setNotifyValue函数被取消注释时,didUpdateNotificationStateFor函数被执行。但是,该if(error != nil)陈述是正确的,我会得到的错误是:Error changing notification state:Optional("The request is not supported.")。我不确定这是否相关。但是,该didUpdateValueFor函数仍将被执行。

4)在函数中找到给我问题的代码,didUpdateValueFor该行是:var stringFromData = String(data: characteristic.value!, encoding: String.Encoding.ascii)

5)是的,我确实尝试过var stringFromData = String(data: characteristic.value!, encoding: String.Encoding.utf8)var stringFromData = String(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue)结果是一样的。StringFromData是全部/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0

更新:

6)所以经过一些测试,我遇到了一个可能相关的问题。代表只被调用一次,didUpdateValueFor之后就再也不会了。我通过每 1/4 秒不断发送一个字符串来验证这一点。

标签: iosswiftbluetooth-lowenergy

解决方案


推荐阅读