ruby-fitbit 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +26 -10
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/bin/ruby-fitbit +36 -12
- data/lib/ruby-fitbit.rb +72 -8
- data/ruby-fitbit.gemspec +66 -0
- metadata +35 -6
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
This is a Ruby API for the fitbit and the data at fitbit.com
|
4
4
|
|
5
|
-
Currently the gem uses screen scraping to get the data, but it will switch over to use the official API once available. The current set of data it retrieves is pretty limited, but it should grow over time. Originally built just to display a dashboard of my current fitbit stats on my blog.
|
5
|
+
Currently the gem uses screen scraping to get the data, but it will switch over to use the official API once available. The current set of data it retrieves is pretty limited, but it should grow over time. Originally built just to display a dashboard of my current fitbit stats on my blog. I started adding additonal data scrapped from the graphs. Which allows me to export the data or do my own charting.
|
6
6
|
|
7
7
|
== Usage
|
8
8
|
|
@@ -17,13 +17,8 @@ Currently the gem uses screen scraping to get the data, but it will switch over
|
|
17
17
|
fitbit = RubyFitbit.new(EMAIL,PASSWORD)
|
18
18
|
|
19
19
|
puts "Calories Burned #{fitbit.calories}"
|
20
|
-
|
21
|
-
|
22
|
-
puts "Activity Levels Durations:"
|
23
|
-
puts "Sedentary #{fitbit.sedentary_active}"
|
24
|
-
puts "Lightly #{fitbit.lightly_active}"
|
25
|
-
puts "Fairly #{fitbit.fairly_active}"
|
26
|
-
puts "Very #{fitbit.very_active}"
|
20
|
+
...
|
21
|
+
look at bin.ruby-fitbit for example usage of coding to the client.
|
27
22
|
|
28
23
|
output
|
29
24
|
~/projects/ruby-fitbit(master) > ruby bin/ruby-fitbit my@email.com MYPASS
|
@@ -38,11 +33,32 @@ Currently the gem uses screen scraping to get the data, but it will switch over
|
|
38
33
|
|
39
34
|
done
|
40
35
|
|
36
|
+
advanced usage: Print activity, steps, or calorie data broken down in 5 minute chunks for a given date.
|
37
|
+
~/projects/ruby-fitbit(master) > ruby bin/ruby-fitbit my@email.com MYPASS activity 06/22/2010
|
38
|
+
Calories Burned 803
|
39
|
+
Steps Taken 552
|
40
|
+
Milkes Walked .23
|
41
|
+
Activity Levels Durations:
|
42
|
+
Sedentary 11hrs 1min
|
43
|
+
Lightly 18min
|
44
|
+
Fairly 16min
|
45
|
+
Very 0min
|
46
|
+
|
47
|
+
+--------------------------------+------+
|
48
|
+
| 0 | 1 |
|
49
|
+
+--------------------------------+------+
|
50
|
+
| Tue Jun 22 21:50:00 -0400 2010 | 10.0 |
|
51
|
+
| Tue Jun 22 05:05:00 -0400 2010 | 0.0 |
|
52
|
+
| Tue Jun 22 16:15:00 -0400 2010 | 0.0 |
|
53
|
+
| Tue Jun 22 10:40:00 -0400 2010 | 0.0 |
|
54
|
+
...
|
55
|
+
|
56
|
+
done
|
57
|
+
|
58
|
+
|
41
59
|
|
42
60
|
== TODOs
|
43
61
|
|
44
|
-
* Get data from any date not just current data
|
45
|
-
* get the minute by minute calorie chart breakdowns
|
46
62
|
* get food intake tracked etc
|
47
63
|
* add ability for gem to write data to fitbit, such as log and food entries
|
48
64
|
* build everything needed for a nice fitbit IPhone app to use this API.
|
data/Rakefile
CHANGED
@@ -10,7 +10,9 @@ begin
|
|
10
10
|
gem.email = "Danmayer@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/danmayer/ruby-fitbit"
|
12
12
|
gem.authors = ["Dan Mayer"]
|
13
|
-
gem.add_development_dependency "
|
13
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
14
|
+
gem.add_dependency "nokogiri", ">= 1.3.0"
|
15
|
+
gem.add_dependency "hirb", ">= 0.2.10"
|
14
16
|
gem.add_dependency "mechanize", ">= 0.9.3"
|
15
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
18
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/bin/ruby-fitbit
CHANGED
@@ -1,16 +1,40 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'ruby-fitbit')
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'ruby-fitbit')
|
3
|
+
require 'hirb'
|
3
4
|
|
4
|
-
|
5
|
+
if(ARGV[0]!=nil && ARGV[1]!=nil)
|
6
|
+
fitbit = RubyFitbit.new(ARGV[0],ARGV[1])
|
7
|
+
|
8
|
+
puts "Calories Burned #{fitbit.calories}"
|
9
|
+
puts "Steps Taken #{fitbit.steps}"
|
10
|
+
puts "Milkes Walked #{fitbit.miles_walked}"
|
11
|
+
puts "Activity Levels Durations:"
|
12
|
+
puts "Sedentary #{fitbit.sedentary_active}"
|
13
|
+
puts "Lightly #{fitbit.lightly_active}"
|
14
|
+
puts "Fairly # => {fitbit.fairly_active}"
|
15
|
+
puts "Very #{fitbit.very_active}"
|
16
|
+
end
|
5
17
|
|
6
|
-
|
7
|
-
puts "Steps Taken #{fitbit.steps}"
|
8
|
-
puts "Milkes Walked #{fitbit.miles_walked}"
|
9
|
-
puts "Activity Levels Durations:"
|
10
|
-
puts "Sedentary #{fitbit.sedentary_active}"
|
11
|
-
puts "Lightly #{fitbit.lightly_active}"
|
12
|
-
puts "Fairly #{fitbit.fairly_active}"
|
13
|
-
puts "Very #{fitbit.very_active}"
|
18
|
+
if ARGV[2]!=nil
|
14
19
|
|
15
|
-
|
16
|
-
|
20
|
+
begin
|
21
|
+
date = Time.parse(ARGV[3])
|
22
|
+
rescue
|
23
|
+
date = Time.now
|
24
|
+
end
|
25
|
+
|
26
|
+
case ARGV[2]
|
27
|
+
when 'calorie'
|
28
|
+
puts "calorie data for data #{date}"
|
29
|
+
data = fitbit.get_calorie_data(date)
|
30
|
+
when 'activity'
|
31
|
+
puts "calorie data for data #{date}"
|
32
|
+
data = fitbit.get_activity_score_data(date)
|
33
|
+
else
|
34
|
+
puts "steps data for data #{date}"
|
35
|
+
data = fitbit.get_steps_data(date)
|
36
|
+
end
|
37
|
+
puts Hirb::Helpers::AutoTable.render(data)
|
38
|
+
end
|
39
|
+
|
40
|
+
puts "done"
|
data/lib/ruby-fitbit.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'mechanize'
|
3
|
+
require 'nokogiri'
|
3
4
|
|
4
5
|
class RubyFitbit
|
5
6
|
|
@@ -8,18 +9,35 @@ class RubyFitbit
|
|
8
9
|
def initialize(email, pass)
|
9
10
|
@email = email
|
10
11
|
@pass = pass
|
12
|
+
@agent = WWW::Mechanize.new #{|a| a.log = Logger.new(STDERR) } #turn on if debugging
|
13
|
+
@logged_in = false
|
11
14
|
get_data
|
12
15
|
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
#todo only login once
|
18
|
+
def login
|
19
|
+
unless @logged_in
|
20
|
+
page = @agent.get 'https://www.fitbit.com/login'
|
21
|
+
|
22
|
+
form = page.forms.first
|
23
|
+
form.email = @email
|
24
|
+
form.password = @pass
|
25
|
+
|
26
|
+
page = @agent.submit(form, form.buttons.first)
|
27
|
+
|
28
|
+
@userId = page.search("//div[@class='accountLinks']").search("a")[0]['href'].gsub('/user/','')
|
29
|
+
# @agent.cookie_jar.jar["www.fitbit.com"]['/']['uid'].value
|
30
|
+
# @agent.cookie_jar.jar["www.fitbit.com"]['/']['sid'].value
|
21
31
|
|
22
|
-
|
32
|
+
@logged_in = true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_data(date = Time.now)
|
37
|
+
login
|
38
|
+
|
39
|
+
date = get_fitbit_date_format(date).gsub('-','/')
|
40
|
+
page = @agent.get "https://www.fitbit.com/#{date}"
|
23
41
|
|
24
42
|
@calories = page.search("//div[@class='data']").search("span").children[0].text
|
25
43
|
@steps = page.search("//div[@class='data']").search("span").children[2].text.strip
|
@@ -30,4 +48,50 @@ class RubyFitbit
|
|
30
48
|
@very_active = page.search("//div[@class='caption very']/div[@class='number']").text.strip
|
31
49
|
end
|
32
50
|
|
51
|
+
def get_steps_data(date = Time.now)
|
52
|
+
get_graph_data('intradaySteps',date)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_calorie_data(date = Time.now)
|
56
|
+
get_graph_data('intradayCaloriesBurned',date)
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_activity_score_data(date = Time.now)
|
60
|
+
get_graph_data('intradayActiveScore',date)
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_graph_data(graph_type = 'intradaySteps', date = Time.now, data_version = '2108')
|
64
|
+
login
|
65
|
+
|
66
|
+
date = get_fitbit_date_format(date)
|
67
|
+
|
68
|
+
params = {:userId => @userId,
|
69
|
+
:type => graph_type,
|
70
|
+
:version => "amchart",
|
71
|
+
:dataVersion => data_version,
|
72
|
+
:chart_Type => "column2d",
|
73
|
+
:period => "1d",
|
74
|
+
:dateTo => date}
|
75
|
+
|
76
|
+
params = WWW::Mechanize::Util.build_query_string(params)
|
77
|
+
uri = "http://www.fitbit.com/graph/getGraphData?#{params}"
|
78
|
+
|
79
|
+
page = @agent.get uri
|
80
|
+
doc = Nokogiri::HTML(page.content)
|
81
|
+
minutes_segment = 0
|
82
|
+
chart_data = {}
|
83
|
+
doc.xpath('//data/chart/graphs/graph/value').each do |ele|
|
84
|
+
moment = Time.parse(date)+(5*60*minutes_segment)
|
85
|
+
minutes_segment += 1
|
86
|
+
chart_data[moment] = ele.child.text
|
87
|
+
end
|
88
|
+
|
89
|
+
chart_data
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_fitbit_date_format(date)
|
93
|
+
#fitbit date format expects like so: 2010-06-24
|
94
|
+
date = date.strftime("%Y-%m-%d")
|
95
|
+
end
|
96
|
+
|
33
97
|
end
|
data/ruby-fitbit.gemspec
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ruby-fitbit}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Dan Mayer"]
|
12
|
+
s.date = %q{2010-07-03}
|
13
|
+
s.default_executable = %q{ruby-fitbit}
|
14
|
+
s.description = %q{This is a Ruby API for Fitbit.com, currently scraping, but soon will use the officail API (when released)}
|
15
|
+
s.email = %q{Danmayer@gmail.com}
|
16
|
+
s.executables = ["ruby-fitbit"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
"LICENSE",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"bin/ruby-fitbit",
|
29
|
+
"lib/ruby-fitbit.rb",
|
30
|
+
"ruby-fitbit.gemspec",
|
31
|
+
"test/helper.rb",
|
32
|
+
"test/test_ruby-fitbit.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/danmayer/ruby-fitbit}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.6}
|
38
|
+
s.summary = %q{This is a Ruby API for Fitbit.com}
|
39
|
+
s.test_files = [
|
40
|
+
"test/helper.rb",
|
41
|
+
"test/test_ruby-fitbit.rb"
|
42
|
+
]
|
43
|
+
|
44
|
+
if s.respond_to? :specification_version then
|
45
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
46
|
+
s.specification_version = 3
|
47
|
+
|
48
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
50
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.0"])
|
51
|
+
s.add_runtime_dependency(%q<hirb>, [">= 0.2.10"])
|
52
|
+
s.add_runtime_dependency(%q<mechanize>, [">= 0.9.3"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
55
|
+
s.add_dependency(%q<nokogiri>, [">= 1.3.0"])
|
56
|
+
s.add_dependency(%q<hirb>, [">= 0.2.10"])
|
57
|
+
s.add_dependency(%q<mechanize>, [">= 0.9.3"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
61
|
+
s.add_dependency(%q<nokogiri>, [">= 1.3.0"])
|
62
|
+
s.add_dependency(%q<hirb>, [">= 0.2.10"])
|
63
|
+
s.add_dependency(%q<mechanize>, [">= 0.9.3"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
- 0
|
8
7
|
- 1
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Dan Mayer
|
@@ -14,11 +14,11 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-07-03 00:00:00 -04:00
|
18
18
|
default_executable: ruby-fitbit
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: shoulda
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
@@ -30,9 +30,37 @@ dependencies:
|
|
30
30
|
type: :development
|
31
31
|
version_requirements: *id001
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
33
|
+
name: nokogiri
|
34
34
|
prerelease: false
|
35
35
|
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 1
|
41
|
+
- 3
|
42
|
+
- 0
|
43
|
+
version: 1.3.0
|
44
|
+
type: :runtime
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: hirb
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
- 2
|
56
|
+
- 10
|
57
|
+
version: 0.2.10
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id003
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: mechanize
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
36
64
|
requirements:
|
37
65
|
- - ">="
|
38
66
|
- !ruby/object:Gem::Version
|
@@ -42,7 +70,7 @@ dependencies:
|
|
42
70
|
- 3
|
43
71
|
version: 0.9.3
|
44
72
|
type: :runtime
|
45
|
-
version_requirements: *
|
73
|
+
version_requirements: *id004
|
46
74
|
description: This is a Ruby API for Fitbit.com, currently scraping, but soon will use the officail API (when released)
|
47
75
|
email: Danmayer@gmail.com
|
48
76
|
executables:
|
@@ -61,6 +89,7 @@ files:
|
|
61
89
|
- VERSION
|
62
90
|
- bin/ruby-fitbit
|
63
91
|
- lib/ruby-fitbit.rb
|
92
|
+
- ruby-fitbit.gemspec
|
64
93
|
- test/helper.rb
|
65
94
|
- test/test_ruby-fitbit.rb
|
66
95
|
has_rdoc: true
|