--- # Copyright 2025 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. title: Heart Rate Monitor description: | Information on using the HealthService API to obtain information from the Heart Rate Monitor. guide_group: events-and-services order: 6 related_docs: - HealthService related_examples: - title: HRM Watchface url: https://github.com/pebble-examples/watchface-tutorial-hrm - title: HRM Activity url: https://github.com/pebble-examples/hrm-activity-example platform_choice: true --- The Pebble Time 2 and Pebble 2 (excluding SE model) {% guide_link tools-and-resources/hardware-information "devices" %} include a heart rate monitor. This guide will demonstrate how to use the ``HealthService`` API to retrieve information about the user's current, and historical heart rates. If you aren't already familiar with the ``HealthService``, we recommended that you read the {% guide_link events-and-services/health "Health guide" %} before proceeding. ## Enable Health Data
{% markdown {} %} Before your application is able to access the heart rate information, you will need to add `heath` to the `capabilities` array in your applications `package.json` file. ```js { ... "pebble": { ... "capabilities": [ "health" ], ... } } ``` {% endmarkdown %}
^CP^ Before your application is able to access heart rate information, you will need to enable the `USES HEALTH` option in your project settings on [CloudPebble]({{ site.data.links.cloudpebble }}). ## Data Quality Heart rate sensors aren't perfect, and their readings can be affected by improper positioning, environmental factors and excessive movement. The raw data from the HRM sensor contains a metric to indicate the quality of the readings it receives. The HRM API provides a raw BPM reading (``HealthMetricHeartRateRawBPM``) and a filtered reading (``HealthMetricHeartRateBPM``). This filtered value minimizes the effect of hand movement and improper sensor placement, by removing the bad quality readings. This filtered data makes it easy for developers to integrate in their applications, without needing to filter the data themselves. ## Obtaining the Current Heart Rate To obtain the current heart rate, you should first check whether the ``HealthMetricHeartRateBPM`` is available by using the ``health_service_metric_accessible`` method. Then you can obtain the current heart rate using the ``health_service_peek_current_value`` method: ```c HealthServiceAccessibilityMask hr = health_service_metric_accessible(HealthMetricHeartRateBPM, time(NULL), time(NULL)); if (hr & HealthServiceAccessibilityMaskAvailable) { HealthValue val = health_service_peek_current_value(HealthMetricHeartRateBPM); if(val > 0) { // Display HRM value static char s_hrm_buffer[8]; snprintf(s_hrm_buffer, sizeof(s_hrm_buffer), "%lu BPM", (uint32_t)val); text_layer_set_text(s_hrm_layer, s_hrm_buffer); } } ``` > **Note** this value is averaged from readings taken over the past minute, but due to the [sampling rate](#heart-rate-sample-periods) and our data filters, this value could be several minutes old. Use `HealthMetricHeartRateRawBPM` for the raw, unfiltered value. ## Subscribing to Heart Rate Updates The user's heart rate can also be monitored via an event subscription, in a similar way to the other health metrics. If you wanted your watchface to update the displayed heart rate every time the HRM takes a new reading, you could use the ``health_service_events_subscribe`` method. ```c static void prv_on_health_data(HealthEventType type, void *context) { // If the update was from the Heart Rate Monitor, query it if (type == HealthEventHeartRateUpdate) { HealthValue value = health_service_peek_current_value(HealthMetricHeartRateBPM); // Display the heart rate } } static void prv_init(void) { // Subscribe to health event handler health_service_events_subscribe(prv_on_health_data, NULL); // ... } ``` > **Note** The frequency of these updates does not directly correlate to the > sensor sampling rate. ## Heart Rate Sample Periods The default sample period is 10 minutes, but the system automatically controls the HRM sample rate based on the level of user activity. It increases the sampling rate during intense activity and reduces it again during inactivity. This aims to provide the optimal battery usage. ### Battery Considerations Like all active sensors, accelerometer, backlight etc, the HRM sensor will have a negative affect on battery life. It's important to consider this when using the APIs within your application. By default the system will automatically control the heart rate sampling period for the optimal balance between update frequency and battery usage. In addition, the APIs have been designed to allow developers to retrieve values for the most common use cases with minimal impact on battery life. ### Altering the Sampling Period Developers can request a specific sampling rate using the ``health_service_set_heart_rate_sample_period`` method. The system will use this value as a suggestion, but does not guarantee that value will be used. The actual sampling period may be greater or less due to other apps that require input from the sensor, or data quality issues. The shortest period you can currently specify is `1` second, and the longest period you can specify is `600` seconds (10 minutes). In this example, we will sample the heart rate monitor every second: ```c // Set the heart rate monitor to sample every second bool success = health_service_set_heart_rate_sample_period(1); ``` > **Note** This does not mean that you can peek the current value every second, > only that the sensor will capture more samples. ### Resetting the Sampling Period Developers **must** reset the heart rate sampling period when their application exits. Failing to do so may result in the heart rate monitor continuing at the increased rate for a period of time, even after your application closes. This is fundamentally different to other Pebble sensors and was designed so that applications which a reliant upon high sampling rates can be temporarily interupted for notifications, or music, without affecting the sensor data. ```c // Reset the heart rate sampling period to automatic health_service_set_heart_rate_sample_period(0); ``` ## Obtaining Historical Data If your application is using heart rate information, it may also want to obtain historical data to compare it against. In this section we'll look at how you can use the `health_service_aggregate` functions to obtain relevant historic data. Before requesting historic/aggregate data for a specific time period, you should ensure that it is available using the ``health_service_metric_accessible`` method. Then we'll use the ``health_service_aggregate_averaged`` method to obtain the average daily heart rate over the last 7 days. ```c // Obtain history for last 7 days time_t end_time = time(NULL); time_t start_time = end_time - (7 * SECONDS_PER_DAY); HealthServiceAccessibilityMask hr = health_service_metric_accessible(HealthMetricHeartRateBPM, start_time, end_time); if (hr & HealthServiceAccessibilityMaskAvailable) { uint32_t weekly_avg_hr = health_service_aggregate_averaged(HealthMetricHeartRateBPM, start_time, end_time, HealthAggregationAvg, HealthServiceTimeScopeDaily); } ``` You can also query the average `min` and `max` heart rates, but only within the past two hours (maximum). This limitation is due to very limited storage capacity on the device, but the implementation may change in the future. ```c // Obtain history for last 1 hour time_t end_time = time(NULL); time_t start_time = end_time - SECONDS_PER_HOUR; HealthServiceAccessibilityMask hr = health_service_metric_accessible(HealthMetricHeartRateBPM, start_time, end_time); if (hr & HealthServiceAccessibilityMaskAvailable) { uint32_t min_hr = health_service_aggregate_averaged(HealthMetricHeartRateBPM, start_time, end_time, HealthAggregationMin, HealthServiceTimeScopeOnce); uint32_t max_hr = health_service_aggregate_averaged(HealthMetricHeartRateBPM, start_time, end_time, HealthAggregationMax, HealthServiceTimeScopeOnce); } ``` ## Read Per-Minute History The ``HealthMinuteData`` structure contains multiple types of activity-related data that are recorded in a minute-by-minute fashion. Although this structure now contains HRM readings, it does not contain information about the quality of those readings. > **Note** Please refer to the > {% guide_link events-and-services/health#read-per-minute-history "Health Guide" %} > for futher information. ## Next Steps This guide covered the basics of how to interact with realtime and historic heart information. We encourage you to further explore the ``HealthService`` documentation, and integrate it into your next project.