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 .c2 import C2Integration
from .strava import StravaIntegration from .strava import StravaIntegration
from .nk import NKIntegration from .nk import NKIntegration
from .sporttracks import SportTracksIntegration

View File

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

View File

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

View File

@@ -1,8 +1,6 @@
from .integrations import SyncIntegration, NoTokenError from .integrations import SyncIntegration, NoTokenError
from rowers.models import User, Rower, Workout, TombStone from rowers.models import User, Rower, Workout, TombStone
from rowingdata import rowingdata
from rowers import mytypes from rowers import mytypes
from rowers.nkimportutils import * from rowers.nkimportutils import *
from rowers.tasks import handle_nk_async_workout from rowers.tasks import handle_nk_async_workout
@@ -31,7 +29,7 @@ queuehigh = django_rq.get_queue('low')
class NKIntegration(SyncIntegration): class NKIntegration(SyncIntegration):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(NKIntegration, self).__init__(self, *args, **kwargs) super(NKIntegration, self).__init__(*args, **kwargs)
self.oauth_data = { self.oauth_data = {
'client_id': NK_CLIENT_ID, 'client_id': NK_CLIENT_ID,
'client_secret': NK_CLIENT_SECRET, 'client_secret': NK_CLIENT_SECRET,
@@ -310,7 +308,3 @@ class NKIntegration(SyncIntegration):
return r.nktoken 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): class StravaIntegration(SyncIntegration):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(StravaIntegration, self).__init__(self, *args, **kwargs) super(StravaIntegration, self).__init__(*args, **kwargs)
self.oauth_data = { self.oauth_data = {
'client_id': STRAVA_CLIENT_ID, 'client_id': STRAVA_CLIENT_ID,
'client_secret': STRAVA_CLIENT_SECRET, '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 from rowers.rower_rules import is_workout_user
import rowers.mytypes as mytypes import rowers.mytypes as mytypes
from rowsandall_app.settings import ( 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() 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, user,
sporttracksid, data, sporttracksid, data,
strokedata, strokedata,
source='sporttracks', 'sporttracks',
workoutsource='sporttracks') 'sporttracks')
return id 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 # Create workout from SportTracks Data, which are slightly different
# than Strava or Concept2 data # 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 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 @app.task
def handle_sporttracks_sync(workoutid, url, headers, data, debug=False, **kwargs): 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)) f.write(str(e))
do_st_export = w.user.sporttracks_auto_export 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 try: # pragma: no cover
upload_to_st = options['upload_to_SportTracks'] or do_st_export upload_to_st = options['upload_to_SportTracks'] or do_st_export
do_st_export = upload_to_st do_st_export = upload_to_st

View File

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