from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals from __future__ import unicode_literals, absolute_import # All the functionality needed to connect to Runkeeper from rowers.imports import * import re from rowsandall_app.settings import ( C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, RUNKEEPER_CLIENT_ID, RUNKEEPER_CLIENT_SECRET,RUNKEEPER_REDIRECT_URI, ) oauth_data = { 'client_id': RUNKEEPER_CLIENT_ID, 'client_secret': RUNKEEPER_CLIENT_SECRET, 'redirect_uri': RUNKEEPER_REDIRECT_URI, 'autorization_uri': "https://www.runkeeper.com/apps/authorize", 'content_type': 'application/x-www-form-urlencoded', 'tokenname': 'runkeepertoken', 'refreshtokenname': None, 'expirydatename': None, 'bearer_auth': True, 'base_url': "https://runkeeper.com/apps/token", 'headers': {'user-agent': 'sanderroosendaal'}, 'scope':'write', } def splitrunkeeperlatlongdata(lijst,tname,latname,lonname): t = [] lat = [] lon = [] for d in lijst: t.append(d[tname]) lat.append(d[latname]) lon.append(d[lonname]) return [np.array(t),np.array(lat),np.array(lon)] def splitrunkeeperdata(lijst,xname,yname): x = [] y = [] for d in lijst: x.append(d[xname]) y.append(d[yname]) return [np.array(x),np.array(y)] # Checks if user has SportTracks token, renews them if they are expired def runkeeper_open(user): return imports_open(user,oauth_data) # Exchange access code for long-lived access token def get_token(code): return imports_get_token(code,oauth_data) # Make authorization URL including random string def make_authorization_url(request): return imports_make_authorization_url(oauth_data) # Get list of workouts available on Runkeeper def get_runkeeper_workout_list(user): r = Rower.objects.get(user=user) if (r.runkeepertoken == '') or (r.runkeepertoken is None): s = "Token doesn't exist. Need to authorize" return custom_exception_handler(401,s) else: # ready to fetch. Hurray authorizationstring = str('Bearer ' + r.runkeepertoken) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} url = "https://api.runkeeper.com/fitnessActivities" s = requests.get(url,headers=headers) return s # Get workout summary data by Runkeeper ID def get_workout(user,runkeeperid): r = Rower.objects.get(user=user) if (r.runkeepertoken == '') or (r.runkeepertoken is None): return custom_exception_handler(401,s) s = "Token doesn't exist. Need to authorize" else: # ready to fetch. Hurray authorizationstring = str('Bearer ' + r.runkeepertoken) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} url = "https://api.runkeeper.com/fitnessActivities/"+str(runkeeperid) s = requests.get(url,headers=headers) try: data = s.json() except ValueError: data = {} strokedata = pd.DataFrame.from_dict({ key: pd.Series(value) for key, value in data.items() }) return data,strokedata # Create Workout Data for upload to SportTracks def createrunkeeperworkoutdata(w): filename = w.csvfilename try: row = rowingdata(filename) except: return 0 averagehr = int(row.df[' HRCur (bpm)'].mean()) maxhr = int(row.df[' HRCur (bpm)'].max()) duration = w.duration.hour*3600 duration += w.duration.minute*60 duration += w.duration.second duration += +1.0e-6*w.duration.microsecond # adding diff, trying to see if this is valid #t = row.df.ix[:,'TimeStamp (sec)'].values-10*row.df.ix[0,'TimeStamp (sec)'] t = row.df.loc[:,'TimeStamp (sec)'].values-row.df.loc[:,'TimeStamp (sec)'].iloc[0] t[0] = t[1] d = row.df.loc[:,'cum_dist'].values d[0] = d[1] t = t.astype(int) d = d.astype(int) spm = row.df[' Cadence (stokes/min)'].astype(int) spm[0] = spm[1] hr = row.df[' HRCur (bpm)'].astype(int) haslatlon=1 try: lat = row.df[' latitude'].values lon = row.df[' longitude'].values if not lat.std() and not lon.std(): haslatlon = 0 except KeyError: haslatlon = 0 # path data if haslatlon: locdata = [] for e in zip(t,lat,lon): point = {'timestamp':e[0], 'latitude':e[1], 'longitude':e[2], 'altitude':0, "type":"gps"} locdata.append(point) hrdata = [] for e in zip(t,hr): point = {'timestamp':e[0], 'heart_rate':e[1] } hrdata.append(point) distancedata = [] for e in zip(t,d): point = {'timestamp':e[0], 'distance':e[1] } distancedata.append(point) st = w.startdatetime.astimezone(pytz.timezone(w.timezone)) start_time = st.strftime("%a, %d %b %Y %H:%M:%S") try: newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com' except TypeError: newnotes = 'from '+w.workoutsource+' via rowsandall.com' if haslatlon: data = { "type": "Rowing", "start_time": start_time, "total_distance": int(w.distance), "duration": duration, "notes": newnotes, "average_heart_rate": averagehr, "path": locdata, "distance": distancedata, "heart_rate": hrdata, "post_to_twitter":"false", "post_to_facebook":"false", } else: data = { "type": "Rowing", "start_time": start_time, "total_distance": int(w.distance), "duration": duration, "notes": newnotes, "avg_heartrate": averagehr, "distance": distancedata, "heart_rate": hrdata, "post_to_twitter":"false", "post_to_facebook":"false", } return data # Obtain Runkeeper Workout ID from the response returned on successful # upload def getidfromresponse(response): uri = response.headers["Location"] tester = re.compile('^\/fitnessActivities\/(\d+)$') id = int(tester.match(uri).group(1)) return int(id) def geturifromid(access_token,id): authorizationstring = str('Bearer ' + access_token) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} import urllib url = "https://api.runkeeper.com/fitnessActivities/"+str(id) response = requests.get(url,headers=headers) try: me_json = response.json() except: return '' try: res = me_json['uri'] except KeyError: res = '' return res # Get user id, having access token # Handy for checking if the API access is working def get_userid(access_token): authorizationstring = str('Bearer ' + access_token) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} import urllib url = "https://api.runkeeper.com/user" response = requests.get(url,headers=headers) try: me_json = response.json() except: return '' try: res = me_json['userID'] except KeyError: res = '' return str(res) def workout_runkeeper_upload(user,w): message = "Uploading to Runkeeper" rkid = 0 r = w.user thetoken = runkeeper_open(r.user) # ready to upload. Hurray if (checkworkoutuser(user,w)): data = createrunkeeperworkoutdata(w) if not data: message = "Data error in Runkeeper Upload" rkid = 0 return message, rkid authorizationstring = str('Bearer ' + thetoken) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json', 'Content-Length':'nnn'} url = "https://api.runkeeper.com/fitnessActivities" response = requests.post(url,headers=headers,data=json.dumps(data)) # check for duplicate error first if (response.status_code == 409 ): message = "Duplicate error" w.uploadedtorunkeeper = -1 rkid = -1 w.save() return message, rkid elif (response.status_code == 201 or response.status_code==200): rkid = getidfromresponse(response) rkuri = geturifromid(thetoken,rkid) w.uploadedtorunkeeper = rkid w.save() return 'Successfully synchronized to Runkeeper',rkid else: s = response message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text) rkid = 0 return message, rkid else: message = "You are not authorized to upload this workout" rkid = 0 return message, rkid return message,rkid # Create workout from RunKeeper Data def add_workout_from_data(user,importid,data,strokedata,source='runkeeper', workoutsource='runkeeper'): # To Do - add utcoffset to time workouttype = data['type'] if workouttype not in [x[0] for x in Workout.workouttypes]: workouttype = 'other' try: comments = data['notes'] except: comments = '' try: utcoffset = tz(data['utcoffset']) except: utcoffset = 0 r = Rower.objects.get(user=user) try: rowdatetime = iso8601.parse_date(data['start_time']) except iso8601.ParseError: try: rowdatetime = datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S") rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) except ValueError: try: rowdatetime = parser.parse(data['start_time']) #rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) except: rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) starttimeunix = arrow.get(rowdatetime).timestamp #starttimeunix = mktime(rowdatetime.utctimetuple()) starttimeunix += utcoffset*3600 try: title = data['name'] except: title = "Imported data" res = splitrunkeeperdata(data['distance'],'timestamp','distance') distance = res[1] times_distance = res[0] try: l = data['path'] res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude') times_location = res[0] latcoord = res[1] loncoord = res[2] except: times_location = times_distance latcoord = np.zeros(len(times_distance)) loncoord = np.zeros(len(times_distance)) if workouttype in types.otwtypes: workouttype = 'rower' try: res = splitrunkeeperdata(data['cadence'],'timestamp','cadence') times_spm = res[0] spm = res[1] except KeyError: times_spm = times_distance spm = 0*times_distance try: res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate') hr = res[1] times_hr = res[0] except KeyError: times_hr = times_distance hr = 0*times_distance # create data series and remove duplicates distseries = pd.Series(distance,index=times_distance) distseries = distseries.groupby(distseries.index).first() latseries = pd.Series(latcoord,index=times_location) try: latseries = latseries.groupby(latseries.index).first() except TypeError: latseries = 0.0*distseries lonseries = pd.Series(loncoord,index=times_location) try: lonseries = lonseries.groupby(lonseries.index).first() except TypeError: lonseries = 0.0*distseries spmseries = pd.Series(spm,index=times_spm) spmseries = spmseries.groupby(spmseries.index).first() hrseries = pd.Series(hr,index=times_hr) try: hrseries = hrseries.groupby(hrseries.index).first() except TypeError: hrseries = 0*distseries # Create dicts and big dataframe d = { ' Horizontal (meters)': distseries, ' latitude': latseries, ' longitude': lonseries, ' Cadence (stokes/min)': spmseries, ' HRCur (bpm)' : hrseries, } df = pd.DataFrame(d) df = df.groupby(level=0).last() cum_time = df.index.values df[' ElapsedTime (sec)'] = cum_time velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff() df[' Power (watts)'] = 0.0*velo nr_rows = len(velo.values) df[' DriveLength (meters)'] = np.zeros(nr_rows) df[' StrokeDistance (meters)'] = np.zeros(nr_rows) df[' DriveTime (ms)'] = np.zeros(nr_rows) df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows) df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows) df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows) df[' lapIdx'] = np.zeros(nr_rows) unixtime = cum_time+starttimeunix try: unixtime[0] = starttimeunix except IndexError: return (0,'No data to import') df['TimeStamp (sec)'] = unixtime dt = np.diff(cum_time).mean() wsize = round(5./dt) # velo2 = stravastuff.ewmovingaverage(velo,wsize) # df[' Stroke500mPace (sec/500m)'] = 500./velo2 df = df.fillna(0) df.sort_values(by='TimeStamp (sec)',ascending=True) timestr = strftime("%Y%m%d-%H%M%S") # csvfilename ='media/Import_'+str(importid)+'.csv' csvfilename ='media/{code}_{importid}.csv'.format( importid=importid, code = uuid4().hex[:16] ) res = df.to_csv(csvfilename+'.gz',index_label='index', compression='gzip') id,message = dataprep.save_workout_database(csvfilename,r, workouttype=workouttype, workoutsource='runkeeper', title=title, notes=comments) return (id,message)