fitbit-to-graphite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fitbit-to-graphite (0.1.0)
5
+ choice
6
+ fitgem
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ choice (0.1.6)
12
+ fitgem (0.8.0)
13
+ oauth
14
+ oauth (0.4.7)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ fitbit-to-graphite!
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2013 Daniel Schauenberg
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,45 @@
1
+ # fitbit-to-graphite
2
+
3
+ ## Synopsis
4
+ Record sleep data from fitbit to graphite. That's it.
5
+
6
+ ## Installation
7
+ You can get the script from rubygems:
8
+
9
+ gem install fitbit-to-graphite
10
+
11
+ ## Setup
12
+ fitbit-to-graphite reads its config file at `~/.fitgem.yml` which at least
13
+ needs the following settings:
14
+ ```
15
+ ---
16
+ :oauth:
17
+ :consumer_key: thekey
18
+ :consumer_secret: thesecret
19
+ ```
20
+ Fill in the key and secret from the app you created for it and on first run it
21
+ should register the OAuth data.
22
+
23
+ ## Usage
24
+ ```
25
+ % fitbit-to-graphite.rb --help
26
+ Usage: fitbit-to-graphite.rb [-hpnv]
27
+
28
+ Specific options:
29
+ -h, --host=HOST The hostname or ip of the host graphite is running on
30
+ -p, --port=PORT The port graphite is listening on
31
+ -n, --namespace=NAMESPACE The graphite metric path to store data in
32
+
33
+ Common options:
34
+ --help Show this message
35
+ -v, --version Show version
36
+ --debug run in debug mode
37
+ --jawbone send jawbone compatible data
38
+ ```
39
+
40
+ ## How to contribute
41
+ 1. Fork the repo
42
+ 2. Hack away
43
+ 3. Push the branch up to GitHub
44
+ 4. Send a pull request
45
+
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # simple script to import your sleep data from Fitbit into Graphite
5
+ #
6
+
7
+ require 'date'
8
+ require 'yaml'
9
+
10
+ require 'choice'
11
+ require 'fitgem'
12
+
13
+ PROGRAM_VERSION = "0.1.0"
14
+ SLEEP_STATE_TYPES = ['deep', 'light', 'awake']
15
+ # this is just to be compatible with jawbone data
16
+ JAWBONE_SLEEP_STATES = { 'awake' => 1, 'light' => 2, 'deep' => 3 }
17
+
18
+ Choice.options do
19
+ header ''
20
+ header 'Specific options:'
21
+
22
+ option :host do
23
+ short '-h'
24
+ long '--host=HOST'
25
+ desc 'The hostname or ip of the host graphite is running on'
26
+ default '127.0.0.1'
27
+ end
28
+
29
+ option :port do
30
+ short '-p'
31
+ long '--port=PORT'
32
+ desc 'The port graphite is listening on'
33
+ cast Integer
34
+ default 2003
35
+ end
36
+
37
+ option :namespace do
38
+ short '-n'
39
+ long '--namespace=NAMESPACE'
40
+ desc 'The graphite metric path to store data in'
41
+ end
42
+
43
+ separator ''
44
+ separator 'Common options: '
45
+
46
+ option :help do
47
+ long '--help'
48
+ desc 'Show this message'
49
+ end
50
+
51
+ option :version do
52
+ short '-v'
53
+ long '--version'
54
+ desc 'Show version'
55
+ action do
56
+ puts "#{$0} Fitbit sleep data importer v#{PROGRAM_VERSION}"
57
+ exit
58
+ end
59
+ end
60
+
61
+ option :debug do
62
+ long '--debug'
63
+ desc 'run in debug mode'
64
+ end
65
+
66
+ option :jawbone do
67
+ long '--jawbone'
68
+ desc 'send jawbone compatible data'
69
+ end
70
+ end
71
+
72
+ def client_setup
73
+ # Load the existing yml config
74
+ config = begin
75
+ Fitgem::Client.symbolize_keys(YAML.load(File.open(File.join(ENV['HOME'], ".fitgem.yml"))))
76
+ rescue ArgumentError => e
77
+ puts "Could not parse YAML: #{e.message}"
78
+ exit
79
+ end
80
+
81
+ client = Fitgem::Client.new(config[:oauth])
82
+
83
+ # With the token and secret, we will try to use them
84
+ # to reconstitute a usable Fitgem::Client
85
+ if config[:oauth][:token] && config[:oauth][:secret]
86
+ begin
87
+ access_token = client.reconnect(config[:oauth][:token], config[:oauth][:secret])
88
+ rescue Exception => e
89
+ puts "Error: Could not reconnect Fitgem::Client due to invalid keys in .fitgem.yml"
90
+ exit
91
+ end
92
+ # Without the secret and token, initialize the Fitgem::Client
93
+ # and send the user to login and get a verifier token
94
+ else
95
+ request_token = client.request_token
96
+ token = request_token.token
97
+ secret = request_token.secret
98
+
99
+ puts "Go to http://www.fitbit.com/oauth/authorize?oauth_token=#{token} and then enter the verifier code below"
100
+ verifier = gets.chomp
101
+
102
+ begin
103
+ access_token = client.authorize(token, secret, { :oauth_verifier => verifier })
104
+ rescue Exception => e
105
+ puts "Error: Could not authorize Fitgem::Client with supplied oauth verifier"
106
+ exit
107
+ end
108
+
109
+ user_id = client.user_info['user']['encodedId']
110
+
111
+ config[:oauth].merge!(:token => access_token.token, :secret => access_token.secret, :user_id => user_id)
112
+
113
+ # Write the whole oauth token set back to the config file
114
+ File.open(File.join(ENV['HOME'], ".fitgem.yml"), "w") {|f| f.write(config.to_yaml) }
115
+ end
116
+
117
+ return client
118
+ end
119
+
120
+ def extract_data(client, &block)
121
+ if block.nil?
122
+ puts "No block given."
123
+ return
124
+ end
125
+ user_info = client.user_info
126
+ user_timezone = user_info['user']['timezone']
127
+ today = Date.today
128
+ all_sleep_data = client.sleep_on_date(today)['sleep']
129
+ if all_sleep_data.nil?
130
+ puts "API rate limit potentially exceeded."
131
+ return
132
+ end
133
+ sleep_data = []
134
+ sleep_summary = nil
135
+ all_sleep_data.each do |potential_log|
136
+ if potential_log['isMainSleep']
137
+ sleep_data = potential_log['minuteData']
138
+ sleep_summary = potential_log
139
+ end
140
+ end
141
+ createdate = DateTime.strptime("#{sleep_summary['startTime']}#{user_timezone}",'%Y-%m-%dT%H:%M:%S.%L%z').to_time.to_i
142
+ msg = ""
143
+ msg << "#{Choice[:namespace]}.summary.awakenings #{sleep_summary['awakeningsCount']} #{createdate}\n"
144
+ msg << "#{Choice[:namespace]}.summary.quality #{sleep_summary['efficiency']} #{createdate}\n"
145
+ msg << "#{Choice[:namespace]}.summary.deep_minutes #{sleep_summary['minutesAsleep']} #{createdate}\n"
146
+ msg << "#{Choice[:namespace]}.summary.light_minutes #{sleep_summary['minutesAwake']} #{createdate}\n"
147
+ sleep_data.each do |data|
148
+ d = DateTime.strptime("#{today.year}-#{today.month}-#{today.day}T#{data['dateTime']}#{user_timezone}",'%Y-%m-%dT%H:%M:%S%z')
149
+ state_name = SLEEP_STATE_TYPES[ data['value'].to_i - 1 ]
150
+ value = Choice[:jawbone] == true ? JAWBONE_SLEEP_STATES[state_name] : data['value']
151
+ msg << "#{Choice[:namespace]}.details.#{state_name} #{value} #{d.to_time.to_i}\n"
152
+ end
153
+ yield msg
154
+ end
155
+
156
+ def send_to_graphite(client)
157
+ extract_data(client) do |msg|
158
+ socket = TCPSocket.open(Choice[:host], Choice[:port])
159
+ socket.write(msg)
160
+ end
161
+ end
162
+
163
+ def print_sleep_data(client)
164
+ extract_data(client) {|msg| puts msg}
165
+ end
166
+
167
+
168
+ # main
169
+ client = client_setup
170
+ if Choice[:debug]
171
+ print_sleep_data(client)
172
+ else
173
+ send_to_graphite(client)
174
+ end
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'fitbit-to-graphite'
3
+ gem.version = '0.1.0'
4
+ gem.authors = ["Daniel Schauenberg"]
5
+ gem.email = 'd@unwiredcouch.com'
6
+ gem.homepage = 'https://github.com/mrtazz/fitbit-to-graphite'
7
+ gem.summary = "script to import fitbit sleep data into graphite"
8
+ gem.description = "script to import fitbit sleep data into graphite"
9
+ gem.license = 'MIT'
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.name = "fitbit-to-graphite"
13
+
14
+ gem.add_runtime_dependency "fitgem"
15
+ gem.add_runtime_dependency "choice"
16
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fitbit-to-graphite
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Daniel Schauenberg
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fitgem
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: choice
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: script to import fitbit sleep data into graphite
47
+ email: d@unwiredcouch.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - LICENSE
55
+ - README.md
56
+ - Rakefile
57
+ - bin/fitbit-to-graphite.rb
58
+ - fitbit-to-graphite.gemspec
59
+ homepage: https://github.com/mrtazz/fitbit-to-graphite
60
+ licenses:
61
+ - MIT
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.25
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: script to import fitbit sleep data into graphite
84
+ test_files: []
85
+ has_rdoc: