Reading BLE service in Appinventor

I am running out of things to suggest.

I notice you are registering in a Clock Timer.

You only need to register once per device channel.
Repeatedly registering has caused problems for other users.
Once you register, you don’t read bytes.
The bytes (whatever you registered for) arrive when they want, and trigger the event block.

Another thing to try after cleaning that up …
Instead of registering for bytes, register for shorts or for strings, and add events for those.

I have a couple of observations in your screen shots …

What is the 6 byte hex code in the stock BLE app you have connected to your BLE device?
Is it an address, and if so, why is it not used in your AI2 UUIDs?
Or is it a reading value, changing as you watch the app?

Also, I notice the Heart Rate Measurement in the app shown is verbose, a full sentence.
Did that app add the extra words, or are they being transmitted by the device on the BLE channel, thus requiring registering for strings instead of bytes?

Hello @ABG

I just put on the relevant part of the program. I have removed the clock and tried to capture by strings and integers, with no results. So it is now complete:

The data is sent from the device through a GATT Service Standard:

void updateSensorValue () {
// Do blocking calls or whatever is necessary for sensor polling.
// In our case, we simply update the HRM measurement.
hrmCounter ++;

// 100 <= HRM bps <= 175
if (hrmCounter == 175) {
hrmCounter = 100;
}

hrServicePtr-> updateHeartRate (hrmCounter);
}

I have consulted the HeartRateService.h library and I think it is an integer. I think the rest of the information in the string is added by nRF Connect.

Thanks a lot!!!

Looking at your new blocks, I see you Register For Bytes, but you did not include a BytesReceived event to catch them when (and if) they arrive.
That can’t be right.

I can’t find the controls that let me assign this thread to some one else with more BLE Heart Rate Monitor experience.

I suggest you add a post to this thread asking them (@Martin_Wood) to visit this thread Reading BLE service in Appinventor
and help you.

I’m in over my head.

One last thought for you …

Increasing the font size to 50 on the output label opens you up to seeing nothing because the text is too big to display. Leave that out for now.

It doesn’t hurt to have extra event blocks for the different when BLe.somethingReceived types.
If you go down the list of them (Strings, Reals, Shorts, etc.) and add events to catch and display them, maybe you will get lucky.

Hi,
There are several codes for BLE_heartrate, you have loaded that code in the device, because it can have this other …

Hello
I have read all your contributions, and thanks to your help I am improving:

I have tested this program with every data type. In some cases I already receive data, then the UUIDs are correct.
But I don’t get what I should. The program sends values between 100 and 174 each 500 ms:

void updateSensorValue () {
// Do blocking calls or whatever is necessary for sensor polling.
// In our case, we simply update the HRM measurement.
hrmCounter ++;

 // 100 <= HRM bps <= 175
 if (hrmCounter == 175) {
     hrmCounter = 100;
 }

 hrServicePtr-> updateHeartRate (hrmCounter);

}

And this is exactly what I receive for each type of data:

Shorts:
(26112)
(26368)
(26624)
(26880)

Strings:
(f)
(g)
(h)
(i)

Floats:
()
()
()
()

Integers:
()
()
()
()

Bytes:
Nothing

I don’t know how to fine tune this.
Thanks again.

Only
RegisterForString
and
StringReceived

hrmCounter ++;

f
g
h
i

I've adapted it to this, and the reading remains the same.

Did you notice how the received value increases by a constant amount each cycle?
It increases by 256 (a special number!) each short value arrives.
Each string also increases by 1 each time one arrives.

This makes me think you are measuring the ticking of a clock rather than the beating of a heart.

Because if the heart beats like metronome, you would be dead in 4 days. :wink:

"If the pattern of the heartbeat becomes regular as the tapping of woodpecker or the dripping of rain from the roof, the patient will be dead in four days." (Wang Shu-h, Chinese doctor, 3rd century AD)

This sentence can be found in almost every article / book on heart rate variability (HRV).

1 Like

Hello, I found this:

As an example, the Heart Rate Measurement characteristic is mandatory for the Heart Rate Service, and uses a UUID of 0x2A37. It starts with a single 8-bit value describing the HRM data format (whether the data is UINT8 or UINT16, etc.), and the goes on to include the heart rate measurement data that matches this config byte.

In an older BLE Heart Rate Project that I worked on in the middle of last year (hardly any memories of it), this was used:

Thank you @Anke, I started with that project but it was not capturing data.
The recommendation was that for the GATT service registration was better.

I was using this BLE device for heart beat measurement:


that worked fine for me. When I found it again :wink:, I’ll try to do another test with the new BLE ext.

I’m rather surprised by your report that using read/register for bytes returned nothing. The bytes representation is the most basic and essentially gives you access to the underlying packet without any interpretation of the values. Every other type requires some interpretation as each type is larger than 1 byte (other than bytes, of course).

I also want to point out that the heart rate service and heart rate measurement characteristic are a bit more sophisticated than just reading a value off the wire. In particular, the first byte of the packet is a bitfield containing flags that are used to interpret the remainder of the packet (Bluetooth SIG reference).

If we look at the underlying representation of your data, it will look like this (hex):

00 66
00 67
00 68
00 69
00 6A
...

The first byte is the flag byte, and the important bit here (pun intended) is that it indicates that there is only a single byte of data in the remainder of the packet. The second byte is the data byte. Your sketch mimics a heart rate monitor by simply counting from 100 to 175 and then resetting back to 100 ad infinitum and we can see that behavior exhibited here in your data.

When you attempt to interpret the data as short (16-bit) values, they are interpreted least-significant bit first, so the first value will be 0x6600, or 26112, the second will be 0x6700 (26368), etc. Likewise, with the interpretation as strings you end up seeing the ASCII interpretation of these values (f, g, h, …).

To facilitate working with this type of data, I’ve created the following extension:

It requires this version of the BLE extension and will not work with earlier versions of the extension:

And here is a test app that I used to test with an Arduino using a similar sketch to the one you showed above.

HeartRateTest.aia (196.5 KB)

2 Likes

Hello
The program works correctly @ewpatton, fantastic.
But this was only a first step of my work, if I want to use other GATT services, I think I could not with that library.
I have also thought to use the heart rate to send other types of data, but I see that it only reads values up to 250; Yes, I know that above 250 bpm we talk about impossible.

I have to think of other possibilities like UART. But I can't get it up and running on my max32630fthr.

Thank you very much once more for your help. You are great.

Yes, and I checked my BLE_HRM app with the new BLE ext.
Doesn't work, but worked fine with previous BLE version.

Could you expand on this?

This app works fine with the old BLE extension, but not with the new one.
BLE_HRM.aia (782.1 KB)