Private
Public Access
1
0

adding splits to C2 workout export

This commit is contained in:
Sander Roosendaal
2019-10-31 11:45:44 +01:00
parent 102efa2cf2
commit d4f311c612

View File

@@ -120,7 +120,7 @@ def c2_open(user):
if (timezone.now()>r.tokenexpirydate): if (timezone.now()>r.tokenexpirydate):
res = rower_c2_token_refresh(user) res = rower_c2_token_refresh(user)
if res == None: if res == None:
raise NoTokenError("User has no token") raise NoTokenError("User has no token")
if res[0] != None: if res[0] != None:
thetoken = res[0] thetoken = res[0]
else: else:
@@ -156,7 +156,7 @@ def get_c2_workouts(rower):
if not isprorower(rower): if not isprorower(rower):
return 0 return 0
try: try:
thetoken = c2_open(rower.user) thetoken = c2_open(rower.user)
except NoTokenError: except NoTokenError:
@@ -181,7 +181,7 @@ def get_c2_workouts(rower):
] ]
knownc2ids = uniqify(knownc2ids+tombstones) knownc2ids = uniqify(knownc2ids+tombstones)
newids = [c2id for c2id in c2ids if not c2id in knownc2ids] newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
for c2id in newids: for c2id in newids:
@@ -267,7 +267,7 @@ def c2wc(weightclass):
# Concept2 logbook sends over split data for each interval # Concept2 logbook sends over split data for each interval
# We use it here to generate a custom summary # We use it here to generate a custom summary
# Some users complained about small differences # Some users complained about small differences
def summaryfromsplitdata(splitdata,data,filename,sep='|'): def summaryfromsplitdata(splitdata,data,filename,sep='|'):
totaldist = data['distance'] totaldist = data['distance']
@@ -310,17 +310,17 @@ def summaryfromsplitdata(splitdata,data,filename,sep='|'):
restvelo = restdistance/resttime restvelo = restdistance/resttime
except (ZeroDivisionError,OverflowError): except (ZeroDivisionError,OverflowError):
restvelo = 0 restvelo = 0
restpower = 2.8*restvelo**(3.0) restpower = 2.8*restvelo**(3.0)
try: try:
avgdps = totaldist/data['stroke_count'] avgdps = totaldist/data['stroke_count']
except (ZeroDivisionError,OverflowError,KeyError): except (ZeroDivisionError,OverflowError,KeyError):
avgdps = 0 avgdps = 0
from rowingdata import summarystring,workstring,interval_string from rowingdata import summarystring,workstring,interval_string
sums = summarystring(totaldist,totaltime,avgpace,spm,avghr,maxhr, sums = summarystring(totaldist,totaltime,avgpace,spm,avghr,maxhr,
avgdps,avgpower,readFile=filename, avgdps,avgpower,readFile=filename,
separator=sep) separator=sep)
@@ -336,16 +336,16 @@ def summaryfromsplitdata(splitdata,data,filename,sep='|'):
sums += '#-{sep}SDist{sep}-Split-{sep}-SPace-{sep}-Pwr-{sep}SPM-{sep}AvgHR{sep}MaxHR{sep}DPS-\n'.format( sums += '#-{sep}SDist{sep}-Split-{sep}-SPace-{sep}-Pwr-{sep}SPM-{sep}AvgHR{sep}MaxHR{sep}DPS-\n'.format(
sep=sep sep=sep
) )
intervalnr=0 intervalnr=0
sa = [] sa = []
results = [] results = []
try: try:
timebased = data['workout_type'] in ['FixedTimeSplits','FixedTimeInterval'] timebased = data['workout_type'] in ['FixedTimeSplits','FixedTimeInterval']
except KeyError: except KeyError:
timebased = False timebased = False
for interval in splitdata: for interval in splitdata:
idist = interval['distance'] idist = interval['distance']
itime = interval['time']/10. itime = interval['time']/10.
@@ -373,7 +373,7 @@ def summaryfromsplitdata(splitdata,data,filename,sep='|'):
if timebased: if timebased:
iarr = [itime,'seconds','work'] iarr = [itime,'seconds','work']
resarr = [idist] resarr = [idist]
if irest_time > 0: if irest_time > 0:
iarr += [irest_time,'seconds','rest'] iarr += [irest_time,'seconds','rest']
try: try:
@@ -390,7 +390,7 @@ def summaryfromsplitdata(splitdata,data,filename,sep='|'):
else: else:
ivelo = 0 ivelo = 0
ipower = 0 ipower = 0
sums += interval_string(intervalnr,idist,itime,ipace,ispm, sums += interval_string(intervalnr,idist,itime,ipace,ispm,
iavghr,imaxhr,0,ipower,separator=sep) iavghr,imaxhr,0,ipower,separator=sep)
intervalnr+=1 intervalnr+=1
@@ -398,14 +398,14 @@ def summaryfromsplitdata(splitdata,data,filename,sep='|'):
return sums,sa,results return sums,sa,results
# Not used now. Could be used to add workout split data to Concept2 # Not used now. Could be used to add workout split data to Concept2
# logbook but needs to be reviewed. # logbook but needs to be reviewed.
def createc2workoutdata_as_splits(w): def createc2workoutdata_as_splits(w):
filename = w.csvfilename filename = w.csvfilename
row = rowingdata(csvfile=filename) row = rowingdata(csvfile=filename)
# resize per minute # resize per minute
df = row.df.groupby(lambda x:x/60).mean() df = row.df.groupby(lambda x:x/60).mean()
averagehr = int(df[' HRCur (bpm)'].mean()) averagehr = int(df[' HRCur (bpm)'].mean())
maxhr = int(df[' HRCur (bpm)'].max()) maxhr = int(df[' HRCur (bpm)'].max())
@@ -443,7 +443,7 @@ def createc2workoutdata_as_splits(w):
wtype = w.workouttype wtype = w.workouttype
if wtype in otwtypes: if wtype in otwtypes:
wtype = 'water' wtype = 'water'
data = { data = {
"type": wtype, "type": wtype,
"date": w.startdatetime.isoformat(), "date": w.startdatetime.isoformat(),
@@ -467,7 +467,7 @@ def createc2workoutdata_as_splits(w):
def createc2workoutdata(w): def createc2workoutdata(w):
filename = w.csvfilename filename = w.csvfilename
try: try:
row = rowingdata(filename) row = rowingdata(csvfile=filename)
except IOError: except IOError:
return 0 return 0
@@ -478,19 +478,45 @@ def createc2workoutdata(w):
averagehr = 0 averagehr = 0
maxhr = 0 maxhr = 0
# Calculate intervalstats
itime, idist, itype = row.intervalstats_values()
lapnames = row.df[' lapIdx'].unique()
nrintervals = len(itime)
if len(lapnames != nrintervals):
newlapnames = []
for name in lapnames:
newlapnames += [name,name]
lapnames = newlapnames
intervaldata = []
for i in range(nrintervals):
if itime[i]>0:
mask = (row.df[' lapIdx'] == lapnames[i]) & (row.df[' WorkoutState'] == itype[i])
spmav = int(row.df[' Cadence (stokes/min)'][mask].mean().astype(int))
hrav = int(row.df[' HRCur (bpm)'][mask].mean().astype(int))
intervaldict = {
'type': 'distance',
'time': int(10*itime[i]),
'distance': int(idist[i]),
'heart_rate': {
'average':hrav,
},
'stroke_rate': spmav,
}
intervaldata.append(intervaldict)
# adding diff, trying to see if this is valid # adding diff, trying to see if this is valid
t = 10*row.df.loc[:,'TimeStamp (sec)'].values-10*row.df.loc[:,'TimeStamp (sec)'].iloc[0] t = 10*row.df.loc[:,'TimeStamp (sec)'].values-10*row.df.loc[:,'TimeStamp (sec)'].iloc[0]
try: try:
t[0] = t[1] t[0] = t[1]
except IndexError: except IndexError:
pass pass
d = 10*row.df.loc[:,' Horizontal (meters)'].values d = 10*row.df.loc[:,' Horizontal (meters)'].values
try: try:
d[0] = d[1] d[0] = d[1]
except IndexError: except IndexError:
pass pass
p = abs(10*row.df.loc[:,' Stroke500mPace (sec/500m)'].values) p = abs(10*row.df.loc[:,' Stroke500mPace (sec/500m)'].values)
p = np.clip(p,0,3600) p = np.clip(p,0,3600)
if w.workouttype == 'bike': if w.workouttype == 'bike':
@@ -516,7 +542,7 @@ def createc2workoutdata(w):
p = p.tolist() p = p.tolist()
spm = spm.tolist() spm = spm.tolist()
hr = hr.tolist() hr = hr.tolist()
for i in range(len(t)): for i in range(len(t)):
thisrecord = {"t":t[i], thisrecord = {"t":t[i],
"d":d[i], "d":d[i],
@@ -547,14 +573,18 @@ def createc2workoutdata(w):
"time": int(10*makeseconds(durationstr)), "time": int(10*makeseconds(durationstr)),
"weight_class": c2wc(w.weightcategory), "weight_class": c2wc(w.weightcategory),
"comments": w.notes, "comments": w.notes,
'stroke_rate': int(row.df[' Cadence (stokes/min)'].mean()),
'drag_factor': int(row.dragfactor),
"heart_rate": { "heart_rate": {
"average": averagehr, "average": averagehr,
"max": maxhr, "max": maxhr,
}, },
"stroke_data": stroke_data, "stroke_data": stroke_data,
'workout': {
'splits': intervaldata,
}
} }
return data return data
# Refresh Concept2 authorization token # Refresh Concept2 authorization token
@@ -570,7 +600,7 @@ def do_refresh_token(refreshtoken):
url = "https://log.concept2.com/oauth/access_token" url = "https://log.concept2.com/oauth/access_token"
s = Session() s = Session()
req = Request('POST',url, data=post_data, headers=headers) req = Request('POST',url, data=post_data, headers=headers)
prepped = req.prepare() prepped = req.prepare()
prepped.body+="&scope=" prepped.body+="&scope="
prepped.body+=scope prepped.body+=scope
@@ -672,7 +702,7 @@ def get_workout(user,c2id):
url = "https://log.concept2.com/api/users/me/results/"+str(c2id) url = "https://log.concept2.com/api/users/me/results/"+str(c2id)
s = requests.get(url,headers=headers) s = requests.get(url,headers=headers)
data = s.json()['data'] data = s.json()['data']
splitdata = None splitdata = None
@@ -694,7 +724,7 @@ def get_workout(user,c2id):
strokedata = pd.DataFrame() strokedata = pd.DataFrame()
else: else:
strokedata = pd.DataFrame() strokedata = pd.DataFrame()
return data,strokedata return data,strokedata
# Get stroke data belonging to C2 ID # Get stroke data belonging to C2 ID
@@ -740,7 +770,7 @@ def get_c2_workout_list(user,page=1):
return s return s
# Get username, having access token. # Get username, having access token.
# Handy for checking if the API access is working # Handy for checking if the API access is working
def get_username(access_token): def get_username(access_token):
@@ -751,7 +781,7 @@ def get_username(access_token):
import urllib import urllib
url = "https://log.concept2.com/api/users/me" url = "https://log.concept2.com/api/users/me"
response = requests.get(url,headers=headers) response = requests.get(url,headers=headers)
me_json = response.json() me_json = response.json()
@@ -776,14 +806,14 @@ def get_userid(access_token):
response = requests.get(url,headers=headers) response = requests.get(url,headers=headers)
except: except:
return 0 return 0
me_json = response.json() me_json = response.json()
try: try:
res = me_json['data']['id'] res = me_json['data']['id']
except KeyError: except KeyError:
res = 0 res = 0
return res return res
# For debugging purposes # For debugging purposes
@@ -799,7 +829,7 @@ def process_callback(request):
return HttpResponse("got a user name: %s" % username) return HttpResponse("got a user name: %s" % username)
def default(o): def default(o):
if isinstance(o, numpy.int64): return int(o) if isinstance(o, numpy.int64): return int(o)
raise TypeError raise TypeError
# Uploading workout # Uploading workout
@@ -810,7 +840,7 @@ def workout_c2_upload(user,w):
return "This workout type cannot be uploaded to Concept2",0 return "This workout type cannot be uploaded to Concept2",0
except KeyError: except KeyError:
return "This workout type cannot be uploaded to Concept2",0 return "This workout type cannot be uploaded to Concept2",0
thetoken = c2_open(user) thetoken = c2_open(user)
r = Rower.objects.get(user=user) r = Rower.objects.get(user=user)
@@ -825,7 +855,7 @@ def workout_c2_upload(user,w):
if data == 0: if data == 0:
return "Error: No data file. Contact info@rowsandall.com if the problem persists",0 return "Error: No data file. Contact info@rowsandall.com if the problem persists",0
authorizationstring = str('Bearer ' + r.c2token) authorizationstring = str('Bearer ' + r.c2token)
headers = {'Authorization': authorizationstring, headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal', 'user-agent': 'sanderroosendaal',
@@ -849,7 +879,7 @@ def workout_c2_upload(user,w):
else: else:
message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text
c2id = 0 c2id = 0
return message,c2id return message,c2id
@@ -882,7 +912,7 @@ def add_workout_from_data(user,importid,data,strokedata,
workouttype = mytypes.c2mappinginv[data['type']] workouttype = mytypes.c2mappinginv[data['type']]
except KeyError: except KeyError:
workouttype = 'rower' workouttype = 'rower'
if workouttype not in [x[0] for x in Workout.workouttypes]: if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'other' workouttype = 'other'
try: try:
@@ -902,14 +932,14 @@ def add_workout_from_data(user,importid,data,strokedata,
rowdatetime = iso8601.parse_date(data['start_date']) rowdatetime = iso8601.parse_date(data['start_date'])
except ParseError: except ParseError:
rowdatetime = iso8601.parse_date(data['date']) rowdatetime = iso8601.parse_date(data['date'])
try: try:
c2intervaltype = data['workout_type'] c2intervaltype = data['workout_type']
except KeyError: except KeyError:
c2intervaltype = '' c2intervaltype = ''
try: try:
title = data['name'] title = data['name']
except KeyError: except KeyError:
@@ -951,7 +981,7 @@ def add_workout_from_data(user,importid,data,strokedata,
spm = strokedata.loc[:,'spm'] spm = strokedata.loc[:,'spm']
except KeyError: except KeyError:
spm = 0*dist2 spm = 0*dist2
try: try:
hr = strokedata.loc[:,'hr'] hr = strokedata.loc[:,'hr']
except KeyError: except KeyError:
@@ -966,7 +996,7 @@ def add_workout_from_data(user,importid,data,strokedata,
velo = 1000./pace velo = 1000./pace
pace = 500./velo pace = 500./velo
# save csv # save csv
# Create data frame with all necessary data to write to csv # Create data frame with all necessary data to write to csv
df = pd.DataFrame({'TimeStamp (sec)':unixtime, df = pd.DataFrame({'TimeStamp (sec)':unixtime,
@@ -988,9 +1018,9 @@ def add_workout_from_data(user,importid,data,strokedata,
' ElapsedTime (sec)':seconds ' ElapsedTime (sec)':seconds
}) })
df.sort_values(by='TimeStamp (sec)',ascending=True) df.sort_values(by='TimeStamp (sec)',ascending=True)
timestr = strftime("%Y%m%d-%H%M%S") timestr = strftime("%Y%m%d-%H%M%S")
@@ -1024,6 +1054,6 @@ def add_workout_from_data(user,importid,data,strokedata,
dosummary=True dosummary=True
) )
return id,message return id,message