Private
Public Access
1
0

st half implemented

This commit is contained in:
Sander Roosendaal
2023-02-13 20:12:42 +01:00
parent 9975dfd897
commit 410722a990
10 changed files with 327 additions and 176 deletions

View File

@@ -1,3 +1,4 @@
from .c2 import C2Integration
from .strava import StravaIntegration
from .nk import NKIntegration
from .sporttracks import SportTracksIntegration

View File

@@ -56,7 +56,7 @@ def c2wc(weightclass):
class C2Integration(SyncIntegration):
def __init__(self, *args, **kwargs):
super(C2Integration, self).__init__(self, *args, **kwargs)
super(C2Integration, self).__init__(*args, **kwargs)
self.oauth_data = {
'client_id': C2_CLIENT_ID,
'client_secret': C2_CLIENT_SECRET,

View File

@@ -26,7 +26,7 @@ class SyncIntegration(metaclass=ABCMeta):
rower = Rower()
def __init__(self, *args, **kwargs):
user = args[1]
user = args[0]
self.user = user
self.rower = user.rower

View File

@@ -1,8 +1,6 @@
from .integrations import SyncIntegration, NoTokenError
from rowers.models import User, Rower, Workout, TombStone
from rowingdata import rowingdata
from rowers import mytypes
from rowers.nkimportutils import *
from rowers.tasks import handle_nk_async_workout
@@ -31,7 +29,7 @@ queuehigh = django_rq.get_queue('low')
class NKIntegration(SyncIntegration):
def __init__(self, *args, **kwargs):
super(NKIntegration, self).__init__(self, *args, **kwargs)
super(NKIntegration, self).__init__(*args, **kwargs)
self.oauth_data = {
'client_id': NK_CLIENT_ID,
'client_secret': NK_CLIENT_SECRET,
@@ -310,7 +308,3 @@ class NKIntegration(SyncIntegration):
return r.nktoken
# just as a quick test during development
u = User.objects.get(id=1)
nk_integration_1 = NKIntegration(u)

View File

@@ -0,0 +1,143 @@
from .integrations import SyncIntegration, NoTokenError
from rowers.models import User, Rower, Workout, TombStone
from rowers.tasks import handle_sporttracks_sync
from rowers.rower_rules import is_workout_user
import rowers.mytypes as mytypes
from rowsandall_app.settings import (
SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID,
SPORTTRACKS_REDIRECT_URI
)
import re
import numpy
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('high')
from rowers.utils import myqueue, dologging
class SportTracksIntegration(SyncIntegration):
def __init__(self, *args, **kwargs):
super(SportTracksIntegration, self).__init__(*args, **kwargs)
self.oauth_data = {
'client_id': SPORTTRACKS_CLIENT_ID,
'client_secret': SPORTTRACKS_CLIENT_SECRET,
'redirect_uri': SPORTTRACKS_REDIRECT_URI,
'autorization_uri': "https://api.sporttracks.mobi/oauth2/authorize",
'content_type': 'application/json',
'tokenname': 'sporttrackstoken',
'refreshtokenname': 'sporttracksrefreshtoken',
'expirydatename': 'sporttrackstokenexpirydate',
'bearer_auth': False,
'base_url': "https://api.sporttracks.mobi/oauth2/token",
'scope': 'write',
}
def open(self, *args, **kwargs) -> str:
return super(SportTracksIntegration, self).open(*args, **kwargs)
def createworkoutdata(self, w, *args, **kwargs):
return None
def workout_export(self, workout, *args, **kwargs) -> str:
pass
def get_workouts(self, *args, **kwargs) -> int:
pass
def get_workout(self, id) -> int:
_ = self.open()
r = self.rower
authorizationstring = str('Bearer ' + r.sporttrackstoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/" + \
str(sporttracksid)
s = requests.get(url, headers=headers)
data = s.json()
strokedata = pd.DataFrame.from_dict({
key: pd.Series(value, dtype='object') for key, value in data.items()
})
id = myqueue(
queue,
handle_sporttracks_workout_from_data,
self.user,
sporttracksid, data,
strokedata,
'sporttracks',
'sporttracks'
)
return id
def get_workout_list(self, *args, **kwargs) -> list:
_ = self.open()
r = self.rower
authorizationstring = str('Bearer ' + r.sporttrackstoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities"
res = requests.get(url, headers=headers)
if (res.status_code != 200):
s = "Token doesn't exist. Need to authorize"
raise NoTokenError(s)
workouts = []
knownstids = uniqify([
w.uploadedtosporttracks for w in Workout.objects.filter(user=r)
])
for item in res.json()['items']:
d = int(float(item['total_distance']))
i = int(getidfromuri(item['uri']))
if i in knownstids: # pragma: no cover
nnn = ''
else:
nnn = 'NEW'
n = item['name']
ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
s = item['start_time']
r = item['type']
keys = ['id', 'distance', 'duration',
'starttime', 'rowtype', 'source', 'name', 'new']
values = [i, d, ttot, s, r, None, n, nnn]
res = dict(zip(keys, values))
workouts.append(res)
return workouts
def make_authorization_url(self, *args, **kwargs) -> str: # pragma: no cover
return super(SportTracksIntegration, self).make_authorization_url(*args, **kwargs)
def get_token(self, code, *args, **kwargs) -> (str, int, str):
return ""
def token_refresh(self, *args, **kwargs) -> str:
return super(SportTracksIntegration, self).token_refresh(*args, **kwargs)
# just as a quick test during development
u = User.objects.get(id=1)
nk_integration_1 = SportTracksIntegration(u)

View File

@@ -79,7 +79,7 @@ def strava_push_delete(id): # pragma: no cover
class StravaIntegration(SyncIntegration):
def __init__(self, *args, **kwargs):
super(StravaIntegration, self).__init__(self, *args, **kwargs)
super(StravaIntegration, self).__init__(*args, **kwargs)
self.oauth_data = {
'client_id': STRAVA_CLIENT_ID,
'client_secret': STRAVA_CLIENT_SECRET,

View File

@@ -1,4 +1,4 @@
from rowers.tasks import handle_sporttracks_sync
from rowers.tasks import handle_sporttracks_sync, handle_sporttracks_workout_from_data
from rowers.rower_rules import is_workout_user
import rowers.mytypes as mytypes
from rowsandall_app.settings import (
@@ -127,12 +127,14 @@ def get_workout(user, sporttracksid, do_async=False):
key: pd.Series(value, dtype='object') for key, value in data.items()
})
id, message = add_workout_from_data(
id= myqueue(
queue,
handle_sporttracks_workout_from_data,
user,
sporttracksid, data,
strokedata,
source='sporttracks',
workoutsource='sporttracks')
'sporttracks',
'sporttracks')
return id
@@ -346,165 +348,3 @@ def workout_sporttracks_upload(user, w, asynchron=False): # pragma: no cover
# Create workout from SportTracks Data, which are slightly different
# than Strava or Concept2 data
def add_workout_from_data(user, importid, data, strokedata, source='sporttracks',
workoutsource='sporttracks'):
try:
workouttype = data['type']
except KeyError: # pragma: no cover
workouttype = 'other'
if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'other'
try:
comments = data['comments']
except:
comments = ''
r = Rower.objects.get(user=user)
try:
rowdatetime = iso8601.parse_date(data['start_time'])
except iso8601.ParseError: # pragma: no cover
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 = arrow.get(rowdatetime).timestamp()
try:
title = data['name']
except: # pragma: no cover
title = "Imported data"
try:
res = splitstdata(data['distance'])
distance = res[1]
times_distance = res[0]
except KeyError: # pragma: no cover
try:
res = splitstdata(data['heartrate'])
times_distance = res[0]
distance = 0*times_distance
except KeyError:
return (0, "No distance or heart rate data in the workout")
try:
locs = data['location']
res = splitstdata(locs)
times_location = res[0]
latlong = res[1]
latcoord = []
loncoord = []
for coord in latlong:
lat = coord[0]
lon = coord[1]
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 mytypes.otwtypes: # pragma: no cover
workouttype = 'rower'
try:
res = splitstdata(data['cadence'])
times_spm = res[0]
spm = res[1]
except KeyError: # pragma: no cover
times_spm = times_distance
spm = 0*times_distance
try:
res = splitstdata(data['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)
velo2 = ewmovingaverage(velo, wsize)
df[' Stroke500mPace (sec/500m)'] = 500./velo2
df = df.fillna(0)
df.sort_values(by='TimeStamp (sec)', ascending=True)
# 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,
title=title,
notes=comments,
dosmooth=r.dosmooth,
workoutsource='sporttracks')
return (id, message)

View File

@@ -447,6 +447,174 @@ def handle_c2_sync(workoutid, url, headers, data, debug=False, **kwargs):
return 1
def splitstdata(lijst):
t = []
latlong = []
while len(lijst) >= 2:
t.append(lijst[0])
latlong.append(lijst[1])
lijst = lijst[2:]
return [np.array(t), np.array(latlong)]
@app.task
def handle_sporttracks_workout_from_data(user, importid, data, strokedata, source,
workoutsource, debug=False, **kwargs):
try:
workouttype = data['type']
except KeyError: # pragma: no cover
workouttype = 'other'
if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'other'
try:
comments = data['comments']
except:
comments = ''
r = Rower.objects.get(user=user)
rowdatetime = iso8601.parse_date(data['start_time'])
starttimeunix = arrow.get(rowdatetime).timestamp()
try:
title = data['name']
except: # pragma: no cover
title = "Imported data"
try:
res = splitstdata(data['distance'])
distance = res[1]
times_distance = res[0]
except KeyError: # pragma: no cover
try:
res = splitstdata(data['heartrate'])
times_distance = res[0]
distance = 0*times_distance
except KeyError:
return (0, "No distance or heart rate data in the workout")
try:
locs = data['location']
res = splitstdata(locs)
times_location = res[0]
latlong = res[1]
latcoord = []
loncoord = []
for coord in latlong:
lat = coord[0]
lon = coord[1]
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 mytypes.otwtypes: # pragma: no cover
workouttype = 'rower'
try:
res = splitstdata(data['cadence'])
times_spm = res[0]
spm = res[1]
except KeyError: # pragma: no cover
times_spm = times_distance
spm = 0*times_distance
try:
res = splitstdata(data['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)
velo2 = ewmovingaverage(velo, wsize)
df[' Stroke500mPace (sec/500m)'] = 500./velo2
df = df.fillna(0)
df.sort_values(by='TimeStamp (sec)', ascending=True)
csvfilename = 'media/{code}_{importid}.csv'.format(
importid=importid,
code=uuid4().hex[:16]
)
res = df.to_csv(csvfilename+'.gz', index_label='index',
compression='gzip')
uploadoptions = {
'secret': UPLOAD_SERVICE_SECRET,
'user': user.id,
'file': csvfilename+'.gz',
'title': '',
'workouttype': workouttype,
'boattype': '1x',
'sporttracksid': importid,
'title':title,
}
session = requests.session()
newHeaders = {'Content-type': 'application/json', 'Accept': 'text/plain'}
session.headers.update(newHeaders)
_ = session.post(UPLOAD_SERVICE_URL, json=uploadoptions)
return 1
@app.task
def handle_sporttracks_sync(workoutid, url, headers, data, debug=False, **kwargs):

View File

@@ -236,6 +236,10 @@ def do_sync(w, options, quick=False):
f.write(str(e))
do_st_export = w.user.sporttracks_auto_export
if options['sporttracksid'] != 0 and options['sporttracksid'] != '':
w.uploadedtost = options['sporttracksid']
w.save()
do_st_export = False
try: # pragma: no cover
upload_to_st = options['upload_to_SportTracks'] or do_st_export
do_st_export = upload_to_st

View File

@@ -5209,6 +5209,7 @@ def workout_upload_api(request):
# sync related IDs
sporttracksid = post_data.get('sporttracksid','')
c2id = post_data.get('c2id', '')
workoutid = post_data.get('id','')
startdatetime = post_data.get('startdatetime', '')