Private
Public Access
1
0

import working

This commit is contained in:
Sander Roosendaal
2017-04-16 14:14:20 +02:00
parent cb7d43487e
commit d70df62b63
7 changed files with 359 additions and 13 deletions

View File

@@ -43,12 +43,22 @@
<p>Import workouts from RunKeeper</p>
</div>
</div>
<div class="grid_6">
<div class="grid_3 alpha">
<p>
<a href="/rowers/workout/underarmourimport"><img src="/static/img/UAbtn.png" alt="Under Armour logo" width="140"></a>
</p>
</div>
<div class="grid_3 omega">
<p>Import workouts from MapMyFitness/UnderArmour</p>
</div>
</div>
</div>
<div class="grid_6 omega">
<h3>Connect</h3>
<div class="grid_6">
<div class="grid_6 alpha">
<p>Click one of the below logos to connect to the service of your choice.
You only need to do this once. After that, the site will have access until you
revoke the authorization for the "rowingdata" app.</p>
@@ -67,10 +77,13 @@
</div>
</div>
<div class="grid_6">
<div class="grid_2 alpha suffix_4">
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p><a href="/rowers/me/runkeeperauthorize/"><img src="/static/img/rk-logo.png" alt="connect with RunKeeper" width="120"></a></p>
</div>
<div class="grid_2 suffix_2 omega">
<p><a href="/rowers/me/underarmourauthorize/"><img src="/static/img/UAbtn.png" alt="connect with Under Armour" width="120"></a></p>
</div>
</div>
</div>

View File

@@ -0,0 +1,37 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<h1>Available on MapMyFitness (UnderArmour)</h1>
{% if workouts %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Import </th>
<th> Date/Time </th>
<th> Duration </th>
<th> Total Distance</th>
<th> Type</th>
</tr>
</thead>
<tbody>
{% for workout in workouts %}
<tr>
<td>
<a href="/rowers/workout/underarmourimport/{{ workout|ualookup:'id' }}/">Import</a></td>
<td>{{ workout|ualookup:'starttime' }}</td>
<td>{{ workout|ualookup:'duration' }} </td>
<td>{{ workout|ualookup:'distance' }} m</td>
<td>{{ workout|ualookup:'type' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> No workouts found. We only list workouts with time data series. </p>
{% endif %}
{% endblock %}

View File

@@ -1,5 +1,6 @@
from django import template
from time import strftime
import dateutil.parser
register = template.Library()
@@ -27,6 +28,17 @@ def strfdeltah(tdelta):
return res
def secondstotimestring(tdelta):
hours, rest = divmod(tdelta,3600)
minutes,seconds = divmod(rest,60)
res = "{hours:0>2}:{minutes:0>2}:{seconds:0>2}".format(
hours=hours,
minutes=minutes,
seconds=seconds,
)
return res
@register.filter
def durationprint(d,dstring):
if (d == None):
@@ -57,6 +69,22 @@ def lookup(dict, key):
s = s[:22]
return s
@register.filter
def ualookup(dict, key):
s = dict.get(key)
if key=='distance':
s = int(float(s))
if key=='duration':
s = secondstotimestring(int(s))
if key=='starttime':
s = dateutil.parser.parse(s)
return s
@register.filter(name='times')
def times(number):
return range(number)

View File

@@ -171,9 +171,9 @@ def get_underarmour_workout_list(user):
headers = {'Authorization': authorizationstring,
'Api-Key': UNDERARMOUR_CLIENT_KEY,
'user-agent': 'sanderroosendaal',
'user':'v7.1/user/'+str(get_userid(r.underarmourtoken))+'/',
'Content-Type': 'application/json'}
url = "https://api.ua.com/v7.1/workout/"
url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))
s = requests.get(url,headers=headers)
return s
@@ -191,7 +191,7 @@ def get_underarmour_workout(user,underarmourid):
'Api-Key': UNDERARMOUR_CLIENT_KEY,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.ua.com/v7.1/workout/"+str(underarmourid)+"/"
url = "https://api.ua.com/v7.1/workout/"+str(underarmourid)+"/?field_set=time_series"
s = requests.get(url,headers=headers)
return s
@@ -292,13 +292,36 @@ def createunderarmourworkoutdata(w):
return data
# Obtain Underarmour Workout ID from the response returned on successful
# upload
def getidfromresponse(response):
uri = response.headers["Location"]
id = uri[len(uri)-9:]
# 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 get_typefromid(typeid,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'}
import urllib
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
return int(id)
# Get user id, having access token

View File

@@ -229,6 +229,8 @@ urlpatterns = [
url(r'^workout/sporttracksimport/(\d+)/$',views.workout_getsporttracksworkout_view),
url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view),
url(r'^workout/runkeeperimport/(\d+)/$',views.workout_getrunkeeperworkout_view),
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view),
url(r'^workout/underarmourimport/(\d+)/$',views.workout_getunderarmourworkout_view),
url(r'^workout/(\d+)/deleteconfirm$',views.workout_delete_confirm_view),
url(r'^workout/(\d+)/c2uploadw/$',views.workout_c2_upload_view),
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),

View File

@@ -214,6 +214,15 @@ def get_time(second):
def getidfromsturi(uri,length=8):
return uri[len(uri)-length:]
def splituadata(lijst):
t = []
y = []
for d in lijst:
t.append(d[0])
y.append(d[1])
return np.array(t),np.array(y)
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
t = []
lat = []
@@ -816,6 +825,173 @@ def add_workout_from_stdata(user,importid,data):
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_underarmourdata(user,importid,data):
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.datetime.strptime(data['start_datetime'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
except:
try:
rowdatetime = dateutil.parser.parse(data['start_datetime'])
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())
try:
title = data['name']
except:
title = "Imported data"
timeseries = data['time_series']
# position, distance, speed, cadence, power,
res = splituadata(timeseries['distance'])
distance = res[1]
times_distance = res[0]
print distance[0:5]
print times_distance[0:5]
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 == 'water':
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
@@ -1401,7 +1577,7 @@ def rower_underarmour_authorize(request):
redirect_uri = UNDERARMOUR_REDIRECT_URI
redirect_uri = 'http://localhost:8000/underarmour_callback'
url = 'https://api.mapmyfitness.com/v7.1/oauth2/authorize/?' \
url = 'https://www.mapmyfitness.com/v7.1/oauth2/authorize/?' \
'client_id={0}&response_type=code&redirect_uri={1}'.format(
UNDERARMOUR_CLIENT_KEY, redirect_uri
)
@@ -4896,6 +5072,50 @@ def workout_runkeeperimport_view(request,message=""):
return HttpResponse(res)
# The page where you select which RunKeeper workout to import
@login_required()
def workout_underarmourimport_view(request,message=""):
res = underarmourstuff.get_underarmour_workout_list(request.user)
if (res.status_code != 200):
if (res.status_code == 401):
r = Rower.objects.get(user=request.user)
if (r.underarmourtoken == '') or (r.underarmourtoken is None):
s = "Token doesn't exist. Need to authorize"
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
message = "Something went wrong in workout_underarmourimport_view"
if settings.DEBUG:
return HttpResponse(res)
else:
url = reverse(workouts_view,
kwargs = {
'message': str(message)
})
return HttpResponseRedirect(url)
else:
workouts = []
items = res.json()['_embedded']['workouts']
for item in items:
if 'has_time_series' in item:
if item['has_time_series']:
s = item['start_datetime']
i,r = underarmourstuff.get_idfromuri(request.user,item['_links'])
n = item['name']
d = item['aggregates']['distance_total']
ttot = item['aggregates']['active_time_total']
keys = ['id','distance','duration','starttime','type']
values = [i,d,ttot,s,r]
thedict = dict(zip(keys,values))
workouts.append(thedict)
return render(request,'underarmour_list_import.html',
{'workouts':workouts,
'teams':get_my_teams(request.user),
'message':message,
})
return HttpResponse(res)
# The page where you select which SportTracks workout to import
@login_required()
def workout_sporttracksimport_view(request,message=""):
@@ -5078,6 +5298,29 @@ def workout_getrunkeeperworkout_view(request,runkeeperid):
})
return HttpResponseRedirect(url)
# Imports a workout from Underarmour
@login_required()
def workout_getunderarmourworkout_view(request,underarmourid):
res = underarmourstuff.get_underarmour_workout(request.user,underarmourid)
data = res.json()
id,message = add_workout_from_underarmourdata(request.user,underarmourid,data)
w = Workout.objects.get(id=id)
w.uploadedtounderarmour=underarmourid
w.save()
if message:
url = reverse(workout_edit_view,
kwargs = {
'id':id,
'message':message,
})
else:
url = reverse(workout_edit_view,
kwargs = {
'id':id,
})
return HttpResponseRedirect(url)
# Imports a workout from SportTracks

BIN
static/img/UAbtn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB