How to Capture Real‑Time Heart Rate Data in a Taro Mini‑Program Using BLE
This tutorial walks through building a Taro mini‑program that connects to a BLE heart‑rate strap, discovers services and characteristics, reads device name and heart‑rate measurements, and handles data conversion, providing code examples and practical insights for mobile developers.
Background
The author started a weight‑loss plan and bought a heart‑rate strap, aiming to monitor heart rate while using a rowing machine. The strap does not display values directly and requires an app or device connection. The official app only shows real‑time data without charts.
The strap must be connected via an app; it does not show raw numbers.
The official app provides live heart‑rate data but cannot generate statistical charts.
Using the Gudong app, the strap can monitor heart‑rate changes during exercise, but the rowing machine is not a supported activity. The author also created a simple rowing‑machine metronome mini‑program.
Simple Bluetooth Overview
Bluetooth Low Energy (BLE) enables low‑power device communication. The tutorial briefly introduces central (client) and peripheral (server) devices, GAP (Generic Access Profile) for device discovery, and GATT (Generic Attribute Profile) for data exchange.
Central / Peripheral
Client (central): the author's phone. Server (peripheral): the heart‑rate strap, earphones, etc.
BLE
BLE offers lower energy consumption compared to classic Bluetooth. The tutorial focuses on GAP (device discovery) and GATT (service/characteristic interaction).
GAP (Generic Access Profile)
Controls device advertising and connection. Peripherals broadcast information; the central discovers and connects. Connections are exclusive, stopping advertising after establishment. iBeacon devices broadcast without connecting.
GATT (Generic Attribute Profile)
Defines services and characteristics. A service groups one or more characteristics. Characteristics are the smallest data units, with properties such as read, write, notify, indicate. Each has a unique UUID, some predefined by the Bluetooth SIG, others custom.
API Overview
Taro Bluetooth APIs
Taro.openBluetoothAdapter(option)
Initializes the Bluetooth module.
Taro.openBluetoothAdapter({
success: function (res) {
console.log("Bluetooth environment started:", res);
setInitStatus(true);
},
fail: function (err) {
if (err.errMsg.includes("fail already opened")) {
console.log("Bluetooth environment already started:", err);
setInitStatus(true);
} else {
console.log("Bluetooth environment start failed:", err);
setInitStatus(false);
}
},
});Taro.getBluetoothDevices(option)
Gets all discovered Bluetooth devices during the module's active period.
discoverInterval = setInterval(() => {
Taro.getBluetoothDevices({
success: async function (res) {
const canConnectDevices = res.devices.filter(
(item) =>
item.RSSI > -80 &&
!["未知设备", "MBeacon"].includes(item.name)
);
console.log("Discovered devices:", canConnectDevices);
setDeviceList(() => canConnectDevices);
},
});
}, 2000);You can also use Taro.onBluetoothDeviceFound(callback) to discover devices.
Taro.createBLEConnection(option)
Connects to a BLE device. If the device was previously discovered, you can pass its deviceId directly.
Taro.createBLEConnection({
deviceId,
success: function (res) {
console.log("Device connected", res);
setConnectDeviceId(deviceId);
Taro.onBLEConnectionStateChange(function (res) {
console.log(`Device ${res.deviceId} connection state changed: ${res.connected}`);
if (!res.connected) {
setConnectDeviceId("");
}
});
},
});Taro.getBLEDeviceServices(option)
Retrieves all services of a connected BLE device.
Taro.getBLEDeviceServices({
deviceId,
success: function (res) {
console.log('device services:', res.services);
}
});Taro.getBLEDeviceCharacteristics(option)
Gets all characteristics of a specific service.
Taro.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: function (res) {
console.log('device characteristics:', res.characteristics);
}
});Taro.readBLECharacteristicValue(option)
Reads the binary value of a characteristic (requires the characteristic to support read).
The read data must be obtained via the onBLECharacteristicValueChange callback.
Taro.notifyBLECharacteristicValueChange(option)
Enables notifications for characteristic value changes (requires notify or indicate support).
Taro.onBLECharacteristicValueChange(callback)
Listens for characteristic value change events; must enable notifications first.
Web Bluetooth API
References to MDN and other resources are provided for further reading.
Device Name Details
After calling getBLEDeviceServices, the service list shows the needed service (0x1800). Using getBLEDeviceCharacteristics, the characteristic 0x2A00 is identified as the device name, which has the read property.
Taro.onBLECharacteristicValueChange(function (characteristic) {
const buffer = characteristic.value;
const uint8Array = new Uint8Array(buffer);
console.log("uint8Array:", uint8Array);
const encodedString = String.fromCodePoint.apply(null, uint8Array);
console.log('Device name:', encodedString);
});
Taro.readBLECharacteristicValue({
deviceId,
serviceId: DeviceNameService,
characteristicId: DeviceNameCharacteristics,
});The output shows the device name (e.g., a specific earphone model).
Heart Rate Measurement Details
The required service and characteristic UUIDs are:
export const HEART_RATE_SERVICE_UUID = "0000180D-0000-1000-8000-00805F9B34FB";
export const HEART_RATE_CHARACTERISTIC_UUID = "00002A37-0000-1000-8000-00805F9B34FB";After connecting, subscribe to characteristic changes:
export const blueToothGetHeartRate = (deviceId, onHeartRateChange) => {
Taro.onBLECharacteristicValueChange(function (characteristic) {
const heartRateValue = getHeartRateValue(characteristic.value);
onHeartRateChange(heartRateValue);
});
Taro.notifyBLECharacteristicValueChange({
state: true,
deviceId,
serviceId: HEART_RATE_SERVICE_UUID,
characteristicId: HEART_RATE_CHARACTERISTIC_UUID,
});
};The heart‑rate data is obtained, but the raw bytes need decoding according to the Bluetooth Heart Rate Service specification.
Flag field (binary 10110) indicates heart‑rate format (uint8), sensor contact status, energy expended presence, and RR‑interval presence. The heart‑rate value (binary 1100101) equals 101 bpm. RR‑interval bytes (0x02, 0x52) decode to 594 ms, matching 60 000 ms / 101 bpm.
Conclusion and Open Questions
The implementation successfully reads heart‑rate data while using a metronome. Remaining questions include:
Why prepend "00" and slice the last two characters when converting a byte to a two‑digit hex string?
How does a phone obtain battery level information from earphones that do not expose the standard Battery Service (0x180F) and Battery Level characteristic (0x2A19) in the discovered services?
The author invites knowledgeable readers to provide answers.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
