BluetoothLE cannot write list of different type values

Hi,
Can somebody help me to explain where is the catch with this issue?
Using BluetoothLE extension last ver. 20200828 I'm trying to send a list with 2 value to one characteristic.
first value in the list is an integer or hex, second one is an FLOAT like 0.21.
With any other int or hex value on second position on the list works fine,
but, When second value is FLOAT an error occurred.
invalid parameter in this case


or text to number parse error like this one
error on float
in this case

P.S. I need to write a list of 2 parameters to this characteristic...
like that (4,0.21) or ("4","0.21")
I found that a list like (8,4) or (7,3) on other characteristics, works fine because the final parse of entire list returns a string like (8,4) without double comma like in my case when the string sent to Bluetooth extension is (4,"0.21").
That commas are the issue problem or what?

The AI2 BLE and BlueTooth components use the name Byte for unsigned integer values between 0 and 255. If you want to send text, or fractional numbers, use a different Write Block. Maybe a different Characteristic ID or Service ID might be needed here for a different data stream format.

In the GATT server specs of my device, a cycling trainer like TACX, we have a specific Service & Characteristic UUIDS, so cannot be changed.
To change the target resistance level of this device, we need to write an array / a list of 2 parameters.
First parameter OPCODE in hex "0x04", second parameter an float variable like "0.21".
If i try to change the writing method to BluetoothLE.WriteFloatWithResponse the parameter list must take only float values, my hex OPCODE "0x04" being rejected by this procedure.

There are two possible approaches to this, depending on how BLE handles packets of data.
(I don't know the answer but it is easy to try.) There are two possibilities:

  • AI2 BLE can send a WriteBytes (make list(4)) followed immediately by a Write Floats (make list(0.21)). Will the receiving device will have access to that data stream as a single packet, with 0x04 at the front and a 4 byte float immediately after it?
  • If the first approach does not work, there is some data conversion work that can be done in Ai2 using the bit conversion math blocks and knowledge of the internal format of floating numbers. The WriteBytes Ai2 blocks offer the most flexibility in terms of what you can send in your data stream, at the expense of having to build a list of unsigned bytes (0-255) representing your mix of integers and floating point numbers.

I once coded an AI2 routine to convert a 32 bit datum into an IEEE754 floating number value in Ai2, at https://groups.google.com/g/mitappinventortest/c/Mnmk2wfTFK8/m/CkUsAbLtBgAJ

There are different flavors of floating point, depending on the base (2 or 10) and the accuracy (32 bit or 64 bit). What do you know of the float specs on your device?

Thank you for your quick responses, ABG!
The first approach doesn't work, I tried this before.
For the second one...
I already know your conversion routines,
I'll try to understand the conversion walkthrough and integrate it into my project.
I'll be back with my result.
Thanks a lot!

My conversion was backward to what you need.
Follow the Wikipedia article at


to get the bit pattern, and clip off bits 8 at a time, convert each 8 bit sequence to decimal, and add them to a list.

You should send a 5 item list, first item = 4.

The second approach is writing an array/list of 5 values (ex. [4, 54, 123, 43, 52] array like this one)
Obviously, the returned byte message from GATT is again, Invalid Parameter, because we need only 2 parameters 4 and 0.21 (or other float value between 0 and 100)
So what it needs is only [4, 0.21]
If I will send exactly this 2 params, the issue is resolved.
Probably, some conversion of this string into a hex can be an answer.
I found many blog discussions on the internet, on APP INVENTOR, THUNKABLE, KODULAR and similar environments about this issue.
My code for this one is:


Those 4 byte chunks are the result of float to binary conversion for 0.21 value.
Any way,
Let me/us know if you found something.
Thank you so much!
:clap: :clap: :clap:

Apparently, my idea of sending the two different typed parameters as a byte list failed.

Could you post a link to your device specs, in case some one else might have an idea?

2 Likes

After device connection with device ID or address like wifi address like F0:54:C2:86:9C:F6
In a Bluetooth GATT server we know that:

  1. The server provide some Services with addresses like UUID
    our service is FTMS - Fitness Machine Service witch UUID is 0x1826
  2. Those services contains some Characteristics also addressed by UUID
    our characteristic is Fitness Machine Control Point witch UUID is 0x2AD9 (chapter 4.16)
  3. This FTMS control point FMCP have security permissions to WRITE and NOTIFY
    like his name tells us FMCP provide many gates to write to with some values.
    Each gate is defined by another address, called OPCODE - operation code
    The scenario is to write consecutive values to 0x2AD9 characteristic, for each action, like this:
    a. Request control permission (chapter 4.16.2.1)- write value of 0x00 or simply integer 0 - zero [0];
    b. Start a training session - write value of 0x07 or simply integer 7 - seven [7];
    c. Set Target resistance level (chapter 4.16.2.5), write 0x04 followed by a float like 0.21 (with range from 0 to 100, with a resolution of 0.1 units) representing resistance level, an array or list of values like [0x04,0.21], where first param is OPCODE and second resistance level.
    The control point will return the result through OPCODE of 0x80, a standard one, witch will notify with value of 0x01 for success or 0x03 for invalid parameter(chapter 4.16.2.22, table 4.24).

bibliography:
FTMS_v1.0.pdf (1.3 MB)

That's it, all done.

If my quick browse of your manual is right, you should not be trying to send a float.

The parameter you want is scaled in units of 0.1, so it is a small integer (an octet?) that will be multiplied by 0.1 when interpreted by the server (machine) or your app.

Your list requirement sounds like a List Picker loaded with decimal values as Elements, but converted back into integers before transmission to the server.

P.S. I did not delve deeply into how server parameters are set in my manual skim, but I suspect (correct me if I am wrong) that is is done in multiple steps:

  • (client to server); Hi there, I want to set the agony level
  • (server to client) Okay, ready to set the agony level
  • (client to server) 121
  • (server to client) got it, 121

This was based on a quick skim, so it might be wrong.

Yes ABG, you're right, that's the scenario.
Iven the server permit float values, I'll be happy to transmit INT values between 1 and 100.
But trying to send integers like [4,25] server will return invalid parameter at the last answer step,
instead "(server to client) got it, 25"
At the request write permission, sending [0] to the same characteristic, and also to pause the training session sending [8,02] the answer from the server is success - according with parameters from that table in documentation of Bluetooth GATT.
If I was correctly understood you to send int values, instead float.
Sending int values was already tested with NRF connect from a mobile phone, also float.

Thanks ABG for the quick responses.
You rock!!!