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 from rowers.imports import * import numpy import rowers.mytypes as mytypes from rowers.mytypes import otwtypes from rowers.rower_rules import is_workout_user from rowsandall_app.settings import ( UNDERARMOUR_CLIENT_KEY, UNDERARMOUR_CLIENT_SECRET, UNDERARMOUR_REDIRECT_URI, ) oauth_data = { 'client_id': UNDERARMOUR_CLIENT_KEY, 'client_secret': UNDERARMOUR_CLIENT_SECRET, 'redirect_uri': UNDERARMOUR_REDIRECT_URI, 'autorization_uri': "https://www.mapmyfitness.com/v7.1/oauth2/uacf/authorize/", 'content_type': 'application/x-www-form-urlencoded', 'tokenname': 'underarmourtoken', 'refreshtokenname': 'underarmourrefreshtoken', 'expirydatename': 'underarmourtokenexpirydate', 'bearer_auth': True, 'base_url': "https://api.ua.com/v7.1/oauth2/access_token/", 'scope':'write', } # Checks if user has UnderArmour token, renews them if they are expired def underarmour_open(user): return imports_open(user,oauth_data) # Refresh ST token using refresh token def do_refresh_token(refreshtoken,access_token): return imports_do_refresh_token( refreshtoken,oauth_data,access_token=access_token ) # 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 Underarmour def get_underarmour_workout_list(user): r = Rower.objects.get(user=user) if (r.underarmourtoken == '') or (r.underarmourtoken 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.underarmourtoken) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))+"&order_by=-start_datetime" s = requests.get(url,headers=headers) return s # Get workout summary data by Underarmour ID def get_workout(user,underarmourid): r = Rower.objects.get(user=user) if (r.underarmourtoken == '') or (r.underarmourtoken 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.underarmourtoken) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/workout/"+str(underarmourid)+"/?field_set=time_series" s = requests.get(url,headers=headers) data = s.json() strokedata = pd.DataFrame.from_dict({ key: pd.Series(value) for key, value in data.items() }) return data,strokedata # Create Workout Data for upload to Underarmour def createunderarmourworkoutdata(w): filename = w.csvfilename try: row = rowingdata(csvfile=filename) except: return 0 st = w.startdatetime.astimezone(pytz.timezone(w.timezone)) start_time = st.isoformat() averagehr = int(row.df[' HRCur (bpm)'].mean()) minhr = int(row.df[' HRCur (bpm)'].min()) maxhr = int(row.df[' HRCur (bpm)'].max()) averagespm = int(row.df[' Cadence (stokes/min)'].mean()/2.) minspm = int(row.df[' Cadence (stokes/min)'].min()/2.) maxspm = int(row.df[' Cadence (stokes/min)'].max()/2.) 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 name = w.name try: notes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com' except TypeError: notes = 'from '+w.workoutsource+' via rowsandall.com' # adding diff, trying to see if this is valid #t = row.df.loc[:,'TimeStamp (sec)'].values-10*row.df.ix[0,'TimeStamp (sec)'] t = row.df.loc[:,'TimeStamp (sec)'].values #-row.df.ix[0,'TimeStamp (sec)'] # t += arrow.get(st).timestamp # t[0] = t[1] d = row.df.loc[:,'cum_dist'].values d[0] = d[1] t = t.astype(float).tolist() d = d.astype(int).tolist() spm = row.df[' Cadence (stokes/min)'].astype(int).tolist() spm[0] = spm[1] hr = row.df[' HRCur (bpm)'].astype(int).tolist() speed = row.df[' AverageBoatSpeed (m/s)'] speedmin = float(row.df[' AverageBoatSpeed (m/s)'].min()) speedmax = float(row.df[' AverageBoatSpeed (m/s)'].max()) speedmean = float(row.df[' AverageBoatSpeed (m/s)'].mean()) speed = speed.replace(np.inf,0).tolist() haslatlon=1 try: lat = row.df[' latitude'].tolist() lon = row.df[' longitude'].tolist() 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.values,lon.values): point = { 'lat':e[1], 'lng':e[2], 'elevation':0, } locdata.append([e[0],point]) hrdata = [] for e in zip(t,hr): point = [e[0], e[1] ] hrdata.append(point) distancedata = [] for e in zip(t,d): point = [e[0], e[1] ] distancedata.append(point) spmdata = [] for e in zip(t,spm): spmdata.append([e[0],e[1]]) timeseries = { "distance": distancedata, "heartrate": hrdata, "cadence": spmdata, } aggregates = { "elapsed_time_total": int(duration), "active_time_total": int(duration), "distance_total": int(max(d)), "heartrate_avg": averagehr, "heart_rate_min": minhr, "heart_rate_max": maxhr, "speed_min": speedmin, "speed_max": speedmax, "speed_avg": speedmean, "cadence_min": minspm, "cadence_max": maxspm, "cadence_avg": averagespm, } if haslatlon: timeseries["position"] = locdata data = { "start_datetime": start_time, "name": name, "has_time_series": True, "time_series": timeseries, "aggregates": aggregates, "start_locale_timezone": "Etc/UTC", "activity_type": "/v7.1/activity_type/128/", "notes": notes, } return data # Obtain Underarmour Workout ID and activity type def get_idfromuri(user,links): id = links['self'][0]['id'] typeid = links['activity_type'][0]['id'] typename = get_typefromid(typeid,user) return id,typename def getidfromresponse(response): t = response.json() links = t["_links"] id = links["self"][0]["id"] return int(id) def refresh_ua_actlist(user): r = Rower.objects.get(user=user) authorizationstring = str('Bearer ' + r.underarmourtoken) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/activity_type/" response = requests.get(url,headers=headers) me_json = response.json() types = me_json["_embedded"]["activity_types"] w = {int(t["_links"]["self"][0]["id"]):t["name"] for t in types} wdf = pd.Series(w,name='Name') wdf.to_csv('static/rigging/ua2.csv',index_label='id',header=True) return w try: activities = pd.read_csv('static/rigging/ua2.csv',index_col='id') actdict = activities.to_dict()['Name'] except: actdict = {} def get_typefromid(typeid,user): r = Rower.objects.get(user=user) try: res = actdict[int(typeid)] except KeyError: authorizationstring = str('Bearer ' + r.underarmourtoken) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/activity_type/"+str(typeid) response = requests.get(url,headers=headers) me_json = response.json() try: res = me_json['name'] except KeyError: res = 0 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, 'Api-Key': UNDERARMOUR_CLIENT_KEY, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/user/self/" response = requests.get(url,headers=headers) me_json = response.json() try: res = me_json['id'] except KeyError: res = 0 return res def default(o): if isinstance(o, numpy.int64): return int(o) raise TypeError def workout_ua_upload(user,w): message = "Uploading to MapMyFitness" uaid = 0 r = w.user thetoken = underarmour_open(r.user) # ready to upload. Hurray if (is_workout_user(user,w)): data = createunderarmourworkoutdata(w) # return HttpResponse(json.dumps(data)) if not data: message = "Data error" uaid = 0 return message, uaid authorizationstring = str('Bearer ' + thetoken) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, 'user-agent': 'sanderroosendaal', 'Content-Type': 'application/json', } url = "https://api.ua.com/v7.1/workout/" response = requests.post(url,headers=headers,data=json.dumps(data,default=default)) # check for duplicate error first if (response.status_code == 409 ): message = "Duplicate error" w.uploadedtounderarmour = -1 uaid = -1 w.save() elif (response.status_code == 201 or response.status_code==200): uaid = getidfromresponse(response) w.uploadedtounderarmour = uaid w.save() return 'Successfully synchronized with MapMyFitness',uaid else: s = response message = "Something went wrong in workout_underarmour_upload_view: %s - %s" % (s.reason,s.text) uaid = 0 return message, uaid else: message = "You are not authorized to upload this workout" uaid = 0 return message, uaid return message, uaid # Create workout from SportTracks Data, which are slightly different # than Strava or Concept2 data def add_workout_from_data(user,importid,data,strokedata, source='mapmyfitness', workoutsource='mapmyfitness'): workouttype = 'water' try: comments = data['notes'] except: comments = '' try: thetimezone = tz(data['start_locale_timezone']) except: thetimezone = 'UTC' r = Rower.objects.get(user=user) try: rowdatetime = iso8601.parse_date(data['start_datetime']) except iso8601.ParseError: try: rowdatetime = datetime.strptime(data['start_datetime'],"%Y-%m-%d %H:%M:%S") rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) except: try: rowdatetime = parser.parse(data['start_datetime']) 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 try: title = data['name'] except: title = "Imported data" timeseries = data['time_series'] # position, distance, speed, cadence, power, try: res = splituadata(timeseries['distance']) distance = res[1] times_distance = res[0] except KeyError: message = "Error. No distance data" return (0,message) try: l = timeseries['position'] res = splituadata(l) times_location = res[0] latlong = res[1] latcoord = [] loncoord = [] for coord in latlong: lat = coord['lat'] lon = coord['lng'] latcoord.append(lat) loncoord.append(lon) except: times_location = times_distance latcoord = np.zeros(len(times_distance)) loncoord = np.zeros(len(times_distance)) if workouttype in otwtypes: workouttype = 'rower' try: res = splituadata(timeseries['cadence']) times_spm = res[0] spm = res[1] except KeyError: times_spm = times_distance spm = 0*times_distance try: res = splituadata(timeseries['heartrate']) 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) latseries = latseries.groupby(latseries.index).first() lonseries = pd.Series(loncoord,index=times_location) lonseries = lonseries.groupby(lonseries.index).first() spmseries = pd.Series(spm,index=times_spm) spmseries = spmseries.groupby(spmseries.index).first() hrseries = pd.Series(hr,index=times_hr) hrseries = hrseries.groupby(hrseries.index).first() # 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 unixtime[0] = starttimeunix df['TimeStamp (sec)'] = unixtime dt = np.diff(cum_time).mean() wsize = round(5./dt) df = df.fillna(0) df.sort_values(by='TimeStamp (sec)',ascending=True) timestr = strftime("%Y%m%d-%H%M%S") 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='mapmyfitness', title=title, notes=comments) return (id,message)