Reading BLE service in Appinventor

I suspect you are using an old BLE extension, for an old tutorial.

ble extension version 2

1 Like

Thank you very much.
What extension do you recommend using?

I will try with this one:
https://mit-cml.github.io/extensions/

Your github source looks current.

However, extension upgrades are tricky.
Also read this entire thread for how to clean out old versions without losing blocks ...

Hello again
I have loaded the updated library. But I don’t know how to solve the data capture part.
Any help or ideas will be welcome.
Thanks for everything.HeartRateMonitor_02.aia (262.5 KB)

Hello
I have tried Readstring and Readbyte. I have also tried changing the UUIDs. And I still don’t receive data.
I only find examples made from Arduinos or the like, with their own GATT, but none with predefined GATT Services.
I do not know what else to do.

This thread mentions BLE heart rate measurement success.

Have you seen it yet?

Thank you.
I will study it slowly, but I see it difficult for my ability in this :frowning:

Hello again
I have tried to apply what they say in the post.
I connect well to the device, but my app does not read the data.

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.