A program to read a Phidget IR sensor and log pull-ups with Fitbit's API
at master 119 lines 3.4 kB view raw
1require "oauth" 2require "json" 3 4class Fitbit < Loggerish 5 def self.args 6 [ 7 [ "--fitbit", "-F", GetoptLong::NO_ARGUMENT, 8 "log to a Fitbit account (will walk through setup)" ], 9 ] 10 end 11 12 def after_initialize 13 if @enabled = !!@parent.config["fitbit"] 14 @parent.vputs "enabling Fitbit logging module" 15 16 verify_keys 17 end 18 end 19 20 def log_pullup!(time) 21 # TODO: update this to log to the user's custom tracker instead of an 22 # activity, because activities don't allow custom units and logging pullups 23 # in miles doesn't make any sense 24 json = self.oauth_request("/1/user/-/activities.json", :post, { 25 "activityName" => "Pullup", 26 "manualCalories" => 1, 27 "startTime" => time.strftime("%H:%M"), 28 "durationMillis" => 1000, 29 "date" => time.strftime("%Y-%m-%d"), 30 }) 31 32 begin 33 h = JSON.parse(json) 34 if (id = h["activityLog"]["activityId"].to_i) != 0 35 @parent.vputs "logged pullup on fitbit (id #{id})" 36 else 37 raise "no activity id" 38 end 39 40 rescue => e 41 @parent.eputs "error from fitbit (#{e.message}): " << json.inspect 42 end 43 end 44 45 def oauth_consumer 46 OAuth::Consumer.new(@parent.config["fitbit_oauth_key"], 47 @parent.config["fitbit_oauth_secret"], 48 { :site => "http://api.fitbit.com", :http_method => :get }) 49 end 50 51 def oauth_request(req, method = :get, post_data = nil) 52 begin 53 Timeout.timeout(20) do 54 at = OAuth::AccessToken.new(oauth_consumer, 55 @parent.config["fitbit_token"], @parent.config["fitbit_secret"]) 56 57 if method == :get 58 res = at.get(req, { "Accept-Language" => "en_US" }) 59 elsif method == :post 60 res = at.post(req, post_data, { "Accept-Language" => "en_US" }) 61 else 62 raise "what kind of method is #{method}?" 63 end 64 65 if res.class.superclass != Net::HTTPSuccess 66 raise res.class.to_s 67 end 68 69 return res.body 70 end 71 rescue Timeout::Error => e 72 @parent.eputs "timed out talking to Fitbit: #{e.message}" 73 rescue StandardError => e 74 @parent.eputs "error talking to Fitbit: #{e.message}" 75 end 76 end 77 78 def verify_keys 79 while @parent.config["fitbit_oauth_key"].to_s == "" 80 puts "No Fitbit OAuth key found. Register an application at", 81 "https://dev.fitbit.com/apps/new with PIN authentication and enter ", 82 "the consumer key and secret here.", 83 "" 84 85 print "OAuth consumer key: " 86 @parent.config["fitbit_oauth_key"] = STDIN.gets.strip 87 print "OAuth consumer secret: " 88 @parent.config["fitbit_oauth_secret"] = STDIN.gets.strip 89 90 # this will be invalid now anyway 91 @parent.config["fitbit_token"] = "" 92 93 puts "" 94 end 95 96 while @parent.config["fitbit_token"].to_s == "" 97 request_token = oauth_consumer.get_request_token 98 99 puts "No Fitbit token found. Authorize your Fitbit account at ", 100 request_token.authorize_url, 101 "" 102 103 print "Enter the PIN received: " 104 pin = STDIN.gets.strip 105 106 access_token = request_token.get_access_token(:oauth_verifier => pin) 107 if !access_token 108 raise "couldn't get access token from pin" 109 end 110 111 @parent.config["fitbit_token"] = access_token.token 112 @parent.config["fitbit_secret"] = access_token.secret 113 114 @parent.config.save! 115 116 puts "" 117 end 118 end 119end