Private
Public Access
1
0

runkeeper functionality complete (not fully tested)

This commit is contained in:
Sander Roosendaal
2017-03-23 20:07:10 +01:00
parent d89219a2df
commit 08c0838d85
4 changed files with 375 additions and 40 deletions

View File

@@ -1,4 +1,5 @@
import time
import timestring
import zipfile
import operator
import warnings
@@ -46,6 +47,8 @@ import datetime
import iso8601
import c2stuff
from c2stuff import C2NoTokenError
from runkeeperstuff import RunKeeperNoTokenError
from sporttracksstuff import SportTracksNoTokenError
from iso8601 import ParseError
import stravastuff
import sporttracksstuff
@@ -189,8 +192,28 @@ def get_time(second):
# get the workout ID from the SportTracks URI
def getidfromsturi(uri):
return uri[len(uri)-8:]
def getidfromsturi(uri,length=8):
return uri[len(uri)-length:]
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)]
# Splits SportTracks data which is one long sequence of
# [t,[lat,lon],t2,[lat2,lon2] ...]
@@ -485,6 +508,166 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
return id,message
# Create workout from RunKeeper Data
def add_workout_from_runkeeperdata(user,importid,data):
# To Do - add utcoffset to time
workouttype = data['type']
if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'water'
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.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
except:
try:
rowdatetime = dateutil.parser.parse(data['start_time'])
#rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
except:
rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
starttimeunix = mktime(rowdatetime.utctimetuple())
startimeunix += 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 == 'water':
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)
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)
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'
res = df.to_csv(csvfilename+'.gz',index_label='index',
compression='gzip')
id,message = dataprep.save_workout_database(csvfilename,r,
workouttype=workouttype,
title=title,
notes=comments)
return (id,message)
# Create workout from SportTracks Data, which are slightly different
# than Strava or Concept2 data
def add_workout_from_stdata(user,importid,data):
@@ -515,19 +698,15 @@ def add_workout_from_stdata(user,importid,data):
except:
rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
# try:
# c2intervaltype = data['workout_type']
# except:
# c2intervaltype = ''
starttimeunix = mktime(rowdatetime.utctimetuple())
try:
title = data['name']
except:
title = "Imported data"
starttimeunix = mktime(rowdatetime.utctimetuple())
res = splitstdata(data['distance'])
@@ -683,7 +862,18 @@ def sporttracks_open(user):
thetoken = r.sporttrackstoken
return thetoken
# Checks if user has SportTracks token, renews them if they are expired
def runkeeper_open(user):
r = Rower.objects.get(user=user)
if (r.runkeepertoken == '') or (r.runkeepertoken is None):
s = "Token doesn't exist. Need to authorize"
raise RunKeeperNoTokenError("User has no token")
else:
thetoken = r.runkeepertoken
return thetoken
# Export workout to TCX and send to user's email address
@login_required()
def workout_tcxemail_view(request,id=0):
@@ -965,6 +1155,70 @@ def workout_c2_upload_view(request,id=0):
return HttpResponseRedirect(url)
# Upload workout to RunKeeper
@login_required()
def workout_runkeeper_upload_view(request,id=0):
message = ""
try:
thetoken = runkeeper_open(request.user)
except RunKeeperNoTokenError:
return HttpResponseRedirect("/rowers/me/runkeeperauthorize/")
# ready to upload. Hurray
try:
w = Workout.objects.get(id=id)
except Workout.DoesNotExist:
raise Http404("Workout doesn't exist")
if (checkworkoutuser(request.user,w)):
data = runkeeperstuff.createrunkeeperworkoutdata(w)
if not data:
message = "Data error"
url = reverse(workout_export_view,
kwargs = {
'message':str(message),
'id':str(w.id),
})
return HttpResponseRedirect(url)
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json',
'Content-Length':'nnn'}
import urllib
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
w.save()
elif (response.status_code == 201 or response.status_code==200):
runkeeperid = runkeeperstuff.getidfromresponse(response)
w.uploadedtorunkeeper = runkeeperid
w.save()
url = "/rowers/workout/"+str(w.id)+"/export"
return HttpResponseRedirect(url)
else:
s = response
print dir(s)
print s.text
message = "Something went wrong in workout_runkeeper_upload_view: %s" % s.reason
else:
message = "You are not authorized to upload this workout"
url = reverse(workout_export_view,
kwargs = {
'message':str(message),
'id':str(w.id),
})
return HttpResponseRedirect(url)
# Upload workout to SportTracks
@login_required()
def workout_sporttracks_upload_view(request,id=0):
@@ -4487,7 +4741,7 @@ def workout_runkeeperimport_view(request,message=""):
else:
workouts = []
for item in res.json()['items']:
d = int(float(item['total_distance']))
d = int(float(item['total_distance']))
i = getidfromsturi(item['uri'],length=9)
ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
s = item['start_time']
@@ -4662,12 +4916,9 @@ def workout_getstravaworkout_view(request,stravaid):
# Imports a workout from Runkeeper
@login_required()
def workout_getrunkeeperworkout_view(request,runkeeperid):
res = runkeeperstuff.get_runkeeper_workout(request.user,runkeeperid)
res = runkeeperstuff.get_runkeeper_workout(request.user,runkeeperid)
data = res.json()
return HttpResponse(data)
id,message = add_workout_from_runkeeperdata(request.user,runkeeperid,data)
w = Workout.objects.get(id=id)
w.uploadedtorunkeeper=runkeeperid