The repository contains two applications in the Toit language from Toitware, which allow access to a BLE device, connection to its services, and reading the required information.
The device I'm trying to access via BLE is a very inexpensive Chinese smart ring marketed as a smart health care device. In addition to fitness information, it can measure several parameters such as oxygen, heart rate, and blood pressure. According to the info from nRF application, the heart rate service (0x180D) is accessable on device, and this parameter can be measured, readed, and for instance saved to a cloud database using the REST API.
The main application module is the r998372.toit file. The following it's components are worth noting:
Class MeasurementHR_R998372 with a public measure function, which allows you to measure and read the heart rate and a result field: a map (hash table) containing the measurement result.
The functions of this class that support the measurement process are listed below:
- find_and_connect - searches for a device using the function
- find-with-service, which scans BLE nearby devices and, if successful, returns a ble.RemoteScannedDevice object.
Next, an attempt is made to connect to the found device and measure the heart_rate using the function
- connect_device
Note: access to heart_rate is by subscription, not by reading.
That's all there is to it. It's not much different from the process of accessing BLE devices in Android apps using packages like flutter_reactive_ble. It's just a bit simpler.
If the measured value is expected to have a timestamp, then it's necessary to somehow obtain the local time corresponding to the moment of measurement. I took advantage of the ability to use NTP (Network Time Protocol) to synchronize the clocks of computers & µcontrollers over a network: https://docs.toit.io/tutorials/misc/date-time.
This essentially concludes the description of the r998372 application. Below is a monitor log for two ESP32 S3 chips: the ESP32 S3 WROOM-N16R8 with 44 pins and ESP32 S3 ZERO-M variants. Oddly enough, there's no significant difference, although I thought the mini was less reliable. It's worth noting the ca = connect attempts parameter, which indicates the number of connection attempts to the device before performing a measurement. It's clear that this number is roughly the same for both chip variants.
- ESP32 S3 WROOM-N16R8 log
[jaguar] INFO: program ab8c3b05-36da-74ef-7336-f7322310292b started
Set time to 2025-11-16T08:27:14.153054Z by adjusting 489800h26m21.814105391s
08:27:21.494: [1] : [{"rssi":-81,"device":"R99 8372","heart rate":79,"units":"bpm","time":"2025/11/16 08:27:21.486","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":1}]
08:28:31.335: [2] : [{"rssi":-79,"device":"R99 8372","heart rate":79,"units":"bpm","time":"2025/11/16 08:28:31.330","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":2}]
08:29:37.083: [3] : [{"rssi":-77,"device":"R99 8372","heart rate":79,"units":"bpm","time":"2025/11/16 08:29:37.077","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":2}]
08:30:44.110: [4] : [{"rssi":-79,"device":"R99 8372","heart rate":79,"units":"bpm","time":"2025/11/16 08:30:44.102","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":1}]
08:31:52.330: [5] : [{"rssi":-79,"device":"R99 8372","heart rate":79,"units":"bpm","time":"2025/11/16 08:31:52.322","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":2}]
08:32:58.269: [6] : [{"rssi":-78,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 08:32:58.263","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":2}]
08:34:05.270: [7] : [{"rssi":-76,"device":"R99 8372","heart rate":79,"units":"bpm","time":"2025/11/16 08:34:05.263","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":1}]
08:35:17.118: [8] : [{"rssi":-76,"device":"R99 8372","heart rate":79,"units":"bpm","time":"2025/11/16 08:35:17.111","sensor":"b45310f9-5107-5db1-8c61-c3b37e7188ca","fa":1,"ca":4}]
Timer has been delete
[jaguar] INFO: program ab8c3b05-36da-74ef-7336-f7322310292b stopped
- ESP32 S3 ZERO-M log
[jaguar] INFO: program ab8c3b05-36da-74ef-7336-f7322310292b started
We already know the time is 2025-11-16T09:30:21.776579Z
09:30:28.360: [1] : [{"rssi":-79,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 09:30:28.354","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":2}]
09:31:38.205: [2] : [{"rssi":-79,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 09:31:38.201","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":3}]
09:32:45.975: [3] : [{"rssi":-77,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 09:32:45.971","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":1}]
09:33:48.765: [4] : [{"rssi":-77,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 09:33:48.762","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":1}]
09:34:53.485: [5] : [{"rssi":-77,"device":"R99 8372","heart rate":77,"units":"bpm","time":"2025/11/16 09:34:53.480","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":1}]
09:36:05.355: [6] : [{"rssi":-79,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 09:36:05.351","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":2}]
09:37:08.025: [7] : [{"rssi":-77,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 09:37:08.020","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":1}]
09:38:13.254: [8] : [{"rssi":-77,"device":"R99 8372","heart rate":78,"units":"bpm","time":"2025/11/16 09:38:13.250","sensor":"a3fb9ac6-4c3a-5bc8-a583-28a0e375fd8f","fa":1,"ca":1}]
Timer has been delete
[jaguar] INFO: program ab8c3b05-36da-74ef-7336-f7322310292b stopped
A few notes about the r998372db.toit app. It's essentially a clone of the r998372.toit app, augmented with the feature of storing measured data in Firebase RunTime DB. The app uses modules from the https://github.com/mk590901/Authentication-with-Toit-Security project almost unchanged. Can also check out the https://github.com/mk590901/Authentication-with-Toit repository to brush up on your authentication knowledge. The movie below shows the contents of the cloud database. This data is automatically collected when measuring heart❤️rate using the r998372db.toit