mirror of
https://github.com/google/pebble.git
synced 2025-04-30 23:31:40 -04:00
559 lines
29 KiB
C
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
|