From ab266dc5740217c7e251cda6f4730e2aa966743c Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 10:48:56 -0600 Subject: [PATCH 1/9] Add new id field to examples The heartrate end point does not supply this, strangely --- oura_ring.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/oura_ring.py b/oura_ring.py index b426e25..ee03c07 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -108,6 +108,7 @@ def get_personal_info(self) -> dict[str, Any]: dict[str, list[dict[str, Any]]]: Response JSON data loaded into an object. Example: { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "age": 31, "weight": 74.8, "height": 1.8, @@ -144,6 +145,7 @@ def get_daily_sleep( Example: [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "contributors": { "deep_sleep": 57, "efficiency": 98, @@ -194,6 +196,7 @@ def get_daily_activity( Example: [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "class_5_min": "", "score": 82, "active_calories": 1222, @@ -269,6 +272,7 @@ def get_daily_readiness( Example: [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "contributors": { "activity_balance": 56, "body_temperature": 98, @@ -362,6 +366,7 @@ def get_sleep_periods( Example: [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "average_breath": 12.625, "average_heart_rate": 4.25, "average_hrv": 117, @@ -443,6 +448,7 @@ def get_sessions( Example: [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "day": "2021-11-12", "start_datetime": "2021-11-12T12:32:09-08:00", "end_datetime": "2021-11-12T12:40:49-08:00", @@ -495,6 +501,7 @@ def get_tags( Example: [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "day": "2021-01-01", "text": "Need coffee", "timestamp": "2021-01-01T01:02:03-08:00", @@ -539,6 +546,7 @@ def get_workouts( Example: [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "activity": "cycling", "calories": 300, "day": "2021-01-01", From bf99f069d0e974c014347a893f79ab470c94b0e6 Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 10:58:46 -0600 Subject: [PATCH 2/9] Add Spo2 endpoint --- oura_ring.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/oura_ring.py b/oura_ring.py index ee03c07..7ef41b0 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -170,6 +170,48 @@ def get_daily_sleep( params={"start_date": start, "end_date": end}, ) + def get_daily_spo2( + self, + start_date: str | None = None, + end_date: str | None = None, + ) -> list[dict[str, Any]]: + """Make request to Get Daily Spo2 endpoint. + + Returns Oura Daily Spo2 data for the specified Oura user within a given + timeframe. + + The Daily SpO2 (blood oxygenation) routes include daily SpO2 average. + Data will only be available for users with a Gen 3 Oura Ring. + + Args: + start_date (str, optional): The earliest date for which to get data. + Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to one day + before `end_date`. + end_date (str, optional): The latest date for which to get data. Expected + in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + + Returns: + list[dict[str, Any]]: Response JSON data loaded into an object. + Example: + [ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "spo2_percentage": { + "average": 0 + } + }, + ... + ] + """ + start, end = self._format_dates(start_date, end_date) + + return self._make_paginated_request( + method="GET", + url_slug="v2/usercollection/daily_spo2", + params={"start_date": start, "end_date": end}, + ) + def get_daily_activity( self, start_date: str | None = None, From d89aa2db18f529b149e73458a7b98795dc93bd11 Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 15:00:14 -0600 Subject: [PATCH 3/9] Add daily stress endpoint --- oura_ring.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/oura_ring.py b/oura_ring.py index 7ef41b0..f071516 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -212,6 +212,52 @@ def get_daily_spo2( params={"start_date": start, "end_date": end}, ) + def get_daily_stress( + self, + start_date: str | None = None, + end_date: str | None = None, + ) -> list[dict[str, Any]]: + """Make request to Get Daily Stress endpoint. + + Returns Oura Daily Stress data for the specified Oura user within a given + timeframe. + + The daily stress route includes a summary of the number of minutes the user + spends in high stress and high recovery each day. This is a great way to + see how your stress and recovery are trending over time. Stress and + recovery are mutally exclusive. E.g. one can only be stressed or recovered + at any given moement - and cannot be stressed and recovered at the same + time. + + Args: + start_date (str, optional): The earliest date for which to get data. + Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to one day + before `end_date`. + end_date (str, optional): The latest date for which to get data. Expected + in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + + Returns: + list[dict[str, Any]]: Response JSON data loaded into an object. + Example: + [ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "stress_high": 0, + "recovery_high": 0, + "day_summary": "restored" + }, + ... + ] + """ + start, end = self._format_dates(start_date, end_date) + + return self._make_paginated_request( + method="GET", + url_slug="v2/usercollection/daily_stress", + params={"start_date": start, "end_date": end}, + ) + def get_daily_activity( self, start_date: str | None = None, From aa75deb7b392f42fde1120e2113c4b842a6a5620 Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 15:12:35 -0600 Subject: [PATCH 4/9] Add enhanced tag endpoint --- oura_ring.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/oura_ring.py b/oura_ring.py index f071516..369f3b3 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -258,6 +258,53 @@ def get_daily_stress( params={"start_date": start, "end_date": end}, ) + def get_enhanced_tag( + self, + start_date: str | None = None, + end_date: str | None = None, + ) -> list[dict[str, Any]]: + """Make request to Get Enhanced Tag endpoint. + + Returns Oura Enhanced Tag data for the specified Oura user within a given + timeframe. + + The Enhanced Tags data scope includes tags that Oura users enter within + the Oura mobile app. Enhanced Tags can be added for any lifestyle + choice, habit, mood change, or environmental factor an Oura user wants + to monitor the effects of. Enhanced Tags also contain context on a + tag’s start and end time, whether a tag repeats daily, and comments. + + Args: + start_date (str, optional): The earliest date for which to get data. + Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to one day + before `end_date`. + end_date (str, optional): The latest date for which to get data. Expected + in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + + Returns: + list[dict[str, Any]]: Response JSON data loaded into an object. + Example: + [ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "tag_type_code": "string", + "start_time": "2019-08-24T14:15:22Z", + "end_time": "2019-08-24T14:15:22Z", + "start_day": "2019-08-24", + "end_day": "2019-08-24", + "comment": "string" + }, + ... + ] + """ + start, end = self._format_dates(start_date, end_date) + + return self._make_paginated_request( + method="GET", + url_slug="v2/usercollection/enhanced_tag", + params={"start_date": start, "end_date": end}, + ) + def get_daily_activity( self, start_date: str | None = None, From e94a432c9f89a50ef67340b147c3acffaa61180f Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 15:19:55 -0600 Subject: [PATCH 5/9] Add rest mode period endpoint --- oura_ring.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/oura_ring.py b/oura_ring.py index 369f3b3..08ef401 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -120,6 +120,56 @@ def get_personal_info(self) -> dict[str, Any]: method="GET", url_slug="v2/usercollection/personal_info" ) + def get_rest_mode_period( + self, + start_date: str | None = None, + end_date: str | None = None, + ) -> list[dict[str, Any]]: + """Make request to Get Rest Mode Period endpoint. + + Returns Oura Rest Mode Period data for the specified Oura user within + a given timeframe. + + The Rest Mode scope includes information about rest mode periods. This + includes the start, end time and details of the rest mode period. + + Args: + start_date (str, optional): The earliest date for which to get data. + Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to one day + before `end_date`. + end_date (str, optional): The latest date for which to get data. Expected + in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + + Returns: + list[dict[str, Any]]: Response JSON data loaded into an object. + Example: + [ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "end_day": "2019-08-24", + "end_time": "2019-08-24T14:15:22Z", + "episodes": [ + { + "tags": [ + "string" + ], + "timestamp": "2019-08-24T14:15:22Z" + } + ], + "start_day": "2019-08-24", + "start_time": "2019-08-24T14:15:22Z" + }, + ... + ] + """ + start, end = self._format_dates(start_date, end_date) + + return self._make_paginated_request( + method="GET", + url_slug="v2/usercollection/rest_mode_period", + params={"start_date": start, "end_date": end}, + ) + def get_daily_sleep( self, start_date: str | None = None, From af4408a229b9ce7b1d16c1a08855550c7297332f Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 15:25:33 -0600 Subject: [PATCH 6/9] Add ring configuration endpoint --- oura_ring.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/oura_ring.py b/oura_ring.py index 08ef401..cd967c9 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -170,6 +170,50 @@ def get_rest_mode_period( params={"start_date": start, "end_date": end}, ) + def get_ring_configuration( + self, + start_date: str | None = None, + end_date: str | None = None, + ) -> list[dict[str, Any]]: + """Make request to Get Ring Configuration endpoint. + + Returns Oura Ring Configuration data for the specified Oura user within + a given timeframe. + + The Ring Configuration scope includes information about the user's + ring(s). This includes the model, size, color, etc. + + Args: + start_date (str, optional): The earliest date for which to get data. + Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to one day + before `end_date`. + end_date (str, optional): The latest date for which to get data. Expected + in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + + Returns: + list[dict[str, Any]]: Response JSON data loaded into an object. + Example: + [ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "color": "glossy_black", + "design": "heritage", + "firmware_version": "string", + "hardware_type": "gen1", + "set_up_at": "2019-08-24T14:15:22Z", + "size": 0 + }, + ... + ] + """ + start, end = self._format_dates(start_date, end_date) + + return self._make_paginated_request( + method="GET", + url_slug="v2/usercollection/ring_configuration", + params={"start_date": start, "end_date": end}, + ) + def get_daily_sleep( self, start_date: str | None = None, From ab3f69bd2a8c3f6327e96f2da9a435171b6390f8 Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 15:29:53 -0600 Subject: [PATCH 7/9] Add sleep time endpoint --- oura_ring.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/oura_ring.py b/oura_ring.py index cd967c9..ee2e445 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -214,6 +214,52 @@ def get_ring_configuration( params={"start_date": start, "end_date": end}, ) + def get_sleep_time( + self, + start_date: str | None = None, + end_date: str | None = None, + ) -> list[dict[str, Any]]: + """Make request to Get Sleep Time endpoint. + + Returns Oura Sleep Time data for the specified Oura user within a given + timeframe. + + Recommendations for the optimal bedtime window that is calculated based + on sleep data. + + Args: + start_date (str, optional): The earliest date for which to get data. + Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to one day + before `end_date`. + end_date (str, optional): The latest date for which to get data. Expected + in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + + Returns: + list[dict[str, Any]]: Response JSON data loaded into an object. + Example: + [ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "optimal_bedtime": { + "day_tz": 0, + "end_offset": 0, + "start_offset": 0 + }, + "recommendation": "improve_efficiency", + "status": "not_enough_nights" + }, + ... + ] + """ + start, end = self._format_dates(start_date, end_date) + + return self._make_paginated_request( + method="GET", + url_slug="v2/usercollection/sleep_time", + params={"start_date": start, "end_date": end}, + ) + def get_daily_sleep( self, start_date: str | None = None, From 64e471708a993e0b1350da31b403d8f37e917fee Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 15 Jan 2024 17:09:23 -0600 Subject: [PATCH 8/9] Add support for single document requests by id --- oura_ring.py | 401 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 388 insertions(+), 13 deletions(-) diff --git a/oura_ring.py b/oura_ring.py index ee2e445..47a3850 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -124,7 +124,8 @@ def get_rest_mode_period( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Rest Mode Period endpoint. Returns Oura Rest Mode Period data for the specified Oura user within @@ -139,6 +140,9 @@ def get_rest_mode_period( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -161,9 +165,33 @@ def get_rest_mode_period( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "end_day": "2019-08-24", + "end_time": "2019-08-24T14:15:22Z", + "episodes": [ + { + "tags": [ + "string" + ], + "timestamp": "2019-08-24T14:15:22Z" + } + ], + "start_day": "2019-08-24", + "start_time": "2019-08-24T14:15:22Z" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/rest_mode_period/{document_id}" + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/rest_mode_period", @@ -174,7 +202,8 @@ def get_ring_configuration( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Ring Configuration endpoint. Returns Oura Ring Configuration data for the specified Oura user within @@ -189,6 +218,9 @@ def get_ring_configuration( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -205,9 +237,27 @@ def get_ring_configuration( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "color": "glossy_black", + "design": "heritage", + "firmware_version": "string", + "hardware_type": "gen1", + "set_up_at": "2019-08-24T14:15:22Z", + "size": 0 + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/ring_configuration/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/ring_configuration", @@ -218,7 +268,8 @@ def get_sleep_time( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Sleep Time endpoint. Returns Oura Sleep Time data for the specified Oura user within a given @@ -233,6 +284,9 @@ def get_sleep_time( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -251,9 +305,29 @@ def get_sleep_time( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "optimal_bedtime": { + "day_tz": 0, + "end_offset": 0, + "start_offset": 0 + }, + "recommendation": "improve_efficiency", + "status": "not_enough_nights" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/sleep_time/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/sleep_time", @@ -264,7 +338,8 @@ def get_daily_sleep( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Daily Sleep endpoint. Returns Oura Daily Sleep data for the specified Oura user within a given @@ -279,6 +354,9 @@ def get_daily_sleep( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -301,9 +379,33 @@ def get_daily_sleep( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "contributors": { + "deep_sleep": 57, + "efficiency": 98, + "latency": 81, + "rem_sleep": 20, + "restfulness": 54, + "timing": 84, + "total_sleep": 60 + }, + "day": "2022-07-14", + "score": 63, + "timestamp": "2022-07-14T00:00:00+00:00" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/daily_sleep/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/daily_sleep", @@ -314,7 +416,8 @@ def get_daily_spo2( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Daily Spo2 endpoint. Returns Oura Daily Spo2 data for the specified Oura user within a given @@ -329,6 +432,9 @@ def get_daily_spo2( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -343,9 +449,25 @@ def get_daily_spo2( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "spo2_percentage": { + "average": 0 + } + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/daily_spo2/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/daily_spo2", @@ -356,7 +478,8 @@ def get_daily_stress( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Daily Stress endpoint. Returns Oura Daily Stress data for the specified Oura user within a given @@ -375,6 +498,9 @@ def get_daily_stress( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -389,9 +515,25 @@ def get_daily_stress( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "stress_high": 0, + "recovery_high": 0, + "day_summary": "restored" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/daily_stress/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/daily_stress", @@ -402,7 +544,8 @@ def get_enhanced_tag( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Enhanced Tag endpoint. Returns Oura Enhanced Tag data for the specified Oura user within a given @@ -420,6 +563,9 @@ def get_enhanced_tag( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -439,6 +585,12 @@ def get_enhanced_tag( """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_paginated_request( + method="GET", + url_slug=f"v2/usercollection/enhanced_tag/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/enhanced_tag", @@ -449,7 +601,8 @@ def get_daily_activity( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Daily Activy endpoint. Returns Oura Daily Activity data for the specified Oura user within a given @@ -465,6 +618,9 @@ def get_daily_activity( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -514,9 +670,60 @@ def get_daily_activity( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "class_5_min": "", + "score": 82, + "active_calories": 1222, + "average_met_minutes": 1.90625, + "contributors": { + "meet_daily_targets": 43, + "move_every_hour": 100, + "recovery_time": 100, + "stay_active": 98, + "training_frequency": 71, + "training_volume": 98 + }, + "equivalent_walking_distance": 20122, + "high_activity_met_minutes": 444, + "high_activity_time": 3000, + "inactivity_alerts": 0, + "low_activity_met_minutes": 117, + "low_activity_time": 10020, + "medium_activity_met_minutes": 391, + "medium_activity_time": 6060, + "met": { + "interval": 60, + "items": [ + 0.1, + ... + ], + "timestamp": "2021-11-26T04:00:00.000-08:00" + }, + "meters_to_target": -16200, + "non_wear_time": 27480, + "resting_time": 18840, + "sedentary_met_minutes": 10, + "sedentary_time": 21000, + "steps": 18430, + "target_calories": 350, + "target_meters": 7000, + "total_calories": 3446, + "day": "2021-11-26", + "timestamp": "2021-11-26T04:00:00-08:00" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/daily_activity/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/daily_activity", @@ -527,7 +734,8 @@ def get_daily_readiness( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Daily Readiness endpoint. Returns Oura Daily Readiness data for the specified Oura user within a given @@ -541,6 +749,9 @@ def get_daily_readiness( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -566,9 +777,36 @@ def get_daily_readiness( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "contributors": { + "activity_balance": 56, + "body_temperature": 98, + "hrv_balance": 75, + "previous_day_activity": None, + "previous_night": 35, + "recovery_index": 47, + "resting_heart_rate": 94, + "sleep_balance": 73 + }, + "day": "2021-10-27", + "score": 66, + "temperature_deviation": -0.2, + "temperature_trend_deviation": 0.1, + "timestamp": "2021-10-27T00:00:00+00:00" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/daily_readiness/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/daily_readiness", @@ -620,7 +858,8 @@ def get_sleep_periods( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Sleep Periods endpoint. Returns available Oura sleep data for the specified Oura user within a given @@ -635,6 +874,9 @@ def get_sleep_periods( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -688,9 +930,64 @@ def get_sleep_periods( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "average_breath": 12.625, + "average_heart_rate": 4.25, + "average_hrv": 117, + "awake_time": 4800, + "bedtime_end": "2022-07-12T09:25:14-07:00", + "bedtime_start": "2022-07-12T01:05:14-07:00", + "day": "2022-07-12", + "deep_sleep_duration": 4170, + "efficiency": 84, + "heart_rate": { + "interval": 300, + "items": [ + None, + 50, + 46, + ... + ], + "timestamp": "2022-07-12T01:05:14.000-07:00" + }, + "hrv": { + "interval": 300, + "items": [ + None, + -102, + -122, + ... + ], + "timestamp": "2022-07-12T01:05:14.000-07:00" + }, + "latency": 540, + "light_sleep_duration": 18750, + "low_battery_alert": False, + "lowest_heart_rate": 48, + "movement_30_sec": "", + "period": 0, + "readiness_score_delta": 0, + "rem_sleep_duration": 2280, + "restless_periods": 415, + "sleep_phase_5_min": "", + "sleep_score_delta": 0, + "time_in_bed": 30000, + "total_sleep_duration": None, + "type": "long_sleep" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/sleep/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/sleep", @@ -701,7 +998,8 @@ def get_sessions( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Sessions endpoint. Returns available Oura session data for the specified Oura user within a given @@ -717,6 +1015,9 @@ def get_sessions( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -741,9 +1042,34 @@ def get_sessions( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2021-11-12", + "start_datetime": "2021-11-12T12:32:09-08:00", + "end_datetime": "2021-11-12T12:40:49-08:00", + "type": "rest", + "heart_rate": None, + "heart_rate_variability": None, + "mood": None, + "motion_count": { + "interval": 5, + "items": [ + 0 + ], + "timestamp": "2021-11-12T12:32:09.000-08:00" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/session/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/session", @@ -754,11 +1080,14 @@ def get_tags( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Tags endpoint. Returns Oura tags data for the specified Oura user within a given timeframe. + Note: Tag is deprecated. We recommend transitioning to Enhanced Tag. + The Tags data scope includes tags that Oura users enter within the Oura mobile app. Tags are a growing list of activities, environment factors, symptoms, emotions, and other aspects that provide broader context into what’s happening @@ -770,6 +1099,9 @@ def get_tags( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -786,9 +1118,27 @@ def get_tags( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2021-01-01", + "text": "Need coffee", + "timestamp": "2021-01-01T01:02:03-08:00", + "tags": [ + "tag_generic_nocaffeine" + ] + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/tag/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/tag", @@ -799,7 +1149,8 @@ def get_workouts( self, start_date: str | None = None, end_date: str | None = None, - ) -> list[dict[str, Any]]: + document_id: str | None = None, + ) -> list[dict[str, Any]] | dict[str, Any]: """Make request to Get Workouts endpoint. Returns available Oura workout data for the specified Oura user within a given @@ -815,6 +1166,9 @@ def get_workouts( before `end_date`. end_date (str, optional): The latest date for which to get data. Expected in ISO 8601 format (`YYYY-MM-DD`). Defaults to today's date. + document_id (str, options): Individual document id, listed at "id" + in responses. Allows you to re-access a previous datapoint. + If present, start_date and end_date are ignored. Returns: list[dict[str, Any]]: Response JSON data loaded into an object. @@ -834,9 +1188,30 @@ def get_workouts( }, ... ] + + dict[str, Any]: Response JSON data loaded into an object. + Example: + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "activity": "cycling", + "calories": 300, + "day": "2021-01-01", + "distance": 13500.5, + "end_datetime": "2021-01-01T01:00:00.000000+00:00", + "intensity": "moderate", + "label": None, + "source": "manual", + "start_datetime": "2021-01-01T01:30:00.000000+00:00" + } """ start, end = self._format_dates(start_date, end_date) + if document_id: + return self._make_request( + method="GET", + url_slug=f"v2/usercollection/workout/{document_id}", + ) + return self._make_paginated_request( method="GET", url_slug="v2/usercollection/workout", From f36cc458e6fb2e1c77ed2347d2810cc91ad32e6f Mon Sep 17 00:00:00 2001 From: Michael Dwyer Date: Mon, 29 Jan 2024 13:57:51 -0600 Subject: [PATCH 9/9] Update documentation --- README.md | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++ oura_ring.py | 2 +- 2 files changed, 176 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f8d4beb..2b56555 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,16 @@ Tools for acquiring and analyzing Oura API data. - [API Requests](#api-requests) - [Get Personal Info](#get-personal-info) - [Get Daily Sleep](#get-daily-sleep) + - [Get Daily SpO2](#get-daily-spo2) + - [Get Daily Stress](#get-daily-stress) - [Get Daily Activity](#get-daily-activity) - [Get Daily Readiness](#get-daily-readiness) + - [Get Enhanced Tag](#get-enhanced-tag) - [Get Heart Rate](#get-heart-rate) + - [Get Ring Configuration](#get-ring-configuration) + - [Get Rest Mode Period](#get-rest-mode-period) - [Get Sleep Periods](#get-sleep-periods) + - [Get Sleep Time](#get-sleep-time) - [Get Sessions](#get-sessions) - [Get Tags](#get-tags) - [Get Workouts](#get-workouts) @@ -76,6 +82,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "age": 31, "weight": 74.8, "height": 1.8, @@ -98,6 +105,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "contributors": { "deep_sleep": 57, "efficiency": 98, @@ -129,6 +137,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "class_5_min": "", "score": 82, "active_calories": 1222, @@ -187,6 +196,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "contributors": { "activity_balance": 56, "body_temperature": 98, @@ -207,6 +217,33 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ] ``` +### Get Enhanced Tag + +**Method**: `get_enhanced_tag(start_date: str = , end_date: str = )` + +**Payload**: + +- `start_date`: The earliest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to one day before the `end_date` parameter. +- `end_date`: The latest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to today's date. + +**Example Response**: + +```python +[ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "tag_type_code": "string", + "start_time": "2019-08-24T14:15:22Z", + "end_time": "2019-08-24T14:15:22Z", + "start_day": "2019-08-24", + "end_day": "2019-08-24", + "comment": "string" + }, + ... +] + +``` + ### Get Heart Rate **Method**: `get_heart_rate(start_date: str = , end_date: str = )` @@ -243,6 +280,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "average_breath": 12.625, "average_heart_rate": 4.25, "average_hrv": 117, @@ -291,6 +329,92 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ] ``` +### Get Sleep Time + +**Method**: `get_sleep_time(start_date: str = , end_date: str = )` + +**Payload**: + +- `start_date`: The earliest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to one day before the `end_date` parameter. +- `end_date`: The latest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to today's date. + +**Example Response**: + +```python +[ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "optimal_bedtime": { + "day_tz": 0, + "end_offset": 0, + "start_offset": 0 + }, + "recommendation": "improve_efficiency", + "status": "not_enough_nights" + }, + ... +] +``` + +### Get Ring Configuration + +**Method**: `get_ring_configuration(start_date: str = , end_date: str = )` + +**Payload**: + +- `start_date`: The earliest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to one day before the `end_date` parameter. +- `end_date`: The latest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to today's date. + +**Example Response**: + +```python +[ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "color": "glossy_black", + "design": "heritage", + "firmware_version": "string", + "hardware_type": "gen1", + "set_up_at": "2019-08-24T14:15:22Z", + "size": 0 + }, + ... +] +``` + +### Get Rest Mode Period + +**Method**: `get_rest_mode_period(start_date: str = , end_date: str = )` + +**Payload**: + +- `start_date`: The earliest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to one day before the `end_date` parameter. +- `end_date`: The latest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to today's date. + +**Example Response**: + +```python +[ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "end_day": "2019-08-24", + "end_time": "2019-08-24T14:15:22Z", + "episodes": [ + { + "tags": [ + "string" + ], + "timestamp": "2019-08-24T14:15:22Z" + } + ], + "start_day": "2019-08-24", + "start_time": "2019-08-24T14:15:22Z" + }, + ... +] +``` + ### Get Sessions **Method**: `get_sessions(start_date: str = , end_date: str = )` @@ -305,6 +429,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "day": "2021-11-12", "start_datetime": "2021-11-12T12:32:09-08:00", "end_datetime": "2021-11-12T12:40:49-08:00", @@ -324,6 +449,54 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ] ``` +### Get Daily SpO2 + +**Method**: `get_daily_spo2(start_date: str = , end_date: str = )` + +**Payload**: + +- `start_date`: The earliest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to one day before the `end_date` parameter. +- `end_date`: The latest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to today's date. + +**Example Response**: + +```python +[ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "spo2_percentage": { + "average": 0 + } + }, + ... +] +``` + +### Get Daily Stress + +**Method**: `get_daily_stress(start_date: str = , end_date: str = )` + +**Payload**: + +- `start_date`: The earliest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to one day before the `end_date` parameter. +- `end_date`: The latest date for which to get data. Expected in ISO 8601 format (YYYY-MM-DD). Defaults to today's date. + +**Example Response**: + +```python +[ + { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", + "day": "2019-08-24", + "stress_high": 0, + "recovery_high": 0, + "day_summary": "restored" + }, + ... +] +``` + ### Get Tags **Method**: `get_tags(start_date: str = , end_date: str = )` @@ -338,6 +511,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "day": "2021-01-01", "text": "Need coffee", "timestamp": "2021-01-01T01:02:03-08:00", @@ -363,6 +537,7 @@ There are nine different API requests that `OuraClient` can make. Full Oura API ```python [ { + "id": "8f9a5221-639e-4a85-81cb-4065ef23f979", "activity": "cycling", "calories": 300, "day": "2021-01-01", diff --git a/oura_ring.py b/oura_ring.py index 47a3850..1bf46b4 100644 --- a/oura_ring.py +++ b/oura_ring.py @@ -603,7 +603,7 @@ def get_daily_activity( end_date: str | None = None, document_id: str | None = None, ) -> list[dict[str, Any]] | dict[str, Any]: - """Make request to Get Daily Activy endpoint. + """Make request to Get Daily Activity endpoint. Returns Oura Daily Activity data for the specified Oura user within a given timeframe.