How to get data from an object returned from a Bluetooth device using BLE

I have managed to write a program that connects to my power meter via Bluetooth, I have set up a profile for the power data and retrieved it via BLE. When I try and decode the output I get the following error:

"Details: Could not find symbol 'decodeNumber'"

I imagine this means that the value I am getting in my power characteristic is not a ByteArray but an Object, I am unsure how to get the data I need from this if that is the case. Here is my profile manager code:


import Toybox.BluetoothLowEnergy;

class ProfileManager {

public const POWER_METER_SERVICE = BluetoothLowEnergy.longToUuid(0x6E400001B5A3F393L, 0xE0A9E50E24DCCA9EL);

public const CYCLING_POWER_SERVICE = BluetoothLowEnergy.longToUuid(0x0000181800001000L, 0x800000805F9B34FBL);
public const CYCLING_POWER_MEASURMENT_CHARACTERISTIC = BluetoothLowEnergy.longToUuid(0x00002A6300001000L, 0x800000805F9B34FBL);
public const CYCLING_POWER_FEATURE_CHARACTERISTIC = BluetoothLowEnergy.longToUuid(0x00002A6500001000L, 0x800000805F9B34FBL);
public const CYCLING_POWER_CP_CHARACTERISTIC = BluetoothLowEnergy.longToUuid(0x00002A6600001000L, 0x800000805F9B34FBL);

private const _cyclingPowerDef = {
:uuid => CYCLING_POWER_SERVICE,
:characteristics => [{
:uuid => CYCLING_POWER_MEASURMENT_CHARACTERISTIC
}, {
:uuid => CYCLING_POWER_FEATURE_CHARACTERISTIC
}, {
:uuid => CYCLING_POWER_CP_CHARACTERISTIC
}]
};

//! Register the bluetooth profile
public function registerProfiles() as Void {
BluetoothLowEnergy.registerProfile(_cyclingPowerDef);
}

And my startRead code in device manager:

private function startRead() as Void {
System.println("Start Read");
var device = _device;
if (device != null) {
_cycleService = device.getService(_profileManager.CYCLING_POWER_SERVICE);
var cycleService = _cycleService;
if (cycleService != null) {
_feature = cycleService.getCharacteristic(_profileManager.CYCLING_POWER_FEATURE_CHARACTERISTIC);
_powerMeterData = cycleService.getCharacteristic(_profileManager.CYCLING_POWER_MEASURMENT_CHARACTERISTIC);
}
if (_powerMeterData instanceof Toybox.Lang.ByteArray){
System.println("yup");
}


value.decodeNumber(Lang.NUMBER_FORMAT_UINT8, {});
var pd = _powerMeterData.decodeNumber(Lang.NUMBER_FORMAT_UINT16, {});
System.println(pd);

System.println(_powerMeterData.toString());
}

Any help would be greatly appreciated

  • Ah okay, thank you I no longer get the error nut still get no output. Am I supposed to set _onCharRead to something in the onCharacteristicRead function as my code never enters the following if statement:

    if ((null != onCharRead) && onCharRead.stillAlive()) {
    (onCharRead.get() as DeviceManager).procCharWrite(value);
    System.println("read");

    }

    Is that perhaps something you need to do in one of the notify functions?

  • Have you tried putting a System.println() call right in your onCharacterisicRead() function?  Do the same in your onCharacteristicChanged function, just to make sure which is getting called.

  • The problem was I never initialized onCharRead my function now passes the value ByteArray to the following function in Device Manger:

    public function procCharWrite(value as ByteArray) as Void {
    var pd = value.decodeNumber(Lang.NUMBER_FORMAT_UINT16, {});
    System.println(pd);

    }

    But I still get the same error for decodeNumber despite it being a ByteArray that it is altering now:

    Error: Symbol Not Found Error
    Details: Could not find symbol 'decodeNumber'
    Stack:
    - procCharWrite() at C:\Users\PC-User\eclipse-workspace\PowerMeterBLE\source\DeviceManager.mc:102 0x100005ee
    - onCharacteristicRead() at C:\Users\PC-User\eclipse-workspace\PowerMeterBLE\source\PowerMeterBLEDelegate.mc:69 0x100002de

  • Actually, I think the problem is that value still isn't a ByteArray somehow as when I run the function like this:

    It only prints "got to proCharWrite" and not "it's a ByteArray"

    I do pass it in as a ByteArray in onCharacteristicRead:

    So I have no clue what type the "value" variable could be in proCharWrite

  • Value is the 3rd parameter passed to onCharacteristicRead().  It is a byre array.  right before the var onCharRead-_onCharRead;

    do

    System.println(value);

    and you should see what you are getting back from the read, 

  • Ah that seems to have solved it thank you, I now get an empty list for _powerMeterData but I have tried it with a different service and it works fine. I'll have to figure out whether the UUID is wrong or the power meter just isn't outputting anything as it's not being pushed properly. Thanks for the help much appreciated.

  • Apologies for all the questions but when you implement onCharacteristicChanged can you make it similar to onCharacteristicRead such that the notify looks like:

    public function notifyCharChanged(manager as DeviceManager) as Void {
    System.println("CharChanged");
    _onCharChanged = manager.weak();
    }

    and the function looks like:

    public function onCharacteristicChanged(characteristic as BluetoothLowEnergy.Characteristic,value as Lang.ByteArray) as Void {

    var onCharChanged = _onCharChanged;
    if ((null != onCharChanged) && onCharChanged.stillAlive()) {
    (onCharChanged.get() as DeviceManager).procCharWrite(value);
    System.println("read");
    }
    }

    Or do you have to implement a queue of some sort 

  • Again, the bye array is passed to onCharactisticChanged as "vaule".  It just like onCharacteristicRead, but no status is passed.

    As far as a queue, you'll likely need on for issuing thee read requests or ti turn on notify.

    So if you want to reead 3 xharacteristic, do the first one, then in onCharacteristicReadm the second one, then again in onCharacteristicRead again, the third one.

  • I hopefully will just need to read from one Characteristic if it gives me general power meter data. So in theory, if the value in the characteristic changes it will notify onCharacteristic by calling notifyCharChanged just as it does on onCharacteristicRead? Its just that I have put some print statements in the onCharChanged functions and they never print, but that could of course indicate that the value never changes

  • You need to send a message to enable notify on the devices I've used.  The NordicThingy52 Sample has some queuing to just send those requests.