├── README.md ├── .gitignore ├── settings.py.readme ├── beeminderpy.py ├── fitbit2beeminder.py └── fitbit_api.py /README.md: -------------------------------------------------------------------------------- 1 | beeminderpy 2 | =========== 3 | 4 | python wrapper for beeminder api -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | 3 | # Packages 4 | *.egg 5 | *.egg-info 6 | dist 7 | build 8 | eggs 9 | parts 10 | bin 11 | var 12 | sdist 13 | develop-eggs 14 | .installed.cfg 15 | 16 | # Installer logs 17 | pip-log.txt 18 | 19 | # Unit test / coverage reports 20 | .coverage 21 | .tox 22 | 23 | #Translations 24 | *.mo 25 | 26 | #Mr Developer 27 | .mr.developer.cfg 28 | -------------------------------------------------------------------------------- /settings.py.readme: -------------------------------------------------------------------------------- 1 | #for beeminder values looks here for help : 2 | # https://www.beeminder.com/api 3 | BEEMINDER_USERNAME='username' 4 | BEEMINDER_AUTH_TOKEN='token' 5 | 6 | 7 | #for fitbit value, look here for help : 8 | # https://groups.google.com/forum/?fromgroups=#!topic/fitbit-api/CkXQ6-0-vMs 9 | FITBIT_BASE_URL='api.fitbit.com' 10 | FITBIT_CONSUMER_KEY='consumer key' 11 | FITBIT_CONSUMER_SECRET='consumer secret' 12 | FITBIT_ACCESS_TOKEN_FSP='full path to local file' 13 | FITBIT_REQUEST_TOKEN_URL='http://%s/oauth/request_token' % FITBIT_BASE_URL 14 | FITBIT_AUTH_URL='http://%s/oauth/access_token' % FITBIT_BASE_URL 15 | FITBIT_ACCESS_TOKEN_URL='http://%s/oauth/authorize' % FITBIT_BASE_URL 16 | FITBIT_REALM=FITBIT_BASE_URL 17 | -------------------------------------------------------------------------------- /beeminderpy.py: -------------------------------------------------------------------------------- 1 | import urllib 2 | import urllib2 3 | import settings 4 | 5 | # based on https://www.beeminder.com/api 6 | 7 | class Beeminder: 8 | def __init__(self, this_auth_token): 9 | self.auth_token=this_auth_token 10 | self.base_url='https://www.beeminder.com/api/v1' 11 | 12 | def get_user(self,username): 13 | url = "%s/users/%s.json" % (self.base_url,username) 14 | values = {'auth_token':self.auth_token} 15 | result = self.call_api(url,values,'GET') 16 | return result 17 | 18 | def get_goal(self,username,goalname): 19 | url = "%s/users/%s/goals/%s.json" % (self.base_url,username,goalname) 20 | values = {'auth_token':self.auth_token} 21 | result = self.call_api(url,values,'GET') 22 | return result 23 | 24 | def get_datapoints(self,username,goalname): 25 | url = self.base_url+'users/'+username+'/goals/'+goalname+'/datapoints.json' 26 | url = "%s/users/%s/goals/%s/datapoints.json" % (self.base_url,username,goalname) 27 | values = {'auth_token':self.auth_token} 28 | result = self.call_api(url,values,'GET') 29 | return result 30 | 31 | def create_datapoint(self,username,goalname,timestamp,value,comment=' ',sendmail='false'): 32 | url = self.base_url+'users/'+username+'/goals/'+goalname+'/datapoints.json' 33 | url = "%s/users/%s/goals/%s/datapoints.json" % (self.base_url,username,goalname) 34 | values = {'auth_token':self.auth_token, 'timestamp':timestamp, 'value':value, 'comment':comment, 'sendmail':sendmail} 35 | result = self.call_api(url,values,'POST') 36 | return result 37 | 38 | def call_api(self,url,values,method='GET'): 39 | result='' 40 | data = urllib.urlencode(values) 41 | if method=='POST': 42 | req = urllib2.Request(url,data) 43 | response = urllib2.urlopen(req) 44 | else: 45 | response = urllib2.urlopen(url+'?'+data) 46 | result=response.read() 47 | return result 48 | -------------------------------------------------------------------------------- /fitbit2beeminder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import settings 3 | import beeminderpy 4 | import fitbit_api 5 | import json 6 | import datetime 7 | import time 8 | import sys 9 | 10 | """ 11 | Get a fitbit value for a day, and post it as beeminder datapoint 12 | """ 13 | 14 | 15 | def main(): 16 | fitbit_api_conn=fitbit_api.oauth_connect( server=settings.FITBIT_BASE_URL, 17 | consumer_key =settings.FITBIT_CONSUMER_KEY, 18 | consumer_secret =settings.FITBIT_CONSUMER_SECRET, 19 | access_token_fsp =settings.FITBIT_ACCESS_TOKEN_FSP, 20 | request_token_url =settings.FITBIT_REQUEST_TOKEN_URL, 21 | auth_url =settings.FITBIT_AUTH_URL, 22 | access_token_url =settings.FITBIT_ACCESS_TOKEN_URL, 23 | realm =settings.FITBIT_REALM) 24 | 25 | beeapi=beeminderpy.Beeminder(settings.BEEMINDER_AUTH_TOKEN) 26 | 27 | #deal with the date 28 | #either privide a specific date 'yyyymmdd' or a delta '-2' 29 | tdate='-6' 30 | if len(sys.argv) >1 : 31 | tdate=sys.argv[1] 32 | yyyymmdd="2012-11-05" 33 | try: 34 | yyyymmdd=datetime.datetime.strptime(tdate, "%Y-%m-%d") 35 | except ValueError: 36 | try: 37 | yyyymmdd=(datetime.date.today()-datetime.timedelta(abs(int(tdate)))) 38 | except: 39 | print "bad date" 40 | exit(-1) 41 | 42 | fitbit_api_call = '/1/user/-/activities/steps/date/'+yyyymmdd.strftime("%Y-%m-%d")+'/1d.json' 43 | 44 | data=json.loads(fitbit_api_conn.request(fitbit_api_call)) 45 | print data 46 | 47 | value=data['activities-steps'][0]['value'] 48 | print value 49 | 50 | timestamp=int(time.mktime(time.strptime(data['activities-steps'][0]['dateTime'], '%Y-%m-%d'))) 51 | print timestamp 52 | 53 | 54 | beeapi.create_datapoint(settings.BEEMINDER_USERNAME,'fitbit',timestamp,value,'via API','true') 55 | 56 | if __name__ == '__main__': 57 | main() 58 | 59 | -------------------------------------------------------------------------------- /fitbit_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | 5 | This was taken from https://groups.google.com/forum/?fromgroups=#!topic/fitbit-api/CkXQ6-0-vMs 6 | 7 | Description: 8 | Using the FitBit API get: http://api.fitbit.com/1/user/-/activities/date/2011-04-17.xml 9 | 10 | Displays: 11 | 441894total0.11tracker0.11loggedActivities0veryActive0moderatelyActive0.03lightlyActive0.08sedentaryActive072014132600 12 | 13 | Reference: 14 | http://wiki.fitbit.com/display/API/Fitbit+API 15 | http://wiki.fitbit.com/display/API/API-Get-Activities 16 | http://wiki.fitbit.com/display/API/OAuth-Authentication-API#OAuth-Authentication-API-TheOAuthFlow 17 | http://oauth.net/core/1.0a/ 18 | 19 | Notes: 20 | FitBit API rejects oauth.OAuthSignatureMethod_HMAC_SHA1() 21 | generated signatures so use oauth.OAuthSignatureMethod_PLAINTEXT() 22 | instead. 23 | ''' 24 | 25 | import os, httplib, json, urllib, sys 26 | 27 | # Install oauth for python. On Ubuntu run: sudo apt-get install python-oauth 28 | from oauth import oauth 29 | DEBUG = True 30 | 31 | class oauth_connect: 32 | def __init__(self, server, consumer_key, consumer_secret, access_token_fsp, request_token_url, auth_url, access_token_url, realm): 33 | self.connection = httplib.HTTPSConnection(server) 34 | self.consumer = oauth.OAuthConsumer(consumer_key, consumer_secret) 35 | self.signature_method = oauth.OAuthSignatureMethod_PLAINTEXT() 36 | self.access_token_fsp = access_token_fsp 37 | self.request_token_url = request_token_url 38 | self.auth_url = auth_url 39 | self.access_token_url = access_token_url 40 | self.realm = realm 41 | self.access_token = self.get_access_token() 42 | 43 | def fetch_response(oauth_request, debug=DEBUG): 44 | url= oauth_request.to_url() 45 | self.connection.request(oauth_request.http_method,url) 46 | response = self.connection.getresponse() 47 | s=response.read() 48 | if debug: 49 | print 'requested URL: %s' % url 50 | print 'server response: %s' % s 51 | return s 52 | 53 | def request(self,api_call): 54 | print '* Access a protected resource ...' 55 | print api_call 56 | oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=self.access_token, http_url=api_call) 57 | oauth_request.sign_request(self.signature_method, self.consumer, self.access_token) 58 | headers = oauth_request.to_header(self.realm) 59 | self.connection.request('GET', api_call, headers=headers) 60 | resp = self.connection.getresponse() 61 | return resp.read() 62 | 63 | def get_access_token(self): 64 | # if we don't have a cached access-token stored in a file, then get one 65 | if not os.path.exists(self.access_token_fsp): 66 | print '* Obtain a request token ...' 67 | oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url=self.request_token_url) 68 | if DEBUG: 69 | self.connection.set_debuglevel(10) 70 | oauth_request.sign_request(self.signature_method, self.consumer, None) 71 | resp=fetch_response(oauth_request, self.connection) 72 | auth_token=oauth.OAuthToken.from_string(resp) 73 | print 'Auth key: %s' % str(auth_token.key) 74 | print 'Auth secret: %s' % str(auth_token.secret) 75 | print '-'*75,'\n\n' 76 | 77 | # authorize the request token 78 | print '* Authorize the request token ...' 79 | auth_url="%s?oauth_token=%s" % (self.auth_url, auth_token.key) 80 | print 'Authorization URL:\n%s' % auth_url 81 | oauth_verifier = raw_input( 'Please go to the above URL and authorize the app -- Type in the Verification code from the website, when done: ') 82 | print '* Obtain an access token ...' 83 | # note that the token we're passing to the new 84 | # OAuthRequest is our current request token 85 | oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=auth_token, http_url=self.access_token_utl, parameters={'oauth_verifier': oauth_verifier}) 86 | oauth_request.sign_request(self.signature_method, self.consumer, auth_token) 87 | 88 | # now the token we get back is an access token 89 | # parse the response into an OAuthToken object 90 | access_token=oauth.OAuthToken.from_string( fetch_response(oauth_request,self.connection)) 91 | print 'Access key: %s' % str(access_token.key) 92 | print 'Access secret: %s' % str(access_token.secret) 93 | print '-'*75,'\n\n' 94 | 95 | # write the access token to file; next time we just read it from file 96 | if DEBUG: 97 | print 'Writing file', self.access_token_fsp 98 | fobj = open(access_token_fsp, 'w') 99 | access_token_string = access_token.to_string() 100 | fobj.write(access_token_string) 101 | fobj.close() 102 | else: 103 | if DEBUG: 104 | print 'Reading file', self.access_token_fsp 105 | fobj = open(self.access_token_fsp) 106 | access_token_string = fobj.read() 107 | fobj.close() 108 | return oauth.OAuthToken.from_string(access_token_string) 109 | 110 | 111 | def main(): 112 | SERVER='api.fitbit.com' 113 | myoauth=oauth_connect( server =SERVER, 114 | consumer_key ='', 115 | consumer_secret ='', 116 | access_token_fsp ='access_token.string', 117 | request_token_url ='https://%s/oauth/request_token' % SERVER, 118 | auth_url ='https://%s/oauth/access_token' % SERVER, 119 | access_token_url ='https://%s/oauth/authorize' % SERVER, 120 | realm =SERVER) 121 | 122 | if len(sys.argv)>1: 123 | apiCall = '/1/user/-/activities/steps/date/'+sys.argv[1]+'.json' 124 | else: 125 | apiCall = '/1/user/-/activities/steps/date/today/1d.json' 126 | #apiCall = '/1/user/-/devices.xml' 127 | #apiCall='/1/user/-/profile.xml' 128 | #apiCall='/1/user/-/activities/recent.xml' 129 | 130 | # For other FitBit API calls: 131 | # http://wiki.fitbit.com/display/API/Resource-Access-API 132 | # http://wiki.fitbit.com/display/API/API-Get-Activities 133 | 134 | # access protected resource 135 | data=json.loads(myoauth.request(apiCall)) 136 | print data 137 | 138 | if __name__ == '__main__': 139 | main() 140 | --------------------------------------------------------------------------------