garmin_connect 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9bd93803810fe9523740c6c9e427f8c588a6d43f
4
+ data.tar.gz: f97df88d95857d8355dc8f815827f9ec37de9f91
5
+ SHA512:
6
+ metadata.gz: af77996055fab29a0469c9b5f163486c6bcc4debd5f0f6c40d8d15c83aa295b68180317bc2a638a6bdf1a2dfc3240c36f1068fe17a9e43282cf7d33897b580f8
7
+ data.tar.gz: a5511e4bd430a1f9387b0ac47f74416ce139948a3dcb46f6bd9a3d584e2361cdfbb58466c0d28e996818183e7e7188c28b31e5dcb545402e20392f5c352061b5
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Paul Hoffer
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # GarminConnect
2
+
3
+ I wrote this so I could more easily work with data from Garmin Connect. It's not really ready to be a gem, but I wanted to use it in a couple projects, so I'm releasing it for my own convenience. Usage instructions coming soon.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'garmin_connect'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install garmin_connect
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,9 @@
1
+ require 'json'
2
+
3
+ require 'garmin_connect/version'
4
+ require "garmin_connect/base"
5
+ require "garmin_connect/activity"
6
+
7
+ module GarminConnect
8
+ # Your code goes here...
9
+ end
@@ -0,0 +1,169 @@
1
+ require 'active_support/time'
2
+ module GarminConnect
3
+ class User
4
+ class << self
5
+ def base
6
+ 'http://connect.garmin.com/proxy/user-service-1.0/'
7
+ end
8
+ def get(format = nil)
9
+ Base.request(self.base, format, '/user')
10
+ end
11
+ end
12
+ end
13
+ class Metric
14
+ attr_accessor :multipled_temp, :multipled_hum, :custom_data, :seconds, :data
15
+ %w{directLongitude directHeartRate directHeartRateZone directHeartRatePercentMax directLatitude directTimestamp directSpeed directPace directElevation sumDistance sumElapsedDuration sumDuration sumMovingDuration}.each do |item|
16
+ define_method(item.to_sym) { @data[@data_types.index(item.to_s)] }
17
+ end
18
+
19
+ alias :longitude :directLongitude
20
+ alias :hr :directHeartRate
21
+ alias :hr_zone :directHeartRateZone
22
+ alias :hr_percent :directHeartRatePercentMax
23
+ alias :latitude :directLatitude
24
+ alias :timestamp :directTimestamp
25
+ alias :speed :directSpeed
26
+ alias :pace :directPace
27
+ alias :elevation :directElevation
28
+ alias :distance :sumDistance
29
+ alias :elapsed_duration :sumElapsedDuration
30
+ alias :sum_duration :sumDuration
31
+ alias :moving_duration :sumMovingDuration
32
+ def initialize(arr, data_types)
33
+ @data_types = data_types
34
+ @custom_data = {}
35
+ @data = arr
36
+ end
37
+ def time
38
+ Time.at(directTimestamp / 1000)
39
+ end
40
+ def method_missing(method, *args)
41
+ @data[@data_types.index(method.to_s)]
42
+ end
43
+ def latlong
44
+ [latitude, longitude]
45
+ end
46
+ def to_s
47
+ inspect
48
+ end
49
+
50
+ # def seconds
51
+ # trying to find a way to define it here
52
+ # end
53
+ # alias :lon :longitude
54
+ class << self
55
+ # @@order = %w{ longitude hr hr_zone hr_percent latitude timestamp speed pace elevation distance elapsed_duration sum_duration moving_duration }
56
+ # def position(what = nil)
57
+ # @@order.index(what)
58
+ # end
59
+ def init_multiple(metrics, data_types)
60
+ metrics.map{ |hash| new(hash['metrics'], data_types) }
61
+ end
62
+ end
63
+ end
64
+ class Activity
65
+ attr_reader :attributes
66
+
67
+ def initialize(data)
68
+ case data
69
+ when Hash
70
+ # nil
71
+ when Integer, String
72
+ data = self.class.get(data)
73
+ end
74
+ @metrics = nil
75
+ @attributes = data
76
+ end
77
+ def [](something)
78
+ @attributes[something]
79
+ end
80
+ def id
81
+ self.activityId
82
+ end
83
+ def time(what = :begin)
84
+ h = what == :begin ? self.activitySummary.BeginTimestamp : self.activitySummary.EndTimestamp
85
+ ActiveSupport::TimeWithZone.new(Time.parse(h.value), ActiveSupport::TimeZone.new(h.uom))
86
+ end
87
+ def hr_data?
88
+ # puts @attributes.keys
89
+ activitySummary.has_key? 'WeightedMeanHeartRate'
90
+ end
91
+ def avg_hr
92
+ hr_data? and self.activitySummary.WeightedMeanHeartRate.value.to_i
93
+ end
94
+ def distance
95
+ activitySummary.SumDistance.value.to_f.round(2)
96
+ end
97
+ def pace_secs
98
+ (activitySummary.WeightedMeanMovingPace.value.to_f * 60).round
99
+ end
100
+ def pace
101
+ Time.at(self.pace_secs).strftime("%M:%S")
102
+ end
103
+ def dur_secs
104
+ activitySummary.SumElapsedDuration.value.to_f.round
105
+ end
106
+ def duration
107
+ Time.at(self.dur_secs).strftime("%M:%S")
108
+ end
109
+ def details
110
+ @details ||= self.class.details(self.activityId)
111
+ end
112
+ def metrics
113
+ return @metrics if @metrics
114
+ metric_data = details.measurements.sort_by{ |hash| hash['metricsIndex'] }.map{ |hash| hash['key'] }
115
+ # puts metric_data.inspect
116
+ @metrics ||= Metric.init_multiple(details.metrics, metric_data)
117
+ end
118
+ def latlong(what = :begin)
119
+ case what
120
+ when :begin
121
+ [self.activitySummary.BeginLatitude.value, self.activitySummary.BeginLongitude.value]
122
+ when :end
123
+ [self.activitySummary.EndLatitude.value, self.activitySummary.EndLongitude.value]
124
+ end
125
+ end
126
+ def method_missing(method, *args)
127
+ if args.size == 1 && method.to_s =~ /(.*)=$/ # ripped from hashie
128
+ return @attributes[$1.to_s] = args.first
129
+ end
130
+ obj = @attributes[method.to_s]
131
+ case obj
132
+ when Base::Hash, Base::Array
133
+ obj
134
+ when Hash, Array
135
+ @attributes[method.to_s] = Base.generate(obj)
136
+ when nil
137
+ super(method, *args)
138
+ else
139
+ obj
140
+ end
141
+ end
142
+ def url
143
+ "http://connect.garmin.com/activity/#{self.activityId}"
144
+ end
145
+ class << self
146
+ def base
147
+ 'http://connect.garmin.com/proxy/activity-service-1.3/'
148
+ end
149
+ def get(id, format = nil)
150
+ Base.request(self.base, format, "/activity/#{validate_id(id)}")['activity']
151
+ end
152
+ def details(id, format = nil)
153
+ h = Base.request(self.base, format, "/activityDetails/#{validate_id(id)}")['com.garmin.activity.details.json.ActivityDetails']
154
+ Base::Hash[h]
155
+ end
156
+ # def course(id, format = nil)
157
+ # h = Base.request(self.base, format, "/course/#{validate_id(id)}")['com.garmin.activity.details.json.ActivityDetails']
158
+ # Base::Hash[h]
159
+ # end
160
+ def validate_id(id)
161
+ id = Integer === id ? id : id.split('/').last
162
+ end
163
+
164
+ def activities(format = nil)
165
+ Base.request(self.base, format, "/activities")
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,129 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ module GarminConnect
4
+ # def setup(p = {})
5
+ # Base.format = p[:format] || :json
6
+ # Base.auth(p)
7
+ # end
8
+ # def auth(p = {})
9
+ # Base.auth(p)
10
+ # end
11
+ # module_function :auth
12
+ # module_function :setup
13
+ class User
14
+ def initialize(username, password = nil)
15
+ # user auth isnt working right now anyways
16
+ @username = username
17
+ end
18
+ def activity_list(limit = 100, start = 1)
19
+ return @activity_list if @activity_list
20
+ uri = URI "http://connect.garmin.com/proxy/activitylist-service/activities/#{@username}?start=#{start}&limit=#{limit}"
21
+ @activity_list = JSON.parse(Net::HTTP.get(uri))['activityList']
22
+ end
23
+ def activity_ids(limit = 100, start = 1)
24
+ self.activity_list(limit, start).map{ |hash| hash['activityId'] }
25
+ end
26
+
27
+ def activities(limit = 100, start = 1)
28
+ return @activities if @activities
29
+ @activities = activity_list(limit, start).map { |a| Activity.new(a['activityId']) }
30
+ end
31
+ def activity(arg)
32
+ Activity.new(arg)
33
+ end
34
+ def most_recent(count = 1)
35
+ count == 1 ? self.activities(1).first : self.activities(count)
36
+ end
37
+ end
38
+
39
+ module Base
40
+ extend GarminConnect
41
+ class << self
42
+ def generate(obj) # this is the only remaining place that the case doesnt work for Hash, Array
43
+ # puts obj.class.inspect
44
+ # puts Hash === obj
45
+ case obj
46
+ when Base::Hash, Base::Array
47
+ obj
48
+ when Hash
49
+ Base::Hash[obj]
50
+ when Array
51
+ Base::Array[obj]
52
+ else
53
+ obj.class.to_s == 'Hash' ? Base::Hash[obj] : Base::Array[obj]
54
+ end
55
+ end
56
+ # def auth(p = {})
57
+ # full = "https://connect.garmin.com/signin?login=login&login:signInButton=Sign%20In&javax.faces.ViewState=j_id1&login:loginUsernameField=#{p[:user]}&login:password=#{p[:pass]}&login:rememberMe=on"
58
+ # url = 'https://connect.garmin.com/signin'
59
+ # self.cookies = (RestClient.get url).cookies
60
+ # if p[:user] && p[:pass]
61
+ # rr = RestClient::Resource.new full
62
+ # r = rr.post("", cookies: self.cookies) do |response, request, result, &block|
63
+ # if [301, 302, 307].include? response.code
64
+ # response.follow_redirection(request, result, &block)
65
+ # self.cookies = response.cookies
66
+ # else
67
+ # response.return!(request, result, &block)
68
+ # end
69
+ # end
70
+ # end
71
+ # end
72
+ def request(base, format = nil, path)
73
+ url = base + (format or self.format).to_s + path
74
+ response = Net::HTTP.get(URI url)
75
+ # response = RestClient.get(url, :cookies => self.cookies) do |response, request, result, &block|
76
+ # if [403].include? response.code
77
+ # puts request.inspect
78
+ # else
79
+ # response.return!(request, result, &block)
80
+ # end
81
+ # end
82
+ JSON.parse(response)
83
+ end
84
+ def cookies
85
+ @@cookies ||= ''
86
+ end
87
+ def cookies=(cookies)
88
+ @@cookies = cookies
89
+ end
90
+ def format
91
+ @@format ||= :json
92
+ end
93
+ def format=(format)
94
+ format = :json unless [:json, :gpx, :tcx].include? format
95
+ @@format = format
96
+ end
97
+ end
98
+ end
99
+ class Base::Hash < Hash
100
+ # garmin data uses 'display' and 'key' as keys. this is why we can't use Hashie as well
101
+ def key
102
+ self.fetch('key') { super }
103
+ end
104
+ def display
105
+ self.fetch('display') { super }
106
+ end
107
+ def method_missing(method, *args)
108
+ if args.size == 1 && method.to_s =~ /(.*)=$/ # ripped from hashie
109
+ return self[$1.to_s] = args.first
110
+ end
111
+ obj = self[method.to_s]
112
+ case obj
113
+ when Base::Hash, Base::Array
114
+ obj
115
+ when Hash, Array
116
+ self[method.to_s] = Base.generate(obj)
117
+ when nil
118
+ super(method, *args)
119
+ else
120
+ obj
121
+ end
122
+ end
123
+ end
124
+ class Base::Array < Array
125
+ def self.[](obj)
126
+ super(*obj.map{ |a| Base.generate(a) })
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,3 @@
1
+ module GarminConnect
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: garmin_connect
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Paul Hoffer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ description: Work with Garmin Connect data easily
28
+ email:
29
+ - paulrhoffer@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/garmin_connect/activity.rb
35
+ - lib/garmin_connect/base.rb
36
+ - lib/garmin_connect/version.rb
37
+ - lib/garmin_connect.rb
38
+ - LICENSE.txt
39
+ - README.md
40
+ - Rakefile
41
+ homepage: http://github.com/phoffer/garmin_connect
42
+ licenses:
43
+ - MIT
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 2.0.14
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: Work with Garmin Connect data easily
65
+ test_files: []