swiftarduinobluetooth-lowenergysensor-fusion

How to read 0-1023 sensor value from Arduino in Swift iOS App


I have an Arduino BLE device sending sensor analog read int values of 0-1023. I can read the values using the LightBlue app and reading the Characteristic using little endian. In my iOS Swift app, I can connect to the peripheral and read my custom UUID Characteristic and report that it is in fact receiving data but I am stuck on how to print that data in the debug window. It only says "Value received". Ultimately I want to display that data in a UITextfield in the UI in the app. Here's the 'didUpdateValueFor' code:

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    

  var characteristicFUELValue = NSString()

  guard rxFuelCharacteristic == characteristic,

        let rxFuelCharacteristic = characteristic.value,
        let dataString = NSString(data: rxFuelCharacteristic, encoding: String.Encoding.utf8.rawValue) else { return }

    characteristicFUELValue = dataString


  print("Value Recieved: \((characteristicFUELValue as String))")

  NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: "\((characteristicFUELValue as String))")
}

And here is the debug window readout:

Is Powered On. Function: centralManager(:didDiscover:advertisementData:rssi:),Line: 160 Peripheral Discovered: <CBPeripheral: 0x283331b80, identifier = B9EC3226-BC71-A657-B78A-A62B63FBB01B, name = Arduino, mtu = 0, state = disconnected> Function: centralManager(:didDiscover:advertisementData:rssi:),Line: 160 Duplicate Found. Peripheral Discovered: <CBPeripheral: 0x283331b80, identifier = B9EC3226-BC71-A657-B78A-A62B63FBB01B, name = Arduino, mtu = 0, state = disconnected> Found 1 characteristics. My Characteristic: D1DF5080-8938-11EC-A8A3-0242AC120002


Function: peripheral(_:didUpdateNotificationStateFor:error:),Line: 297 Characteristic's value subscribed Subscribed. Notification has begun for: D1DF5080-8938-11EC-A8A3-0242AC120002 Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved: Value Recieved:

Any help would be so appreciated. Thank you


Solution

  • You mentioned that you want to read the value as Int, but in code you are trying to read the value as String.

    If your are sure your data has at least 2 bytes, read it as UInt16:

    let fuelValue: UInt16 = rxFuelCharacteristic.withUnsafeBytes { $0.load(as: UInt16.self) }

    It you're not sure about the data size, I suggest to implement Data extension with readFuelValue() function, here is the playground:

    import Foundation
    
    extension Data {
        func readFuelValue() -> UInt? {
            if count >= 2 {
                return UInt(withUnsafeBytes { $0.load(as: UInt16.self) })
            } else if count == 1 {
                return UInt(withUnsafeBytes { $0.load(as: UInt8.self) })
            } else {
                return nil
            }
        }
    }
    
    func demo(_ bytes: [UInt8]) {
        let data = Data(bytes)
        let fuelValue = data.readFuelValue()
        print("\(bytes) => \(fuelValue)")
    }
    
    demo([])
    demo([0])
    demo([5])
    demo([0x00, 0x00])
    demo([0x09, 0x00])
    demo([0xFF, 0x00])
    demo([0x00, 0x01])
    demo([0x00, 0x02])
    demo([0x01, 0x02])
    demo([0x01, 0x02, 150])
    

    The output is:

    [] => nil
    [0] => Optional(0)
    [5] => Optional(5)
    [0, 0] => Optional(0)
    [9, 0] => Optional(9)
    [255, 0] => Optional(255)
    [0, 1] => Optional(256)
    [0, 2] => Optional(512)
    [1, 2] => Optional(513)
    [1, 2, 150] => Optional(513)