Private
Public Access
1
0

another batch of files with a light sprinkle of comments

This commit is contained in:
Sander Roosendaal
2017-01-15 16:06:14 +01:00
parent 737ac5fd3f
commit e5810dbf62
11 changed files with 64 additions and 11 deletions

View File

@@ -4,8 +4,9 @@ from django.contrib.auth.models import User
from .models import Rower, Workout,GraphImage,FavoriteChart,SiteAnnouncement from .models import Rower, Workout,GraphImage,FavoriteChart,SiteAnnouncement
# Register your models here. # Register your models here so you can use them in the Admin module
# Rower details directly under the User
class RowerInline(admin.StackedInline): class RowerInline(admin.StackedInline):
model = Rower model = Rower
can_delete = False can_delete = False

View File

@@ -2,6 +2,6 @@ from __future__ import unicode_literals
from django.apps import AppConfig from django.apps import AppConfig
# Store metadata for the app
class RowersConfig(AppConfig): class RowersConfig(AppConfig):
name = 'rowers' name = 'rowers'

View File

@@ -4,6 +4,9 @@ import os
from celery import Celery from celery import Celery
# Only used for testing with Celery on localhost. RQ is not available
# on Windows, so I use Celery on my notebook.
# set the default Django settings module for the 'celery' program. # set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rowsandall_app.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rowsandall_app.settings')

View File

@@ -1,3 +1,5 @@
# This is Data prep used for testing purposes (no Django environment)
# Uses the debug SQLite database for stroke data
from rowingdata import rowingdata as rrdata from rowingdata import rowingdata as rrdata
from rowingdata import rower as rrower from rowingdata import rower as rrower

View File

@@ -1,3 +1,4 @@
# Processes emails sent to workouts@rowsandall.com
import time import time
from django.conf import settings from django.conf import settings
from rowers.tasks import handle_sendemail_unrecognized from rowers.tasks import handle_sendemail_unrecognized
@@ -21,7 +22,9 @@ from scipy.signal import savgol_filter
import zipfile import zipfile
import os import os
import rowers.dataprep as dataprep
# Sends a confirmation with a link to the workout
def send_confirm(u,name,link): def send_confirm(u,name,link):
fullemail = u.email fullemail = u.email
subject = 'Workout added: '+name subject = 'Workout added: '+name
@@ -38,6 +41,7 @@ def send_confirm(u,name,link):
return 1 return 1
# Reads a "rowingdata" object, plus some error protections
def rdata(file,rower=rrower()): def rdata(file,rower=rrower()):
try: try:
res = rrdata(file,rower=rower) res = rrdata(file,rower=rower)
@@ -49,13 +53,18 @@ def rdata(file,rower=rrower()):
return res return res
# Some error protection around process attachments
def safeprocessattachments(): def safeprocessattachments():
try: try:
return processattachments() return processattachments()
except: except:
return [0] return [0]
# This is duplicated in management/commands/processemail
# Need to double check the code there, update here, and only
# use the code here.
def processattachments(): def processattachments():
# in res, we store the ids of the new workouts
res = [] res = []
attachments = MessageAttachment.objects.all() attachments = MessageAttachment.objects.all()
for a in attachments: for a in attachments:
@@ -73,7 +82,6 @@ def processattachments():
try: try:
wid = [make_new_workout_from_email(rr,a.document,name)] wid = [make_new_workout_from_email(rr,a.document,name)]
res += wid res += wid
print wid
link = 'https://rowsandall.com/rowers/workout/'+str(wid[0])+'/edit' link = 'https://rowsandall.com/rowers/workout/'+str(wid[0])+'/edit'
dd = send_confirm(u,name,link) dd = send_confirm(u,name,link)
except: except:
@@ -92,6 +100,7 @@ def processattachments():
# no attachments, so can be deleted # no attachments, so can be deleted
m.delete() m.delete()
# Delete remaining messages (which should not have attachments)
mm = Message.objects.all() mm = Message.objects.all()
for m in mm: for m in mm:
if m.attachments.exists()==False: if m.attachments.exists()==False:
@@ -99,6 +108,7 @@ def processattachments():
return res return res
# As above, but with some print commands for debugging purposes
def processattachments_debug(): def processattachments_debug():
res = [] res = []
attachments = MessageAttachment.objects.all() attachments = MessageAttachment.objects.all()
@@ -144,7 +154,9 @@ def processattachments_debug():
return res return res
# Process the attachment file, create new workout
# The code here is duplication of the code in views.py (workout_upload_view)
# Need to move the code to a subroutine used both in views.py and here
def make_new_workout_from_email(rr,f2,name,cntr=0): def make_new_workout_from_email(rr,f2,name,cntr=0):
workouttype = 'rower' workouttype = 'rower'
f2 = f2.name f2 = f2.name
@@ -305,6 +317,16 @@ def make_new_workout_from_email(rr,f2,name,cntr=0):
startdatetime=row.rowdatetime) startdatetime=row.rowdatetime)
w.save() w.save()
print w.id
print row.df.info()
# put stroke data in database
res = dataprep.dataprep(row.df,id=w.id,
bands=True,barchart=True,
otwpower=True,empower=True)
return w.id return w.id

View File

@@ -1,3 +1,5 @@
# Interactions with Rowsandall.com API. Not fully complete.
# Python # Python
import oauth2 as oauth import oauth2 as oauth
import cgi import cgi

View File

@@ -1,3 +1,5 @@
# Defines permissions for objects (API related)
from rest_framework import permissions from rest_framework import permissions
from rowers.models import Rower from rowers.models import Rower

View File

@@ -3,6 +3,7 @@ import matplotlib.pyplot as plt
import numpy as np import numpy as np
# Make pace ticks for pace axis '2:00', '1:50', etc
def format_pace_tick(x,pos=None): def format_pace_tick(x,pos=None):
min=int(x/60) min=int(x/60)
sec=int(x-min*60.) sec=int(x-min*60.)
@@ -10,6 +11,7 @@ def format_pace_tick(x,pos=None):
template='%d:%s' template='%d:%s'
return template % (min,sec_str) return template % (min,sec_str)
# Returns a pace string from a pace in seconds/500m, '1:45.4'
def format_pace(x,pos=None): def format_pace(x,pos=None):
if isinf(x) or isnan(x): if isinf(x) or isnan(x):
x=0 x=0
@@ -24,6 +26,7 @@ def format_pace(x,pos=None):
return str1 return str1
# Returns a time string from a time in seconds
def format_time(x,pos=None): def format_time(x,pos=None):
@@ -37,11 +40,13 @@ def format_time(x,pos=None):
return str1 return str1
# Formatting the distance tick marks
def format_dist_tick(x,pos=None): def format_dist_tick(x,pos=None):
km = x/1000. km = x/1000.
template='%6.3f' template='%6.3f'
return template % (km) return template % (km)
# Formatting the time tick marks (h:mm)
def format_time_tick(x,pos=None): def format_time_tick(x,pos=None):
hour=int(x/3600) hour=int(x/3600)
min=int((x-hour*3600.)/60) min=int((x-hour*3600.)/60)
@@ -49,6 +54,11 @@ def format_time_tick(x,pos=None):
template='%d:%s' template='%d:%s'
return template % (hour,min_str) return template % (hour,min_str)
# Utility to select reasonable y axis range
# Basically the data range plus some padding, but with ultimate
# you can set the slowest paces to fall off the axis.
# Useful for OTW rowing where you sometimes stops and pace runs out of
# the boundaries
def y_axis_range(ydata,miny=0,padding=.1,ultimate=[-1e9,1e9]): def y_axis_range(ydata,miny=0,padding=.1,ultimate=[-1e9,1e9]):
# ydata must by a numpy array # ydata must by a numpy array
@@ -86,6 +96,7 @@ def y_axis_range(ydata,miny=0,padding=.1,ultimate=[-1e9,1e9]):
return [yrangemin,yrangemax] return [yrangemin,yrangemax]
# Make a plot (this one is only used for testing)
def mkplot(row,title): def mkplot(row,title):
df = row.df df = row.df

View File

@@ -1,3 +1,6 @@
# Serializers. Defines which fields from an object get to the JSON object
# Also optionally define POST, PATCH methods (create, update)
from rest_framework import serializers from rest_framework import serializers
from rowers.models import Workout,Rower,StrokeData,FavoriteChart from rowers.models import Workout,Rower,StrokeData,FavoriteChart
@@ -104,6 +107,7 @@ class WorkoutSerializer(serializers.ModelSerializer):
instance.save() instance.save()
return instance return instance
# This is just a fake one for URL registration purposes
class StrokeDataSerializer(serializers.Serializer): class StrokeDataSerializer(serializers.Serializer):
workoutid = serializers.IntegerField workoutid = serializers.IntegerField
strokedata = serializers.JSONField strokedata = serializers.JSONField

View File

@@ -21,12 +21,12 @@ from rowers.dataprepnodjango import update_strokedata
from django.core.mail import send_mail, BadHeaderError,EmailMessage from django.core.mail import send_mail, BadHeaderError,EmailMessage
# testing task
@app.task @app.task
def add(x, y): def add(x, y):
return x + y return x + y
# send email to me when an unrecognized file is uploaded
@app.task @app.task
def handle_sendemail_unrecognized(unrecognizedfile,useremail): def handle_sendemail_unrecognized(unrecognizedfile,useremail):
@@ -51,7 +51,7 @@ def handle_sendemail_unrecognized(unrecognizedfile,useremail):
os.remove(unrecognizedfile) os.remove(unrecognizedfile)
return 1 return 1
# Send email with TCX attachment
@app.task @app.task
def handle_sendemailtcx(first_name,last_name,email,tcxfile): def handle_sendemailtcx(first_name,last_name,email,tcxfile):
@@ -75,6 +75,7 @@ def handle_sendemailtcx(first_name,last_name,email,tcxfile):
os.remove(tcxfile) os.remove(tcxfile)
return 1 return 1
# Send email with CSV attachment
@app.task @app.task
def handle_sendemailcsv(first_name,last_name,email,csvfile): def handle_sendemailcsv(first_name,last_name,email,csvfile):
@@ -104,6 +105,7 @@ def handle_sendemailcsv(first_name,last_name,email,csvfile):
return 1 return 1
# Calculate wind and stream corrections for OTW rowing
@app.task @app.task
def handle_otwsetpower(f1,boattype,weightvalue, def handle_otwsetpower(f1,boattype,weightvalue,
first_name,last_name,email,workoutid, first_name,last_name,email,workoutid,
@@ -129,7 +131,7 @@ def handle_otwsetpower(f1,boattype,weightvalue,
except KeyError: except KeyError:
rg = rowingdata.getrigging('static/rigging/1x.txt') rg = rowingdata.getrigging('static/rigging/1x.txt')
# do calculation # do calculation, but do not overwrite NK Empower Power data
powermeasured = False powermeasured = False
try: try:
w = rowdata.df['wash'] w = rowdata.df['wash']
@@ -166,6 +168,7 @@ def handle_otwsetpower(f1,boattype,weightvalue,
return 1 return 1
# This function generates all the static (PNG image) plots
@app.task @app.task
def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename): def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename):
hrmax = hrdata['hrmax'] hrmax = hrdata['hrmax']
@@ -222,5 +225,6 @@ def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename):
return imagename return imagename
# Another simple task for debugging purposes
def add2(x,y): def add2(x,y):
return x+y return x+y

View File

@@ -8,9 +8,8 @@ from rowers.models import Rower, Workout
from rowsandall_app.settings import FORECAST_IO_KEY from rowsandall_app.settings import FORECAST_IO_KEY
# Get weather data from the DarkSky API
def get_weather_data(long,lat,unixtime): def get_weather_data(long,lat,unixtime):
# url = "https://api.forecast.io/forecast/"+FORECAST_IO_KEY+"/"
url = "https://api.darksky.net/forecast/"+FORECAST_IO_KEY+"/" url = "https://api.darksky.net/forecast/"+FORECAST_IO_KEY+"/"
url += str(long)+","+str(lat)+","+str(unixtime) url += str(long)+","+str(lat)+","+str(unixtime)
@@ -21,6 +20,7 @@ def get_weather_data(long,lat,unixtime):
else: else:
return 0 return 0
# Get wind data (and translate from knots to m/s)
def get_wind_data(lat,long,unixtime): def get_wind_data(lat,long,unixtime):
data = get_weather_data(lat,long,unixtime) data = get_weather_data(lat,long,unixtime)
if data: if data:
@@ -39,6 +39,7 @@ def get_wind_data(lat,long,unixtime):
try: try:
temperature = data['currently']['temperature'] temperature = data['currently']['temperature']
# Temp is given in Fahrenheit, so convert to Celsius for Europeans
temperaturec = (temperature-32.)*(5./9.) temperaturec = (temperature-32.)*(5./9.)
temperaturec = int(10*temperaturec)/10. temperaturec = int(10*temperaturec)/10.
except KeyError: except KeyError:
@@ -54,7 +55,8 @@ def get_wind_data(lat,long,unixtime):
windbearing = 0 windbearing = 0
message = 'Not able to get weather data' message = 'Not able to get weather data'
# apply Hellman's coefficient for neutral air above human inhabitated areas # apply Hellman's coefficient for neutral air above human
# inhabitated areas
windspeed = windspeed*(0.1)**0.34 windspeed = windspeed*(0.1)**0.34
windspeed = 0.01*int(100*windspeed) windspeed = 0.01*int(100*windspeed)