Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read and convert Bluetooth characteristic from byte data to proper values(Bluetooth for flutter)

I have to read and write some values to a Bike Smart trainer with BLE (Bluetooth Low Energy) used with Flutter. When I try to read the values from the GATT characteristic org.bluetooth.characteristic.supported_power_range (found on bluetooth.org site https://www.bluetooth.com/specifications/gatt/characteristics/ ) I get the return value of an Int List [0,0,200,0,1,0].

The GATT characteristic sais that there are 3 sint16 fields for Min., Max. and step size Watts (Power).

The Byte transmission order also sais that the least significant octet is transmitted first.

My guessings are, that the 3 parameters are returned in an Int array with 8bit value each. But I can't interpret the 200 for maybe the maximum Power setting. Because the smart trainer should provide max. 2300W Watts resistance (ELITE Drivo https://www.elite-it.com/de/produkte/home-trainer/rollentrainer-interaktive/drivo)

The Output results from this code snippet:

device.readCharacteristic(savedCharacteristics[Characteristics.SUPPORTED_POWER_RANGE]).then((List<int> result) {
  result.forEach((i) {
    print(i.toString());
  });
});
// result: [0,0,200,0,1,0]

Maybe some one of u knows how to interpret the binary/hex/dec values of the flutter_blue characteristic output. Or some hints would be great

Edit

For future readers, I got the solution. I'm a bit asheamed because I read the wrong characteristic.

The return value [0,0,200,0,1,0] was for supported resistance level. (which is 20% and the 200 shows the 20% with a resolution of 0.1 like described in the GATT spec) Max resistance Level with a resolution of 0.1

I also got a return value for the supported power level which was [0,0,160,15,1,0]. Now the solution how to read the 2 Bytes of max powre level: you get the 160,15 the spec sais LSO (least significant octet first, don't confuse it with LSB least significant bit first). In fact of that you have to read it like 15,160. now do the math with the first Byte 15*256 + 160 = 4000 and thats the correct maximum supported power of the trainer like in the datasheet.

I hope I help someone with that. Thanks for the two replys they are also correct and helped me to find my mistake.

like image 736
Xenos Avatar asked May 27 '19 17:05

Xenos


People also ask

What are Bluetooth characteristics?

Bluetooth can achieve convenience, flexibility, safety, low cost, low power data communication, and voice communication, so it is one of the mainstream technology of wireless domain network communication. Connected to other networks can bring a wider range of applications.

Does flutter support BLE?

Flutter library that handles BLE operations for multiple devices.


2 Answers

I had the same problem connecting to a Polar H10 to recover HR and RR intervals. It might not be 100% the same, but I think my case can guide you to solve yours.

I am receiving the same list as you like these two examples:

  1. [0,60]
  2. [16,61,524,2]

Looking at the specs of the GATT Bluetooth Heart Rate Service I figured that each element of the list retrieved matches 1 byte of the data transmitted by the characteristic you are subscripted to. For this service, the first byte, i.e., the first element of the list, has some flags to point out if there is an RR value after the HR value (16) or not (0). This is just two cases among the many different ones that can ocur depending on the flags values, but I think it shows how important this first byte can be.

After that, the HR value is coded as an unsigned integer with 8 bits (UINT8), that is, the HR values match the second element of the lists shown before. However, the RR interval is coded as an unsigned integer eith 16bits (UINT16), so it complicates the translation of those two last elements of the list #2 [16,61,524,2], because we should use 16 bits to get this value and the bytes are not in the correct order.

This is when we import the library dart:typed_data

import 'dart:typed_data';

...

_parseHr(List<int> value) {

// First sort the values in the list to interpret correctly the bytes
List<int> valueSorted = [];
valueSorted.insert(0, value[0]);
valueSorted.insert(1, value[1]);
for (var i=0; i< (value.length-3); i++) {
  valueSorted.insert(i+2, value[i+3]);
  valueSorted.insert(i+3, value[i+2]);
}

// Get flags directly from list
var flags = valueSorted[0];

// Get the ByteBuffer view of the data to recode it later
var buffer = new Uint8List.fromList(valueSorted).buffer; // Buffer bytes from list

if (flags == 0) {
  // HR
  var hrBuffer = new ByteData.view(buffer, 1, 1); // Get second byte
  var hr = hrBuffer.getUint8(0);                  // Recode as UINT8
  print(hr);
}

if (flags == 16) {
  // HR
  var hrBuffer = new ByteData.view(buffer, 1, 1); // Get second byte
  var hr = hrBuffer.getUint8(0);                  // Recode as UINT8

  // RR (more than one can be retrieved in the list)
  var nRr = (valueSorted.length-2)/2; // Remove flags and hr from byte count; then split in two since RR is coded as UINT16
  List<int> rrs = [];
  for (var i = 0; i < nRr; i++) {
    var rrBuffer = new ByteData.view(buffer, 2+(i*2), 2); // Get pairs of bytes counting since the 3rd byte
    var rr = rrBuffer.getUint16(0);                       // Recode as UINT16
    rrs.insert(i,rr);
  }
  print(rrs);
}

Hope it helps, the key is to get the buffer view of the sorted list, get the bytes that you need, and recode them as the standard points out.

like image 133
Salvador Moreno Avatar answered Nov 10 '22 18:11

Salvador Moreno


I used print(new String.fromCharCodes(value)); and that worked for me.

value is your return from List<int> value = await characteristic.read();

I thank ukBaz for his answer to this question. Write data to BLE device and read its response flutter?

like image 35
kaydrae Avatar answered Nov 10 '22 19:11

kaydrae