fitbit_client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +24 -0
- data/.rubocop_todo.yml +13 -0
- data/.travis.yml +11 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +62 -0
- data/Rakefile +12 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/fitbit_client.gemspec +36 -0
- data/lib/fitbit_client.rb +42 -0
- data/lib/fitbit_client/authorization_grant_flow.rb +31 -0
- data/lib/fitbit_client/client.rb +42 -0
- data/lib/fitbit_client/error.rb +24 -0
- data/lib/fitbit_client/network/request.rb +87 -0
- data/lib/fitbit_client/resources.rb +15 -0
- data/lib/fitbit_client/resources/activity.rb +93 -0
- data/lib/fitbit_client/resources/body_and_weight.rb +145 -0
- data/lib/fitbit_client/resources/common.rb +20 -0
- data/lib/fitbit_client/resources/devices.rb +22 -0
- data/lib/fitbit_client/resources/sleep.rb +150 -0
- data/lib/fitbit_client/resources/subscription.rb +59 -0
- data/lib/fitbit_client/util.rb +33 -0
- data/lib/fitbit_client/version.rb +5 -0
- metadata +208 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
class Error < StandardError
|
5
|
+
attr_accessor :response
|
6
|
+
|
7
|
+
def initialize(message, response = nil)
|
8
|
+
@message = message
|
9
|
+
@response = response
|
10
|
+
end
|
11
|
+
|
12
|
+
def json_response
|
13
|
+
@json_response ||= JSON.parse(response.body) if response
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
if response
|
18
|
+
"#{@message}, HTTP_STATUS: #{response.status}, HTTP_BODY: #{response.body}, HTTP_URL: #{response.response.env.url}"
|
19
|
+
else
|
20
|
+
@message.to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
module Network
|
5
|
+
module Request
|
6
|
+
def get_json(path, params = {}, headers = {})
|
7
|
+
parse_response(get(path, params, headers))
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(path, params = {}, headers = {})
|
11
|
+
request(:get, path, headers: headers, params: params)
|
12
|
+
end
|
13
|
+
|
14
|
+
def post_json(path, params = {}, headers = {})
|
15
|
+
parse_response(post(path, params, headers))
|
16
|
+
end
|
17
|
+
|
18
|
+
def post(path, params = {}, headers = {})
|
19
|
+
request(:post, path, headers: headers, params: params)
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete_json(path, params = {}, headers = {})
|
23
|
+
parse_response(delete(path, params, headers))
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(path, params = {}, headers = {})
|
27
|
+
request(:delete, path, headers: headers, params: params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def successful_post?(response)
|
31
|
+
response.status == 201 && response.body == '{}'
|
32
|
+
end
|
33
|
+
|
34
|
+
def successful_delete?(response)
|
35
|
+
response.status == 204 && response.body.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def request(method, path, opts = {})
|
41
|
+
attempt = 0
|
42
|
+
begin
|
43
|
+
default_request_headers(opts)
|
44
|
+
oauth2_access_token.request(method, path, opts)
|
45
|
+
rescue OAuth2::Error => e # Handle refresh token issue automagically
|
46
|
+
attempt += 1
|
47
|
+
if expired_token_error?(e.response)
|
48
|
+
oauth2_refresh_token!
|
49
|
+
retry if attempt < 2
|
50
|
+
end
|
51
|
+
raise FitbitClient::Error.new('Error during OAuth2 request', e.response)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_request_headers(opts)
|
56
|
+
opts[:headers]['User-Agent'] = "FitbitClient v#{::FitbitClient::VERSION}"
|
57
|
+
opts[:headers]['Accept-Language'] = opts.fetch(:language, ::FitbitClient.default_language)
|
58
|
+
opts[:headers]['Accept-Locale'] = opts.fetch(:locale, ::FitbitClient.default_locale)
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_response(response)
|
62
|
+
return {} if response.nil? || response.body.nil? || response.body.empty?
|
63
|
+
JSON.parse response.body
|
64
|
+
end
|
65
|
+
|
66
|
+
def expired_token_error?(response)
|
67
|
+
json_response = parse_response(response)
|
68
|
+
json_response.dig('errors', 0, 'errorType') == 'expired_token'
|
69
|
+
end
|
70
|
+
|
71
|
+
def oauth2_refresh_token!
|
72
|
+
@oauth2_access_token = oauth2_access_token.refresh!
|
73
|
+
refresh_token_callback!(@oauth2_access_token)
|
74
|
+
rescue OAuth2::Error => e
|
75
|
+
raise FitbitClient::Error.new('Error during oauth2_refresh_token! attempt', e.response)
|
76
|
+
end
|
77
|
+
|
78
|
+
def oauth2_access_token
|
79
|
+
@oauth2_access_token ||= OAuth2::AccessToken.new(oauth2_client, access_token, refresh_token: refresh_token)
|
80
|
+
end
|
81
|
+
|
82
|
+
def oauth2_client
|
83
|
+
@oauth2_client ||= OAuth2::Client.new(client_id, client_secret, FitbitClient::OAUTH2_CLIENT_OPTIONS)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
# This module is used to include all resources (endpoints)
|
5
|
+
module Resources
|
6
|
+
include FitbitClient::Util
|
7
|
+
include FitbitClient::Network::Request
|
8
|
+
include FitbitClient::Resources::Common
|
9
|
+
include FitbitClient::Resources::Activity
|
10
|
+
include FitbitClient::Resources::BodyAndWeight
|
11
|
+
include FitbitClient::Resources::Devices
|
12
|
+
include FitbitClient::Resources::Sleep
|
13
|
+
include FitbitClient::Resources::Subscription
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
module Resources
|
5
|
+
module Activity
|
6
|
+
# The Get Lifetime Stats endpoint retrieves the user's activity statistics
|
7
|
+
# in the format requested using units in the unit system which corresponds
|
8
|
+
# to the Accept-Language header provided.
|
9
|
+
#
|
10
|
+
# Activity statistics includes Lifetime and Best achievement values
|
11
|
+
# from the My Achievements tile on the website dashboard.
|
12
|
+
#
|
13
|
+
# Response contains both statistics from the tracker device and
|
14
|
+
# total numbers including tracker data and manual activity log entries
|
15
|
+
# as seen on the Fitbit website dashboard.
|
16
|
+
def lifetime_stats(options = {})
|
17
|
+
get_json(path_user_version('/activities', options))
|
18
|
+
end
|
19
|
+
|
20
|
+
# The Get Daily Activity Summary endpoint retrieves a summary and list
|
21
|
+
# of a user's activities and activity log entries for a given day in the
|
22
|
+
# format requested using units in the unit system which corresponds to
|
23
|
+
# the Accept-Language header provided.
|
24
|
+
def daily_activity_summary(date, options = {})
|
25
|
+
get_json(path_user_version("/activities/date/#{iso_date(date)}", options))
|
26
|
+
end
|
27
|
+
|
28
|
+
# The Get Activity Time Series endpoint returns time series data in
|
29
|
+
# the specified range for a given resource in the format requested
|
30
|
+
# using units in the unit system that corresponds to
|
31
|
+
# the Accept-Language header provided.
|
32
|
+
def activity_time_series(resource, date, period_or_end_date, options = {})
|
33
|
+
period = period_or_date_param(period_or_end_date)
|
34
|
+
path = "/activities/#{resource}/date/#{iso_date(date)}/#{period}"
|
35
|
+
get_json(path_user_version(path, options))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get a tree of all valid Fitbit public activities from the activities
|
39
|
+
# catalog as well as private custom activities the user created in the
|
40
|
+
# format requested.
|
41
|
+
#
|
42
|
+
# If the activity has levels, also get a list of activity level details.
|
43
|
+
def browse_activity_types(options = {})
|
44
|
+
skip_user_options!(options)
|
45
|
+
get_json(path_user_version('/activities', options))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the details of a specific activity in the Fitbit activities
|
49
|
+
# database in the format requested. If activity has levels, also returns
|
50
|
+
# a list of activity level details.
|
51
|
+
#
|
52
|
+
# activity_id : The activity id
|
53
|
+
def activity_type(activity_id, options = {})
|
54
|
+
skip_user_options!(options)
|
55
|
+
get_json(path_user_version("/activities/#{activity_id}", options))
|
56
|
+
end
|
57
|
+
|
58
|
+
# The Get Recent Activity Types endpoint retrieves a list of a user's
|
59
|
+
# recent activities types logged with some details of the last activity
|
60
|
+
# log of that type using units in the unit system which corresponds to
|
61
|
+
# the Accept-Language header provided.
|
62
|
+
#
|
63
|
+
# The record retrieved can be used to log the activity via the
|
64
|
+
# Log Activity endpoint with the same or adjusted values for distance
|
65
|
+
# and duration.
|
66
|
+
def recent_activity_types(options = {})
|
67
|
+
get_json(path_user_version('/activities/recent', options))
|
68
|
+
end
|
69
|
+
|
70
|
+
# The Get Favorite Activities endpoint returns a list of a user's
|
71
|
+
# favorite activities.
|
72
|
+
def favorite_activities
|
73
|
+
get_json(path_user_version('/activities/favorite'))
|
74
|
+
end
|
75
|
+
|
76
|
+
# The Add Favorite Activity endpoint adds the activity with the given ID
|
77
|
+
# to user's list of favorite activities.
|
78
|
+
#
|
79
|
+
# activity_id : The ID of the activity to add to user's favorites.
|
80
|
+
def add_favorite_activity(activity_id)
|
81
|
+
successful_post?(post(path_user_version("/activities/favorite/#{activity_id}")))
|
82
|
+
end
|
83
|
+
|
84
|
+
# The Delete Favorite Activity removes the activity with the given ID
|
85
|
+
# from a user's list of favorite activities.
|
86
|
+
#
|
87
|
+
# activity_id : The ID of the activity to be removed.
|
88
|
+
def delete_favorite_activity(activity_id)
|
89
|
+
successful_delete?(delete(path_user_version("/activities/favorite/#{activity_id}")))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
module Resources
|
5
|
+
module BodyAndWeight
|
6
|
+
# The Get Weight Logs API retrieves a list of all user's body weight log
|
7
|
+
# entries for a given day using units in the unit systems which
|
8
|
+
# corresponds to the Accept-Language header provided.
|
9
|
+
#
|
10
|
+
# Body weight log entries are available only to authorized user.
|
11
|
+
#
|
12
|
+
# Body weight log entries in response are sorted exactly the same as they
|
13
|
+
# are presented on the Fitbit website.
|
14
|
+
def weight_logs(date, _options = {})
|
15
|
+
get_json(path_user_version("/body/log/weight/date/#{iso_date(date)}"))
|
16
|
+
end
|
17
|
+
|
18
|
+
# The Log Weight API creates log entry for a body weight using units in
|
19
|
+
# the unit systems that corresponds to the Accept-Language header provided
|
20
|
+
# and get a response in the format requested.
|
21
|
+
#
|
22
|
+
# <b>Note:</b> The returned Weight Log IDs are unique to the user,
|
23
|
+
# but not globally unique.
|
24
|
+
#
|
25
|
+
# weight : Weight in the format X.XX
|
26
|
+
# date : Date of the measurement
|
27
|
+
# time : Time of the measurement
|
28
|
+
def log_weight(weight, date, time = nil, options = {})
|
29
|
+
params = key_value_date_time_params('weight', weight, date, time)
|
30
|
+
post_json(path_user_version('/body/log/weight', options), params)
|
31
|
+
end
|
32
|
+
|
33
|
+
# The Delete Weight Log API deletes a user's body weight log entry with
|
34
|
+
# the given ID.
|
35
|
+
def delete_weight_log(body_weight_log_id, options = {})
|
36
|
+
path = "/body/log/weight/#{body_weight_log_id}"
|
37
|
+
successful_delete?(delete(path_user_version(path, options)))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Retrieves a user's current body fat percentage or weight goal using
|
41
|
+
# units in the unit systems that corresponds to the Accept-Language header
|
42
|
+
# provided in the format requested.
|
43
|
+
#
|
44
|
+
# goal_type : can be weight or fat
|
45
|
+
def body_goals(goal_type, options = {})
|
46
|
+
get_json(path_user_version("/body/log/#{goal_type}/goal", options))
|
47
|
+
end
|
48
|
+
|
49
|
+
# The Update Body Fat Goal API creates or updates user's fat percentage
|
50
|
+
# goal.
|
51
|
+
#
|
52
|
+
# fat : Target body fat percentage in the format X.XX
|
53
|
+
def update_body_fat_goal(fat, options = {})
|
54
|
+
post_json(path_user_version('/body/log/fat/goal', options), 'fat' => fat)
|
55
|
+
end
|
56
|
+
|
57
|
+
# The Update Weight Goal API creates or updates user's fat or weight goal
|
58
|
+
# using units in the unit systems that corresponds to the Accept-Language
|
59
|
+
# header provided in the format requested.
|
60
|
+
#
|
61
|
+
# startDate : Weight goal start date
|
62
|
+
# startWeight : Weight goal start weight; in the format X.XX
|
63
|
+
# weight : Weight goal target weight; in the format X.XX, in the
|
64
|
+
# unit systems that corresponds to the Accept-Language
|
65
|
+
# header provided; required if user doesn't have an existing
|
66
|
+
# weight goal.
|
67
|
+
def update_body_weight_goal(start_date, start_weight, weight = nil, options = {})
|
68
|
+
params = update_body_weight_goal_params(start_date, start_weight, weight)
|
69
|
+
post_json(path_user_version('/body/log/weight/goal', options), params)
|
70
|
+
end
|
71
|
+
|
72
|
+
# The Get Body Time Series API returns time series data in the specified
|
73
|
+
# range for a given resource in the format requested using units in the
|
74
|
+
# unit systems that corresponds to the Accept-Language header provided.
|
75
|
+
#
|
76
|
+
# <b>Note:</b> If you provide earlier dates in the request, the response
|
77
|
+
# retrieves only data since the user's join date or the first log entry
|
78
|
+
# date for the requested collection.
|
79
|
+
#
|
80
|
+
# resource : Can be "bmi", "fat", or "weight".
|
81
|
+
# date : The range start date or end date of the period specified
|
82
|
+
# period_or_end_date : One of 1d, 7d, 30d, 1w, 1m, 3m, 6m, 1y, max or the end date of the range
|
83
|
+
def body_time_series(resource, date, period_or_end_date, options = {})
|
84
|
+
end_limit = period_or_date_param(period_or_end_date)
|
85
|
+
path = time_series_path('body', resource, date, end_limit)
|
86
|
+
get_json(path_user_version(path, options))
|
87
|
+
end
|
88
|
+
|
89
|
+
# The Get Body Fat Logs API retrieves a list of all user's body fat log
|
90
|
+
# entries for a given day in the format requested. Body fat log entries
|
91
|
+
# are available only to authorized user.
|
92
|
+
#
|
93
|
+
# If you need to fetch only the most recent entry, you can use the
|
94
|
+
# Get Body Measurements endpoint.
|
95
|
+
#
|
96
|
+
# date : base or start date
|
97
|
+
# period_or_end_date : One of 1d, 7d, 1w, 1m or a Date object
|
98
|
+
#
|
99
|
+
# <b>Note:</b> The range should not be longer than 31 days.
|
100
|
+
def body_fat_logs(date, period_or_end_date = nil, options = {})
|
101
|
+
if period_or_end_date
|
102
|
+
end_limit = period_or_date_param(period_or_end_date)
|
103
|
+
path = "/body/log/fat/date/#{iso_date(date)}/#{end_limit}"
|
104
|
+
else
|
105
|
+
path = "/body/log/fat/date/#{iso_date(date)}"
|
106
|
+
end
|
107
|
+
get_json(path_user_version(path, options))
|
108
|
+
end
|
109
|
+
|
110
|
+
# The Log Body Fat API creates a log entry for body fat and returns a
|
111
|
+
# response in the format requested.
|
112
|
+
#
|
113
|
+
# <b>Note:</b> The returned Body Fat Log IDs are unique to the user, but
|
114
|
+
# not globally unique.
|
115
|
+
#
|
116
|
+
# fat : Body fat; in the format X.XX
|
117
|
+
# date : Log entry date
|
118
|
+
# time : Time of the measurement
|
119
|
+
def log_body_fat(fat, date, time = nil, options = {})
|
120
|
+
params = key_value_date_time_params('fat', fat, date, time)
|
121
|
+
post_json(path_user_version('/body/log/fat', options), params)
|
122
|
+
end
|
123
|
+
|
124
|
+
# The Delete Body Fat Log API deletes a user's body fat log entry with
|
125
|
+
# the given ID.
|
126
|
+
def delete_body_fat_log(body_fat_log_id, options = {})
|
127
|
+
successful_delete?(delete(path_user_version("/body/log/fat/#{body_fat_log_id}", options)))
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def key_value_date_time_params(key, value, date, time)
|
133
|
+
params = { key => value, 'date' => iso_date(date) }
|
134
|
+
params['time'] = iso_time_with_seconds(time) if time
|
135
|
+
params
|
136
|
+
end
|
137
|
+
|
138
|
+
def update_body_weight_goal_params(start_date, start_weight, weight)
|
139
|
+
params = { 'startDate' => iso_date(start_date), 'startWeight' => start_weight }
|
140
|
+
params['weight'] = weight if weight
|
141
|
+
params
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
module Resources
|
5
|
+
module Common
|
6
|
+
def skip_user_options!(options)
|
7
|
+
options[:skip_user] = true
|
8
|
+
options.delete![:user_id] if options.key?(:user_id)
|
9
|
+
end
|
10
|
+
|
11
|
+
def time_series_path(type, resource, date, end_limit)
|
12
|
+
"/#{type}/#{resource}/date/#{iso_date(date)}/#{end_limit}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def period_or_date_param(period_or_date)
|
16
|
+
period_or_date.is_a?(Date) ? iso_date(period_or_date) : period_or_date
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
module Resources
|
5
|
+
module Devices
|
6
|
+
# The Get Device endpoint returns a list of the Fitbit devices connected
|
7
|
+
# to a user's account.
|
8
|
+
#
|
9
|
+
# Third-party applications can check when a Fitbit device last synced
|
10
|
+
# with Fitbit's servers using this endpoint.
|
11
|
+
def devices(options = {})
|
12
|
+
get_json(path_user_version('/devices', options))
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns a list of the set alarms connected to a user's account.
|
16
|
+
# tracker_id : The ID of the tracker for which data is returned. The tracker-id value is found via the Get Devices endpoint.
|
17
|
+
def alarms(tracker_id, options = {})
|
18
|
+
get_json(path_user_version("/devices/tracker/#{tracker_id}/alarms", options))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FitbitClient
|
4
|
+
module Resources
|
5
|
+
module Sleep
|
6
|
+
# The Get Sleep Time Series endpoint returns time series data in the
|
7
|
+
# specified range for a given resource in the format requested using units
|
8
|
+
# in the unit system that corresponds to the Accept-Language header provided.
|
9
|
+
#
|
10
|
+
# API Version: 1
|
11
|
+
#
|
12
|
+
# <b>Note:</b> This API has been <b>deprecated</b> with the introduction
|
13
|
+
# of version 1.2 of the \Sleep APIs described above. \Sleep Stages data
|
14
|
+
# cannot be retrieved with this API. If your application requires data
|
15
|
+
# consistency while you transition over to the version 1.2 \Sleep APIs,
|
16
|
+
# you can get this data through the version 1 Get Sleep Logs by Date
|
17
|
+
# endpoint.
|
18
|
+
#
|
19
|
+
# resource : startTime | timeInBed | minutesAsleep |
|
20
|
+
# awakeningsCount | minutesAwake | minutesToFallAsleep
|
21
|
+
# minutesAfterWakeup | efficiency
|
22
|
+
# date : The start date for a range or end date of the period specified
|
23
|
+
# period_or_end_date : One of 1d, 7d, 30d, 1w, 1m, 3m, 6m, 1y, max or the end date of the range
|
24
|
+
def sleep_time_series(resource, date, period_or_end_date, options = {})
|
25
|
+
end_limit = period_or_date_param(period_or_end_date)
|
26
|
+
path = time_series_path('sleep', resource, date, end_limit)
|
27
|
+
get_json(path_user_version(path, options))
|
28
|
+
end
|
29
|
+
|
30
|
+
# The Get Sleep Logs by Date endpoint returns a summary and list
|
31
|
+
# of a user's sleep log entries (including naps) as well as detailed sleep
|
32
|
+
# entry data for a given day.
|
33
|
+
#
|
34
|
+
# This endpoint supports two kinds of sleep data:
|
35
|
+
# - stages: Levels data is returned with 30-second granularity. 'Sleep Stages' levels include deep, light, rem, and wake.
|
36
|
+
# - classic: Levels data returned with 60-second granularity. 'Sleep Pattern' levels include asleep, restless, and awake.
|
37
|
+
#
|
38
|
+
# The response could be a mix of classic and stages sleep logs.
|
39
|
+
#
|
40
|
+
# <b>Note:</b> shortData is only included for stages sleep logs and
|
41
|
+
# includes wake periods that are 3 minutes or less in duration.
|
42
|
+
#
|
43
|
+
# This distinction is to simplify graphically distinguishing short wakes
|
44
|
+
# from longer wakes, but they are physiologically equivalent.
|
45
|
+
def sleep_logs_by_date(date, options = {})
|
46
|
+
path = "/sleep/date/#{iso_date(date)}"
|
47
|
+
sleep_default_version!(options)
|
48
|
+
get_json(path_user_version(path, options))
|
49
|
+
end
|
50
|
+
|
51
|
+
# The Get Sleep Logs by Date Range endpoint returns a list of a user's
|
52
|
+
# sleep log entries (including naps) as well as detailed sleep entry data
|
53
|
+
# for a given date range (inclusive of start and end dates).
|
54
|
+
#
|
55
|
+
# This endpoint supports two kinds of sleep data:
|
56
|
+
# - stages : Levels data is returned with 30-second granularity. 'Sleep Stages' levels include deep, light, rem, and wake.
|
57
|
+
# - classic : Levels data returned with 60-second granularity. 'Sleep Pattern' levels include asleep, restless, and awake.
|
58
|
+
#
|
59
|
+
# The response could be a mix of classic and stages sleep logs.
|
60
|
+
#
|
61
|
+
# <b>Note:</b> shortData is only included for stages sleep logs and
|
62
|
+
# includes wake periods that are 3 minutes or less in duration.
|
63
|
+
#
|
64
|
+
# This distinction is to simplify graphically distinguishing short wakes
|
65
|
+
# from longer wakes, but they are physiologically equivalent.
|
66
|
+
def sleep_logs_by_date_range(start_date, end_date, options = {})
|
67
|
+
path = "/sleep/date/#{iso_date(start_date)}/#{iso_date(end_date)}"
|
68
|
+
sleep_default_version!(options)
|
69
|
+
get_json(path_user_version(path, options))
|
70
|
+
end
|
71
|
+
|
72
|
+
# The Get Sleep Logs List endpoint returns a list of a user's sleep logs
|
73
|
+
# (including naps) before or after a given day with offset, limit, and sort order.
|
74
|
+
#
|
75
|
+
# This endpoint supports two kinds of sleep data:
|
76
|
+
# - stages : Levels data is returned with 30-second granularity. 'Sleep Stages' levels include deep, light, rem, and wake.
|
77
|
+
# - classic : Levels data returned with 60-second granularity. 'Sleep Pattern' levels include asleep, restless, and awake.
|
78
|
+
#
|
79
|
+
# The response could be a mix of classic and stages sleep logs.
|
80
|
+
#
|
81
|
+
# <b>Note:</b> shortData is only included for stages sleep logs and
|
82
|
+
# includes wake periods that are 3 minutes or less in duration.
|
83
|
+
#
|
84
|
+
# This distinction is to simplify graphically distinguishing short wakes
|
85
|
+
# from longer wakes, but they are physiologically equivalent.
|
86
|
+
#
|
87
|
+
# before_date : Either beforeDate or afterDate must be specified.
|
88
|
+
# Set sort to desc when using beforeDate.
|
89
|
+
# after_date : Either beforeDate or afterDate must be specified.
|
90
|
+
# Set sort to asc when using afterDate.
|
91
|
+
def sleep_logs_list(before_date, after_date, sort, limit, options = {})
|
92
|
+
raise 'Before date and Atfer date cannot both be specified' if before_date && after_date
|
93
|
+
if before_date
|
94
|
+
params = { 'beforeDate' => iso_date(before_date), 'sort' => sort, 'limit' => limit, 'offset' => 0 }
|
95
|
+
elsif after_date
|
96
|
+
params = { 'afterDate' => iso_date(after_date), 'sort' => sort, 'limit' => limit, 'offset' => 0 }
|
97
|
+
end
|
98
|
+
sleep_default_version!(options)
|
99
|
+
get_json(path_user_version('/sleep/list', options), params)
|
100
|
+
end
|
101
|
+
|
102
|
+
# The Log Sleep endpoint creates a log entry for a sleep event and
|
103
|
+
# returns a response in the format requested. Keep in mind that it is NOT
|
104
|
+
# possible to create overlapping log entries.
|
105
|
+
#
|
106
|
+
# The dateOfSleep in the response for the sleep log is the date on which
|
107
|
+
# the sleep event ends.
|
108
|
+
|
109
|
+
# It requires read & write access
|
110
|
+
def log_sleep(start_time, duration_milliseconds, date, options = {})
|
111
|
+
params = { 'date' => iso_date(date), 'startTime' => start_time.strftime('%H:%M'), 'duration' => duration_milliseconds }
|
112
|
+
sleep_default_version!(options)
|
113
|
+
post_json(path_user_version('/sleep'), params)
|
114
|
+
end
|
115
|
+
|
116
|
+
# The Delete Sleep Log endpoint deletes a user's sleep log entry with the
|
117
|
+
# given ID.
|
118
|
+
def delete_sleep_log(log_id)
|
119
|
+
successful_delete?(delete(path_user_version("/sleep/#{log_id}")))
|
120
|
+
end
|
121
|
+
|
122
|
+
# The Get Sleep Goal endpoint returns a user's current sleep goal using
|
123
|
+
# unit in the unit system that corresponds to the Accept-Language header
|
124
|
+
# provided in the format requested.
|
125
|
+
def sleep_goals
|
126
|
+
get_json(path_user_version('/sleep/goal'))
|
127
|
+
end
|
128
|
+
|
129
|
+
# Creates or updates a user's sleep goal and get a response in the in the
|
130
|
+
# format requested.
|
131
|
+
#
|
132
|
+
# Access Type: Read & Write
|
133
|
+
#
|
134
|
+
# min_duration_minutes : The target sleep duration is in minutes
|
135
|
+
def update_sleep_goals(min_duration_minutes)
|
136
|
+
post_json(path_user_version('/sleep/goal'), 'minDuration' => min_duration_minutes)
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def sleep_default_version!(options)
|
142
|
+
if options[:version] == '1'
|
143
|
+
warn '[DEPRECATION] These endpoints are deprecated and support for them may end unexpectedly. If your application does not depend on the sleep as calculated by these endpoints, please use the new v1.2 sleep endpoints.'
|
144
|
+
else
|
145
|
+
options[:version] = '1.2'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|