pebble/src/fw/applib/health_service.h
Josh Soref 2e9824bf45 spelling: describing
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2025-01-28 21:32:35 -05:00

559 lines
29 KiB
C

/*
* Copyright 2024 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.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "drivers/ambient_light.h"
#include "services/common/hrm/hrm_manager.h"
#include "util/time/time.h"
//! @addtogroup Foundation
//! @{
//! @addtogroup EventService
//! @{
//! @addtogroup HealthService
//!
//! \brief Get access to health information like step count, sleep totals, etc.
//!
//! The HealthService provides your app access to the step count and sleep activity of the user.
//!
//! @{
// convenient macros to distinguish between health and no health.
// TODO: PBL-21978 remove redundant comments as a workaround around for SDK generator
#if defined(PBL_HEALTH)
//! Convenience macro to switch between two expressions depending on health support.
//! On platforms with health support the first expression will be chosen, the second otherwise.
#define PBL_IF_HEALTH_ELSE(if_true, if_false) (if_true)
#else
//! Convenience macro to switch between two expressions depending on health support.
//! On platforms with health support the first expression will be chosen, the second otherwise.
#define PBL_IF_HEALTH_ELSE(if_true, if_false) (if_false)
#endif
//! Health metric values used to retrieve health data.
//! For example, using \ref health_service_sum().
typedef enum {
//! The number of steps counted.
HealthMetricStepCount,
//! The number of seconds spent active (i.e. not resting).
HealthMetricActiveSeconds,
//! The distance walked, in meters.
HealthMetricWalkedDistanceMeters,
//! The number of seconds spent sleeping.
HealthMetricSleepSeconds,
//! The number of sleep seconds in the 'restful' or deep sleep state.
HealthMetricSleepRestfulSeconds,
//! The number of kcal (Calories) burned while resting due to resting metabolism.
HealthMetricRestingKCalories,
//! The number of kcal (Calories) burned while active.
HealthMetricActiveKCalories,
//! The heart rate, in beats per minute. This is a filtered value that is at most 15 minutes old.
HealthMetricHeartRateBPM,
//! The raw heart rate value of the most recent sample, in beats per minute.
HealthMetricHeartRateRawBPM,
} HealthMetric;
//! Type used to represent HealthMetric values
typedef int32_t HealthValue;
//! Type used as a handle to a registered metric alert (returned by
//! \ref health_service_register_metric_alert)
struct HealthMetricAlert;
typedef struct HealthMetricAlert HealthMetricAlert;
//! Return the sum of a \ref HealthMetric's values over a time range.
//! The `time_start` and `time_end` parameters define the range of time you want the sum for.
//! @note The value returned will be based on daily totals, weighted for the length of the
//! specified time range. This may change in the future.
//! @param metric The metric to query for data.
//! @param time_start UTC time of the earliest data item to incorporate into the sum.
//! @param time_end UTC time of the most recent data item to incorporate into the sum.
//! @return The sum of that metric over the given time range, if available.
HealthValue health_service_sum(HealthMetric metric, time_t time_start, time_t time_end);
//! Convenience wrapper for \ref health_service_sum() that returns the sum for today.
//! @param metric The metric to query.
//! @return The sum of that metric's data for today, if available.
HealthValue health_service_sum_today(HealthMetric metric);
//! Convenience function for peeking at the current value of a metric. This is useful for metrics
//! like \ref HealthMetricHeartRateBPM that represent instantaneous values. It is NOT applicable for
//! metrics like \ref HealthMetricStepCount that must be accumulated over time (it will return 0 if
//! passed that type of metric). This call is equivalent to calling
//! `health_service_aggregate_averaged(metric, time(NULL), time(NULL), HealthAggregationAvg,
//! HealthServiceTimeScopeOnce)`
//! @param metric The metric to query.
//! @return The current value of that metric, if available.
HealthValue health_service_peek_current_value(HealthMetric metric);
//! Used by \ref health_service_sum_averaged() to specify how the average is computed.
typedef enum {
//! No average computed. The result is the same as calling \ref health_service_sum().
HealthServiceTimeScopeOnce,
//! Compute average using the same day from each week. For example, every Monday if the passed
//! in time range falls on a Monday.
HealthServiceTimeScopeWeekly,
//! Compute average using either weekdays (Monday to Friday) or weekends (Saturday and Sunday),
//! depending on which day the passed in time range falls.
HealthServiceTimeScopeDailyWeekdayOrWeekend,
//! Compute average across all days of the week.
HealthServiceTimeScopeDaily,
} HealthServiceTimeScope;
//! Return the value of a metric's sum over a given time range between `time_start`
//! and `time_end`. Using this call you can specify the time range that you are interested in
//! getting the average for, as well as a `scope` specifier on how to compute an average of the sum.
//! For example, if you want to get the average number of steps taken from 12 AM (midnight) to 9 AM
//! across all days you would specify:
//! \code{.c}
//! time_t time_start = time_start_of_today();
//! time_t time_end = time_start + (9 * SECONDS_PER_HOUR);
//! HealthValue value = health_service_sum_averaged(HealthMetricStepCount, time_start,
//! time_end, HealthServiceTimeScopeDaily);
//! \endcode
//! If you want the average number of steps taken on a weekday (Monday to Friday) and today is a
//! Monday (in the local timezone) you would specify:
//! \code{.c}
//! time_start = time_start_of_today();
//! time_end = time_start + SECONDS_PER_DAY;
//! HealthValue value = health_service_sum_averaged(HealthMetricStepCount, time_start,
//! time_end, HealthServiceTimeScopeDailyWeekdayOrWeekend);
//! \endcode
//!
//! Note that this call is the same as calling `health_service_aggregate_averaged(metric,
//! time_start, time_end, HealthAggregationSum, scope)`
//!
//! @param metric Which \ref HealthMetric to query.
//! @param time_start UTC time of the start of the query interval.
//! @param time_end UTC time of the end of the query interval.
//! @param scope \ref HealthServiceTimeScope value describing how the average should be computed.
//! @return The average of the sum of the given metric over the given time range, if available.
HealthValue health_service_sum_averaged(HealthMetric metric, time_t time_start, time_t time_end,
HealthServiceTimeScope scope);
//! Used by \ref health_service_aggregate_averaged() to specify what type of aggregation to perform.
//! This aggregation is applied to the metric before the average is computed.
typedef enum {
//! Sum the metric. The result is the same as calling \ref health_service_sum_averaged(). This
//! operation is only applicable for metrics that accumulate, like HealthMetricStepCount,
//! HealthMetricActiveSeconds, etc.
HealthAggregationSum,
//! Use the average of the metric. This is only applicable for metrics that measure instantaneous
//! values, like HealthMetricHeartRateBPM
HealthAggregationAvg,
//! Use the minimum value of the metric. This is only applicable for metrics that measure
//! instantaneous values, like HealthMetricHeartRateBPM
HealthAggregationMin,
//! Use the maximum value of the metric. This is only applicable for metrics that measure
//! instantaneous values, like HealthMetricHeartRateBPM
HealthAggregationMax
} HealthAggregation;
//! Return the value of an aggregated metric over a given time range. This call is more
//! flexible than health_service_sum_averaged because it lets you specify which aggregation function
//! to perform.
//!
//! The aggregation function `aggregation` is applied to the metric `metric` over the given time
//! range `time_start` to `time_end` first, and then an average is computed based on the passed in
//! `scope`.
//!
//! For example, if you want to get the average number of steps taken from 12 AM (midnight) to 9 AM
//! across all days you would specify:
//! \code{.c}
//! time_t time_start = time_start_of_today();
//! time_t time_end = time_start + (9 * SECONDS_PER_HOUR);
//! HealthValue value = health_service_aggregate_averaged(HealthMetricStepCount, time_start,
//! time_end, HealthAggregationSum, HealthServiceTimeScopeDaily);
//! \endcode
//!
//! If you want to compute the average heart rate on Mondays and today is a Monday, you would
//! specify:
//! \code{.c}
//! time_t time_start = time_start_of_today(),
//! time_t time_end = time_start + SECONDS_PER_DAY,
//! HealthValue value = health_service_aggregate_averaged(HealthMetricHeartRateBPM, time_start,
//! time_end, HealthAggregationAvg, HealthServiceTimeScopeWeekly);
//! \endcode
//!
//! To get the average of the minimum heart rate seen on Mondays for example, you would instead
//! pass in `HealthAggregationMin`
//!
//! Certain HealthAggregation operations are only applicable to certain types of metrics. See the
//! notes above on \ref HealthAggregation for details. Use
//! \ref health_service_metric_aggregate_averaged_accessible to check for applicability at run
//! time.
//!
//! @param metric Which \ref HealthMetric to query.
//! @param time_start UTC time of the start of the query interval.
//! @param time_end UTC time of the end of the query interval.
//! @param aggregation the aggregation function to perform on the metric. This operation is
//! performed across the passed in time range `time_start` to `time_end`.
//! @param scope \ref HealthServiceTimeScope value describing how the average should be computed.
//! Use `HealthServiceTimeScopeOnce` to not compute an average.
//! @return The average of the aggregation performed on the given metric over the given time range,
//! if available.
HealthValue health_service_aggregate_averaged(HealthMetric metric, time_t time_start,
time_t time_end, HealthAggregation aggregation,
HealthServiceTimeScope scope);
//! Health-related activities that can be accessed using
// \ref health_service_peek_current_activities() and \ref health_service_activities_iterate().
typedef enum {
//! No special activity.
HealthActivityNone = 0,
//! The 'sleeping' activity.
HealthActivitySleep = 1 << 0,
//! The 'restful sleeping' activity.
HealthActivityRestfulSleep = 1 << 1,
//! The 'walk' activity.
HealthActivityWalk = 1 << 2,
//! The 'run' activity.
HealthActivityRun = 1 << 3,
//! The 'generic' activity.
HealthActivityOpenWorkout = 1 << 4,
} HealthActivity;
//! A mask value representing all available activities
#define HealthActivityMaskAll ((HealthActivityOpenWorkout << 1) - 1)
//! Expresses a set of \ref HealthActivity values as a bitmask.
typedef uint32_t HealthActivityMask;
//! Return a \ref HealthActivityMask containing a set of bits, one set for each
//! activity that is currently active.
//! @return A bitmask with zero or more \ref HealthActivityMask bits set as appropriate.
HealthActivityMask health_service_peek_current_activities(void);
//! Callback used by \ref health_service_activities_iterate().
//! @param activity Which activity the caller is being informed about.
//! @param time_start Start UTC time of the activity.
//! @param time_end End UTC time of the activity.
//! @param context The `context` parameter initially passed
//! to \ref health_service_activities_iterate().
//! @return `true` if you are interested in more activities, or `false` to stop iterating.
typedef bool (*HealthActivityIteratorCB)(HealthActivity activity, time_t time_start,
time_t time_end, void *context);
//! Iteration direction, passed to \ref health_service_activities_iterate().
//! When iterating backwards (`HealthIterationDirectionPast`), activities that have a greater value
//! for `time_end` come first.
//! When iterating forward (`HealthIterationDirectionFuture`), activities that have a smaller value
//! for `time_start` come first.
typedef enum {
//! Iterate into the past.
HealthIterationDirectionPast,
//! Iterate into the future.
HealthIterationDirectionFuture,
} HealthIterationDirection;
//! Iterates backwards or forward within a given time span to list all recorded activities.
//! For example, this can be used to find the last recorded sleep phase or all deep sleep phases in
//! a given time range. Any activity that overlaps with `time_start` and `time_end` will be
//! included, even if the start time starts before `time_start` or end time ends after `time_end`.
//! @param activity_mask A bitmask containing set of activities you are interested in.
//! @param time_start UTC time of the earliest time you are interested in.
//! @param time_end UTC time of the latest time you are interested in.
//! @param direction The direction in which to iterate.
//! @param callback Developer-supplied callback that is called for each activity iterated over.
//! @param context Developer-supplied context pointer that is passed to the callback.
void health_service_activities_iterate(HealthActivityMask activity_mask, time_t time_start,
time_t time_end, HealthIterationDirection direction,
HealthActivityIteratorCB callback, void *context);
//! Possible values returned by \ref health_service_metric_accessible().
//! The values are used in combination as a bitmask.
//! For example, to check if any data is available for a given request use:
//! bool any_data_available = value & HealthServiceAccessibilityMaskAvailable;
typedef enum {
//! Return values are available and represent the collected health information.
HealthServiceAccessibilityMaskAvailable = 1 << 0,
//! The user hasn't granted permission.
HealthServiceAccessibilityMaskNoPermission = 1 << 1,
//! The queried combination of time span and \ref HealthMetric or \ref HealthActivityMask
//! is currently unsupported.
HealthServiceAccessibilityMaskNotSupported = 1 << 2,
//! No samples were recorded for the given time span.
HealthServiceAccessibilityMaskNotAvailable = 1 << 3,
} HealthServiceAccessibilityMask;
//! Check if a certain combination of metric and time span is accessible using
//! \ref health_service_sum by returning a value of \ref HealthServiceAccessibilityMask. Developers
//! should check if the return value is \ref HealthServiceAccessibilityMaskAvailable before calling
//! \ref health_service_sum.
//!
//! Note that this call is the same as calling `health_service_metric_averaged_accessible(metric,
//! time_start, time_end, HealthServiceTimeScopeOnce)`
//!
//! @param metric The metric to query for data.
//! @param time_start Earliest UTC time you are interested in.
//! @param time_end Latest UTC time you are interested in.
//! @return A \ref HealthServiceAccessibilityMask representing the accessible metrics
//! in this time range.
HealthServiceAccessibilityMask health_service_metric_accessible(
HealthMetric metric, time_t time_start, time_t time_end);
//! Check if a certain combination of metric, time span, and scope is accessible for calculating
//! summed, averaged data by returning a value of \ref HealthServiceAccessibilityMask. Developers
//! should check if the return value is \ref HealthServiceAccessibilityMaskAvailable before calling
//! \ref health_service_sum_averaged.
//!
//! Note that this call is the same as calling
//! `health_service_metric_aggregate_averaged_accessible(metric, time_start, time_end,
//! HealthAggregationSum, HealthServiceTimeScopeOnce)`
//!
//! @param metric The metric to query for averaged data.
//! @param time_start Earliest UTC time you are interested in.
//! @param time_end Latest UTC time you are interested in.
//! @param scope \ref HealthServiceTimeScope value describing how the average should be computed.
//! @return A \HealthServiceAccessibilityMask value describing whether averaged data is available.
HealthServiceAccessibilityMask health_service_metric_averaged_accessible(
HealthMetric metric, time_t time_start, time_t time_end, HealthServiceTimeScope scope);
//! Check if a certain combination of metric, time span, aggregation operation, and scope is
//! accessible for calculating aggregated, averaged data by returning a value of
//! \ref HealthServiceAccessibilityMask. Developers should check if the return value is
//! \ref HealthServiceAccessibilityMaskAvailable before calling
//! \ref health_service_aggregate_averaged.
//! @param metric The metric to query for averaged data.
//! @param time_start Earliest UTC time you are interested in.
//! @param time_end Latest UTC time you are interested in.
//! @param aggregation The aggregation to perform
//! @param scope \ref HealthServiceTimeScope value describing how the average should be computed.
//! @return A \HealthServiceAccessibilityMask value describing whether averaged data is available.
HealthServiceAccessibilityMask health_service_metric_aggregate_averaged_accessible(
HealthMetric metric, time_t time_start, time_t time_end, HealthAggregation aggregation,
HealthServiceTimeScope scope);
//! Check if a certain combination of metric, \ref HealthActivityMask and time span is
//! accessible. Developers should check if the return value is
//! \ref HealthServiceAccessibilityMaskAvailable before calling any other HealthService APIs that
//! involve the given activities.
//! @param activity_mask A bitmask of activities you are interested in.
//! @param time_start Earliest UTC time you are interested in.
//! @param time_end Latest UTC time you are interested in.
//! @return A \ref HealthServiceAccessibilityMask representing which of the
//! passed \ref HealthActivityMask values are available under the given constraints.
HealthServiceAccessibilityMask health_service_any_activity_accessible(
HealthActivityMask activity_mask, time_t time_start, time_t time_end);
//! Health event enum. Passed into the \ref HealthEventHandler.
typedef enum {
//! All data is considered as outdated and apps should re-read all health data.
//! This happens after an app is subscribed via \ref health_service_events_subscribe(),
//! on a change of the day, or in other cases that significantly change the underlying data.
HealthEventSignificantUpdate = 0,
//! Recent values around \ref HealthMetricStepCount, \ref HealthMetricActiveSeconds,
//! or \ref HealthMetricWalkedDistanceMeters have changed.
HealthEventMovementUpdate = 1,
//! Recent values around \ref HealthMetricSleepSeconds, \ref HealthMetricSleepRestfulSeconds,
//! \ref HealthActivitySleep, and \ref HealthActivityRestfulSleep changed.
HealthEventSleepUpdate = 2,
//! A metric has crossed the threshold set by \ref health_service_register_metric_alert.
HealthEventMetricAlert = 3,
//! Value of \ref HealthMetricHeartRateBPM or \ref HealthMetricHeartRateRawBPM has changed.
HealthEventHeartRateUpdate = 4,
} HealthEventType;
//! Developer-supplied event handler, called when a health-related event occurs after subscribing
//! via \ref health_service_events_subscribe();
//! @param event The type of health-related event that occured.
//! @param context The developer-supplied context pointer.
typedef void (*HealthEventHandler)(HealthEventType event, void *context);
//! Subscribe to HealthService events. This allocates a cache on the application's heap of up
//! to 2048 bytes that will be de-allocated if you call \ref health_service_events_unsubscribe().
//! If there's not enough heap available, this function will return `false` and will not
//! subscribe to any events.
//! @param handler Developer-supplied event handler function.
//! @param context Developer-supplied context pointer.
//! @return `true` on success, `false` on failure.
bool health_service_events_subscribe(HealthEventHandler handler, void *context);
//! Unsubscribe from HealthService events.
//! @return `true` on success, `false` on failure.
bool health_service_events_unsubscribe(void);
//! Set the desired sampling period for heart rate readings. Normally, the system will sample the
//! heart rate using a sampling period that is automatically chosen to provide useful information
//! without undue battery drain (it automatically samples more often during periods of intense
//! activity, and less often when the user is idle). If desired though, an application can request a
//! specific sampling period using this call. The system will use this as a suggestion, but does not
//! guarantee that the requested period will be used. The actual sampling period may be greater or
//! less due to system needs or heart rate sensor reading quality issues.
//!
//! Each time a new heart rate reading becomes available, a `HealthEventHeartRateUpdate` event will
//! be sent to the application's `HealthEventHandler`. The sample period request will remain in
//! effect the entire time the app is running unless it is explicitly cancelled (by calling this
//! method again with 0 as the desired interval). If the app exits without first cancelling the
//! request, it will remain in effect even for a limited time afterwards. To determine how long it
//! will remain active after the app exits, use
//! `health_service_get_heart_rate_sample_period_expiration_sec`.
//!
//! Unless the app explicitly needs to access to historical high-resolution heart rate data, it is
//! best practice to always cancel the sample period request before exiting in order to maximize
//! battery life. Historical heart rate data can be accessed using the
//! `health_service_get_minute_history` call.
//! @param interval_sec desired interval between heart rate reading updates. Pass 0 to
//! go back to automatically chosen intervals.
//! @return `true` on success, `false` on failure
bool health_service_set_heart_rate_sample_period(uint16_t interval_sec);
//! Return how long a heart rate sample period request (sent via
//! `health_service_set_heart_rate_sample_period`) will remain active after the app exits. If
//! there is no current request by this app, this call will return 0.
//! @return The number of seconds the heart rate sample period request will remain active after
//! the app exits, or 0 if there is no active request by this app.
uint16_t health_service_get_heart_rate_sample_period_expiration_sec(void);
//! Register for an alert when a metric crosses the given threshold. When the metric crosses this
//! threshold (either goes above or below it), a \ref HealthEventMetricAlert event will be
//! generated. To cancel this registration, pass the returned \ref HealthMetricAlert value to
//! \ref health_service_cancel_metric_alert. The only metric currently supported by this call is
//! \ref HealthMetricHeartRateBPM, but future versions may support additional metrics. To see if a
//! specific metric is supported by this call, use:
//! \code{.c}
//! time_t now = time(NULL);
//! HealthServiceAccessibilityMask accessible =
//! health_service_metric_aggregate_averaged_accessible(metric, now, now, HealthAggregationAvg,
//! HealthServiceTimeScopeOnce);
//! bool alert_supported = (accessible & HealthServiceAccessibilityMaskAvailable);
//! \endcode
//!
//! In the current implementation, only one alert per metric can be registered at a time. Future
//! implementations may support two or more simulataneous alert registrations per metric. To change
//! the alert threshold in the current implementation, cancel the original registration
//! using `health_service_cancel_metric_alert` before registering the new threshold.
//! @param metric Which \ref HealthMetric to query.
//! @param threshold The threshold value.
//! @return handle to the alert registration on success, NULL on failure
HealthMetricAlert *health_service_register_metric_alert(HealthMetric metric, HealthValue threshold);
//! Cancel an metric alert previously created with \ref health_service_register_metric_alert.
//! @param alert the \ref HealthMetricAlert previously returned by
//! \ref health_service_register_metric_alert
//! @return `true` on success, `false` on failure
bool health_service_cancel_metric_alert(HealthMetricAlert *alert);
//! Structure representing a single minute data record returned
//! by \ref health_service_get_minute_history().
//! The `orientation` field encodes the angle of the watch in the x-y plane (the "yaw") in the
//! lower 4 bits (360 degrees linearly mapped to 1 of 16 different values) and the angle to the
//! z axis (the "pitch") in the upper 4 bits.
//! The `vmc` value is a measure of the total amount of movement seen by the watch. More vigorous
//! movement yields higher VMC values.
typedef struct {
uint8_t steps; //!< Number of steps taken in this minute.
uint8_t orientation; //!< Quantized average orientation.
uint16_t vmc; //!< Vector Magnitude Counts (vmc).
bool is_invalid: 1; //!< `true` if the item doesn't represents actual data
//!< and should be ignored.
AmbientLightLevel light: 3; //!< Instantaneous light level during this minute.
uint8_t padding: 4;
uint8_t heart_rate_bpm; //!< heart rate in beats per minute
uint8_t reserved[6]; //!< Reserved for future use.
} HealthMinuteData;
//! Return historical minute data records. This fills in the `minute_data` array parameter with
//! minute by minute statistics of the user's steps, average watch orientation, etc. The data is
//! returned in time order, with the oldest minute data returned at `minute_data[0]`.
//! @param minute_data Pointer to an array of \ref HealthMinuteData records that will be filled
//! in with the historical minute data.
//! @param max_records The maximum number of records the `minute_data` array can hold.
//! @param[in,out] time_start On entry, the UTC time of the first requested record. On exit,
//! the UTC time of the first second of the first record actually returned.
//! If `time_start` on entry is somewhere in the middle of a minute interval, this function
//! behaves as if the caller passed in the start of that minute.
//! @param[in,out] time_end On entry, the UTC time of the end of the requested range of records. On
//! exit, the UTC time of the end of the last record actually returned (i.e. start time of last
//! record + 60). If `time_end` on entry is somewhere in the middle of a minute interval, this
//! function behaves as if the caller passed in the end of that minute.
//! @return Actual number of records returned. May be less then the maximum requested.
//! @note If the return value is zero, `time_start` and `time_end` are meaningless.
//! It's not guaranteed that all records contain valid data, even if the return value is
//! greater than zero. Check `HealthMinuteData.is_invalid` to see if a given record contains
//! valid data.
uint32_t health_service_get_minute_history(HealthMinuteData *minute_data, uint32_t max_records,
time_t *time_start, time_t *time_end);
//! Types of measurement system a \ref HealthMetric may be measured in.
typedef enum {
//! The measurement system is unknown, or does not apply to the chosen metric.
MeasurementSystemUnknown,
//! The metric measurement system.
MeasurementSystemMetric,
//! The imperial measurement system.
MeasurementSystemImperial,
} MeasurementSystem;
//! Get the preferred measurement system for a given \ref HealthMetric, if the user has chosen
//! a preferred system and it is applicable to that metric.
//! @param metric A metric value chosen from \ref HealthMetric.
//! @return A value from \ref MeasurementSystem if applicable, else \ref MeasurementSystemUnknown.
MeasurementSystem health_service_get_measurement_system_for_display(HealthMetric metric);
// -------------------------------------------------------------------------------------------------
// The following types are internally used to implement the cache for the health service.
// They are declared here and not in health_service_private.h to avoid a cyclic dependency between
// events.h and their declaration.
//! @internal
// Auxiliary data passed into HealthEventHandler along with the health event type.
typedef struct {
uint32_t steps; //!< Total number of steps for today
} HealthEventMovementUpdateData;
//! @internal
typedef struct {
uint32_t total_seconds; //!< Total number of seconds of sleep for today
uint32_t total_restful_seconds; //!< Total number of restful seconds
} HealthEventSleepUpdateData;
//! @internal
typedef struct {
uint16_t day_id; //!< The new day_id for today
} HealthEventSignificantUpdateData;
//! @internal
typedef struct {
uint8_t current_bpm;
uint8_t resting_bpm;
HRMQuality quality:8;
bool is_filtered;
} HealthEventHeartRateUpdateData;
//! @internal
typedef struct {
union {
HealthEventMovementUpdateData movement_update;
HealthEventSleepUpdateData sleep_update;
HealthEventSignificantUpdateData significant_update;
HealthEventHeartRateUpdateData heart_rate_update;
};
} HealthEventData;
//! @} // end addtogroup HealthService
//! @} // end addtogroup EventService
//! @} // end addtogroup Foundation