dexcom 0.2.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d92f8ee13e26400f77410fae6493272443160c5b0127a3707803441bdc9ac3ca
4
+ data.tar.gz: fc1ab6d1dcf9ef7830621422fa6e24900a3274745ea6844e7b3e8901ec7920b1
5
+ SHA512:
6
+ metadata.gz: aa6c3c86b3cf48bd6fae4d68c2eed1c7b44999d6e0f69282ce3742bbe7379d46c2e5f3b1696b92a2729a3fa7febedc0b072a1d93945ef186bc8b19f273589b4d
7
+ data.tar.gz: 807626594715076c8ad214156e3117a97eea810afa1b5feb4b182e6b7bb43c176ae8cc6f0a1e8d9d140e92dd12c49cd0ebeb7a18596fc83e25dc7d0bd7b1e9da
@@ -0,0 +1,8 @@
1
+ # Gems
2
+ *.gem
3
+
4
+ # Bundler config
5
+ .bundle/*
6
+
7
+ # RSpec last test run data
8
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
@@ -0,0 +1,76 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dexcom (0.1.0)
5
+ httparty
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activesupport (5.2.3)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (>= 0.7, < 2)
13
+ minitest (~> 5.1)
14
+ tzinfo (~> 1.1)
15
+ addressable (2.7.0)
16
+ public_suffix (>= 2.0.2, < 5.0)
17
+ climate_control (0.2.0)
18
+ coderay (1.1.3)
19
+ concurrent-ruby (1.1.5)
20
+ crack (0.4.3)
21
+ safe_yaml (~> 1.0.0)
22
+ diff-lcs (1.3)
23
+ factory_bot (5.0.2)
24
+ activesupport (>= 4.2.0)
25
+ hashdiff (1.0.1)
26
+ httparty (0.18.0)
27
+ mime-types (~> 3.0)
28
+ multi_xml (>= 0.5.2)
29
+ i18n (1.6.0)
30
+ concurrent-ruby (~> 1.0)
31
+ method_source (1.0.0)
32
+ mime-types (3.3.1)
33
+ mime-types-data (~> 3.2015)
34
+ mime-types-data (3.2020.0512)
35
+ minitest (5.11.3)
36
+ multi_xml (0.6.0)
37
+ pry (0.13.1)
38
+ coderay (~> 1.1)
39
+ method_source (~> 1.0)
40
+ public_suffix (4.0.5)
41
+ rspec (3.9.0)
42
+ rspec-core (~> 3.9.0)
43
+ rspec-expectations (~> 3.9.0)
44
+ rspec-mocks (~> 3.9.0)
45
+ rspec-core (3.9.2)
46
+ rspec-support (~> 3.9.3)
47
+ rspec-expectations (3.9.2)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.9.0)
50
+ rspec-mocks (3.9.1)
51
+ diff-lcs (>= 1.2.0, < 2.0)
52
+ rspec-support (~> 3.9.0)
53
+ rspec-support (3.9.3)
54
+ safe_yaml (1.0.5)
55
+ thread_safe (0.3.6)
56
+ tzinfo (1.2.5)
57
+ thread_safe (~> 0.1)
58
+ webmock (3.8.3)
59
+ addressable (>= 2.3.6)
60
+ crack (>= 0.3.2)
61
+ hashdiff (>= 0.4.0, < 2.0.0)
62
+
63
+ PLATFORMS
64
+ ruby
65
+
66
+ DEPENDENCIES
67
+ bundler
68
+ climate_control
69
+ dexcom!
70
+ factory_bot
71
+ pry
72
+ rspec
73
+ webmock
74
+
75
+ BUNDLED WITH
76
+ 2.0.2
@@ -0,0 +1,2 @@
1
+ # dexcom-ruby
2
+ Gem to interact with Dexcom Share API, enabling real-time retrieval of glucose data
@@ -0,0 +1,3 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
@@ -0,0 +1,32 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'dexcom/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'dexcom'
8
+ spec.version = Dexcom::VERSION
9
+ spec.summary = 'Gem to interact with Dexcom Share API'
10
+ spec.authors = ['Alex Gascon']
11
+ spec.email = 'alexgascon.93@gmail.com'
12
+ spec.license = 'MIT'
13
+
14
+ # Specify which files should be added to the gem when it is released.
15
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
16
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ end
19
+
20
+ spec.bindir = 'exe'
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'httparty'
25
+
26
+ spec.add_development_dependency 'bundler'
27
+ spec.add_development_dependency 'climate_control'
28
+ spec.add_development_dependency 'factory_bot'
29
+ spec.add_development_dependency 'pry'
30
+ spec.add_development_dependency 'rspec'
31
+ spec.add_development_dependency 'webmock'
32
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dexcom/authentication'
4
+ require 'dexcom/blood_glucose'
5
+ require 'dexcom/configuration'
6
+ require 'dexcom/constants'
7
+ require 'dexcom/version'
8
+
9
+ module Dexcom
10
+ class << self
11
+ def configuration
12
+ @configuration ||= Configuration.new
13
+ end
14
+
15
+ def configure
16
+ yield configuration
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty'
4
+
5
+ module Dexcom
6
+ class Authentication
7
+ class << self
8
+ def access_token
9
+ refresh_access_token if @access_token.nil?
10
+
11
+ @access_token
12
+ end
13
+
14
+ def session_id
15
+ refresh_access_token unless auth_started?
16
+ refresh_session_id if @session_id.nil?
17
+
18
+ @session_id
19
+ end
20
+
21
+ def renew_authentication
22
+ @access_token = nil
23
+ @session_id = nil
24
+
25
+ refresh_access_token
26
+ refresh_session_id
27
+ end
28
+
29
+ private
30
+
31
+ def auth_started?
32
+ !@access_token.nil?
33
+ end
34
+
35
+ def refresh_access_token
36
+ response = authenticate
37
+ @access_token = remove_double_quotes(response)
38
+ end
39
+
40
+ def refresh_session_id
41
+ response = login
42
+ @session_id = remove_double_quotes(response)
43
+ end
44
+
45
+ def config
46
+ @config ||= Dexcom.configuration
47
+ end
48
+
49
+ def authenticate
50
+ HTTParty.post(
51
+ authenticate_endpoint,
52
+ headers: credentials_headers,
53
+ body: credentials_payload.to_json
54
+ )
55
+ end
56
+
57
+ def authenticate_endpoint
58
+ "#{config.base_url}/General/AuthenticatePublisherAccount"
59
+ end
60
+
61
+ def login
62
+ HTTParty.post(
63
+ login_endpoint,
64
+ headers: credentials_headers,
65
+ body: credentials_payload.to_json
66
+ )
67
+ end
68
+
69
+ def login_endpoint
70
+ "#{config.base_url}/General/LoginPublisherAccountByName"
71
+ end
72
+
73
+ def credentials_headers
74
+ {
75
+ 'User-Agent' => USER_AGENT,
76
+ 'Content-Type' => 'application/json'
77
+ }
78
+ end
79
+
80
+ def credentials_payload
81
+ {
82
+ accountName: config.username,
83
+ password: config.password,
84
+ applicationId: APPLICATION_ID
85
+ }
86
+ end
87
+
88
+ def remove_double_quotes(text)
89
+ text.gsub('"', '')
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dexcom/blood_glucose/api_handler'
4
+ require 'dexcom/blood_glucose/class_methods'
5
+
6
+ module Dexcom
7
+ class BloodGlucose
8
+ extend BloodGlucoseUtils::ApiHandler
9
+ extend BloodGlucoseUtils::ClassMethods
10
+
11
+ MGDL_TO_MMOL_FACTOR = 0.0555
12
+
13
+ TRENDS = {
14
+ 0 => { symbol: '', description: '' },
15
+ 1 => { symbol: '↑↑', description: 'Rising quickly' },
16
+ 2 => { symbol: '↑', description: 'Rising' },
17
+ 3 => { symbol: '↗', description: 'Rising slightly' },
18
+ 4 => { symbol: '→', description: 'Steady' },
19
+ 5 => { symbol: '↘', description: 'Falling slightly' },
20
+ 6 => { symbol: '↓', description: 'Falling' },
21
+ 7 => { symbol: '↓↓', description: 'Falling quickly' },
22
+ 8 => { symbol: '?', description: 'Undetermined' },
23
+ 9 => { symbol: '-', description: 'Trend unavailable' }
24
+ }.freeze
25
+
26
+ attr_reader :timestamp, :trend, :value
27
+
28
+ alias mg_dl value
29
+
30
+ def initialize(value, trend, timestamp)
31
+ @value = value
32
+ @trend = trend
33
+ @timestamp = timestamp
34
+ end
35
+
36
+ def mmol
37
+ (mg_dl * MGDL_TO_MMOL_FACTOR).round(1)
38
+ end
39
+
40
+ def trend_symbol
41
+ TRENDS.dig(trend, :symbol)
42
+ end
43
+
44
+ def trend_description
45
+ TRENDS.dig(trend, :description)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dexcom
4
+ module BloodGlucoseUtils
5
+ module ApiHandler
6
+ MAX_MINUTES = 1440
7
+
8
+ def make_api_request(number_of_values)
9
+ HTTParty.post(
10
+ endpoint,
11
+ headers: headers,
12
+ query: query(number_of_values)
13
+ )
14
+ end
15
+
16
+ def process_api_response(response)
17
+ response_body = JSON.parse(response.body)
18
+
19
+ response_body.map { |blood_glucose_item| build_from_api_response(blood_glucose_item) }
20
+ end
21
+
22
+ def build_from_api_response(blood_glucose_response_item)
23
+ Dexcom::BloodGlucose.new(
24
+ blood_glucose_response_item['Value'],
25
+ blood_glucose_response_item['Trend'],
26
+ parse_timestamp(blood_glucose_response_item)
27
+ )
28
+ end
29
+
30
+ private
31
+
32
+ def endpoint
33
+ "#{config.base_url}/Publisher/ReadPublisherLatestGlucoseValues"
34
+ end
35
+
36
+ def headers
37
+ {
38
+ 'User-Agent' => USER_AGENT
39
+ }
40
+ end
41
+
42
+ def query(max_count)
43
+ {
44
+ maxCount: max_count,
45
+ minutes: MAX_MINUTES
46
+ }
47
+ end
48
+
49
+ def parse_timestamp(blood_glucose_response_item)
50
+ timestamp_info = blood_glucose_response_item['WT']
51
+ timestamp_regex = /(\d+)000/
52
+ timestamp = timestamp_info[timestamp_regex, 1]
53
+ utc = '+00:00'
54
+
55
+ DateTime.parse(Time.at(timestamp.to_i, in: utc).to_s)
56
+ end
57
+
58
+ def config
59
+ @config ||= Dexcom.configuration
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal
2
+
3
+ module Dexcom
4
+ module BloodGlucoseUtils
5
+ module ClassMethods
6
+ DEFAULT_NUMBER_OF_VALUES = 1
7
+ MINUTES_PER_DATAPOINT = 5
8
+
9
+ def last
10
+ get_last(max_count: 1)
11
+ end
12
+
13
+ def get_last(max_count: nil, minutes: nil)
14
+ number_of_values = calculate_number_of_values(max_count, minutes)
15
+
16
+ response = make_api_request(number_of_values)
17
+ process_api_response(response)
18
+ end
19
+
20
+ private
21
+
22
+ def calculate_number_of_values(max_count, minutes)
23
+ if minutes.nil?
24
+ max_count || DEFAULT_NUMBER_OF_VALUES
25
+ elsif max_count.nil?
26
+ minutes / MINUTES_PER_DATAPOINT
27
+ else
28
+ [max_count, minutes / MINUTES_PER_DATAPOINT].min
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dexcom
4
+ class Configuration
5
+ attr_accessor :username, :password, :outside_usa
6
+
7
+ def initialize
8
+ @username = nil
9
+ @password = nil
10
+ @outside_usa = nil
11
+ end
12
+
13
+ def base_url
14
+ outside_usa ? URL_BASE_OUTSIDE_USA : URL_BASE
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dexcom
4
+ APPLICATION_ID = 'd89443d2-327c-4a6f-89e5-496bbb0317db'
5
+ USER_AGENT = 'Dexcom Share/3.0.2.11 CFNetwork/711.2.23 Darwin/14.0.0'
6
+
7
+ URL_BASE = 'https://share2.dexcom.com/ShareWebServices/Services'
8
+ URL_BASE_OUTSIDE_USA = 'https://shareous1.dexcom.com/ShareWebServices/Services'
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dexcom
4
+ VERSION = '0.2.0'
5
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dexcom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Gascon
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: climate_control
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: factory_bot
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description:
112
+ email: alexgascon.93@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - ".gitignore"
118
+ - ".rspec"
119
+ - Gemfile
120
+ - Gemfile.lock
121
+ - README.md
122
+ - Rakefile
123
+ - dexcom.gemspec
124
+ - lib/dexcom.rb
125
+ - lib/dexcom/authentication.rb
126
+ - lib/dexcom/blood_glucose.rb
127
+ - lib/dexcom/blood_glucose/api_handler.rb
128
+ - lib/dexcom/blood_glucose/class_methods.rb
129
+ - lib/dexcom/configuration.rb
130
+ - lib/dexcom/constants.rb
131
+ - lib/dexcom/version.rb
132
+ homepage:
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 3.0.3
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: Gem to interact with Dexcom Share API
155
+ test_files: []