Class: Fatigue::Garmin

Inherits:
Object
  • Object
show all
Defined in:
lib/fatigue/garmin.rb

Overview

GARMIN A class used to access Garmin Connect.

Instance Method Summary collapse

Constructor Details

#initialize(username, password) ⇒ Garmin

Public: Create a new Garmin instance.

username - The String of the Garmin Connect username. password - The String of the Garmin Connect password.

Returns a new Fatigue::Garmin instance.



13
14
15
16
# File 'lib/fatigue/garmin.rb', line 13

def initialize(username, password)
  @username = username
  @password = password
end

Instance Method Details

#get_formatsObject

Public: gets the number, time and date formats from the settings page

IF the user has different settings from the default, the form may return errors when trying to post runs



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/fatigue/garmin.rb', line 47

def get_formats
  page = @agent.get('http://connect.garmin.com/settings')
  html = Nokogiri::HTML(page.body)
  scr = html.css("script").select { |s| s.text =~ /(DATE_FORMAT)/ }.first.text

  date_value   = scr.match(/DATE_FORMAT = '(.+)'/)[1]
  time_value   = scr.match(/TIME_FORMAT = '(.+)'/)[1]
  number_value = scr.match(/NUMBER_FORMAT = '(.+)'/)[1]
  
  @date_format    = date_value.gsub('yyyy', '%Y').gsub('dd', '%d').gsub('MM', '%m')
  @time_format    = (time_value == 'twenty_four' ? '%H:%M' : '%I:%M %p' )
  @decimal_format = (number_value == 'decimal_comma' ? ',' : '.')
end

#loginObject

Public: logs the instance into Garmin Connect.

Returns true if successful login, false if unsuccessful.



21
22
23
24
25
26
27
28
29
# File 'lib/fatigue/garmin.rb', line 21

def 
  @agent = Mechanize.new
   = @agent.get('https://connect.garmin.com/signin')
  form = .form('login')
  form['login:loginUsernameField'] = @username
  form['login:password'] = @password
  page = @agent.submit(form, form.buttons.first)
  page.inspect =~ /Dashboard for/ ? true : false
end

#logoutObject

Public: logs the instance out of Garmin Connect.

This is pretty important since Garmin hates multi-logins. Apparently?

Returns true if successful logout, false if unsuccessful.



36
37
38
39
40
# File 'lib/fatigue/garmin.rb', line 36

def logout
  page = @agent.get('http://connect.garmin.com/dashboard')
  page.link_with(:text => 'Sign Out').click
  page.inspect =~ /aren't signed in/ ? true : false
end

#post_run(run) ⇒ Object

Public: posts a new Run to your logged-in Garmin account.

run - A Fatigue::Run instance.

Returns true if success, false if failure. Requires #login to be called prior to execution.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/fatigue/garmin.rb', line 67

def post_run(run)
  begin
    manual_run = @agent.get('http://connect.garmin.com/activity/manual')
    form = manual_run.form('manualActivityForm')
    form.activityBeginDate = run.started_at.strftime(@date_format)
    form.activityBeginTime = run.started_at.strftime(@time_format)
    form.field_with(:name => 'activityTimeZoneDecoration:activityTimeZone').
      options.select { |option|
        # select option where our timezones are equal (-07:00, etc)
        zone = run.started_at.getlocal.strftime('%z').gsub('+','\+').gsub('0000', '\(GMT\)')
        option.text.gsub(':','') =~ /#{zone}/
      }.first.select
    form['activityNameDecoration:activityName'] = run.formatted_name
    form.field_with(:name => 'activityTypeDecoration:activityType').
      options.select { |option| option.value == 'running' }.
      first.select
    form['speedPaceContainer:activitySummarySumDuration'] = run.hours
    form['speedPaceContainer:activitySummarySumDurationMinute'] = run.minutes
    form['speedPaceContainer:activitySummarySumDurationSecond'] = run.seconds
    form['speedPaceContainer:activitySummarySumDistanceDecoration:activitySummarySumDistance'] = run.distance.to_s.gsub('.', @decimal_format)
    form.field_with(:name => 'speedPaceContainer:activitySummarySumDistanceDecoration:distanceUnit').
      options.select { |option| option.text == run.unit }.first.select
    form['descriptionDecoration:description'] = run.description
    form['calories'] = run.calories
    form['AJAXREQUEST'] = '_viewRoot'
    form['saveButton'] = 'saveButton'
  
    resp = @agent.submit(form, form.buttons_with(:name => 'saveButton').first)
    verify_response(resp.body)
  rescue NoMethodError => e
    puts "Darn!\nGarmin logged us out while attempting to post a run on #{run.started_at.strftime(@date_format)}. Logging back in!"
    if 
      post_run(run)
    else
      puts "Couldn't log back in. Aborting."
      exit
    end
  end
end

#post_runs(runs) ⇒ Object

Public: Posts a collection of Runs to your logged-in Garmin account.

runs - An Array of Fatigue::Run instances.

Returns the number of runs successfully posted to the Garmin account. Requires #login to be called prior to execution.



113
114
115
116
117
118
119
120
121
122
# File 'lib/fatigue/garmin.rb', line 113

def post_runs(runs)
  get_formats 
  progress = ProgressBar.new("  status", runs.size)
  runs.each do |run|
    post_run(run)
    progress.inc
  end
  progress.finish
  runs.size
end

#verify_response(html_body) ⇒ Object

Verifies whether the response returned is successful or not. For some reason Garmin isn’t spitting out a redirect to the newly-created run, so instead we hackishly check if an error <span> is filled.

Returns a Boolean value for whether the response was successful or not.



132
133
134
135
# File 'lib/fatigue/garmin.rb', line 132

def verify_response(html_body)
  html = Nokogiri::HTML(html_body)
  html.css('#ErrorContainer').text.strip == ''
end