another batch of files with a light sprinkle of comments
This commit is contained in:
@@ -4,8 +4,9 @@ from django.contrib.auth.models import User
|
||||
|
||||
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):
|
||||
model = Rower
|
||||
can_delete = False
|
||||
|
||||
@@ -2,6 +2,6 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
# Store metadata for the app
|
||||
class RowersConfig(AppConfig):
|
||||
name = 'rowers'
|
||||
|
||||
@@ -4,6 +4,9 @@ import os
|
||||
|
||||
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.
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rowsandall_app.settings')
|
||||
|
||||
|
||||
@@ -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 rower as rrower
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Processes emails sent to workouts@rowsandall.com
|
||||
import time
|
||||
from django.conf import settings
|
||||
from rowers.tasks import handle_sendemail_unrecognized
|
||||
@@ -21,7 +22,9 @@ from scipy.signal import savgol_filter
|
||||
|
||||
import zipfile
|
||||
import os
|
||||
import rowers.dataprep as dataprep
|
||||
|
||||
# Sends a confirmation with a link to the workout
|
||||
def send_confirm(u,name,link):
|
||||
fullemail = u.email
|
||||
subject = 'Workout added: '+name
|
||||
@@ -38,6 +41,7 @@ def send_confirm(u,name,link):
|
||||
|
||||
return 1
|
||||
|
||||
# Reads a "rowingdata" object, plus some error protections
|
||||
def rdata(file,rower=rrower()):
|
||||
try:
|
||||
res = rrdata(file,rower=rower)
|
||||
@@ -49,13 +53,18 @@ def rdata(file,rower=rrower()):
|
||||
|
||||
return res
|
||||
|
||||
# Some error protection around process attachments
|
||||
def safeprocessattachments():
|
||||
try:
|
||||
return processattachments()
|
||||
except:
|
||||
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():
|
||||
# in res, we store the ids of the new workouts
|
||||
res = []
|
||||
attachments = MessageAttachment.objects.all()
|
||||
for a in attachments:
|
||||
@@ -73,7 +82,6 @@ def processattachments():
|
||||
try:
|
||||
wid = [make_new_workout_from_email(rr,a.document,name)]
|
||||
res += wid
|
||||
print wid
|
||||
link = 'https://rowsandall.com/rowers/workout/'+str(wid[0])+'/edit'
|
||||
dd = send_confirm(u,name,link)
|
||||
except:
|
||||
@@ -92,6 +100,7 @@ def processattachments():
|
||||
# no attachments, so can be deleted
|
||||
m.delete()
|
||||
|
||||
# Delete remaining messages (which should not have attachments)
|
||||
mm = Message.objects.all()
|
||||
for m in mm:
|
||||
if m.attachments.exists()==False:
|
||||
@@ -99,6 +108,7 @@ def processattachments():
|
||||
|
||||
return res
|
||||
|
||||
# As above, but with some print commands for debugging purposes
|
||||
def processattachments_debug():
|
||||
res = []
|
||||
attachments = MessageAttachment.objects.all()
|
||||
@@ -144,7 +154,9 @@ def processattachments_debug():
|
||||
|
||||
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):
|
||||
workouttype = 'rower'
|
||||
f2 = f2.name
|
||||
@@ -305,6 +317,16 @@ def make_new_workout_from_email(rr,f2,name,cntr=0):
|
||||
startdatetime=row.rowdatetime)
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Interactions with Rowsandall.com API. Not fully complete.
|
||||
|
||||
# Python
|
||||
import oauth2 as oauth
|
||||
import cgi
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Defines permissions for objects (API related)
|
||||
|
||||
from rest_framework import permissions
|
||||
from rowers.models import Rower
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import matplotlib.pyplot as plt
|
||||
|
||||
import numpy as np
|
||||
|
||||
# Make pace ticks for pace axis '2:00', '1:50', etc
|
||||
def format_pace_tick(x,pos=None):
|
||||
min=int(x/60)
|
||||
sec=int(x-min*60.)
|
||||
@@ -10,6 +11,7 @@ def format_pace_tick(x,pos=None):
|
||||
template='%d:%s'
|
||||
return template % (min,sec_str)
|
||||
|
||||
# Returns a pace string from a pace in seconds/500m, '1:45.4'
|
||||
def format_pace(x,pos=None):
|
||||
if isinf(x) or isnan(x):
|
||||
x=0
|
||||
@@ -24,6 +26,7 @@ def format_pace(x,pos=None):
|
||||
|
||||
return str1
|
||||
|
||||
# Returns a time string from a time in seconds
|
||||
def format_time(x,pos=None):
|
||||
|
||||
|
||||
@@ -37,11 +40,13 @@ def format_time(x,pos=None):
|
||||
|
||||
return str1
|
||||
|
||||
# Formatting the distance tick marks
|
||||
def format_dist_tick(x,pos=None):
|
||||
km = x/1000.
|
||||
template='%6.3f'
|
||||
return template % (km)
|
||||
|
||||
# Formatting the time tick marks (h:mm)
|
||||
def format_time_tick(x,pos=None):
|
||||
hour=int(x/3600)
|
||||
min=int((x-hour*3600.)/60)
|
||||
@@ -49,6 +54,11 @@ def format_time_tick(x,pos=None):
|
||||
template='%d:%s'
|
||||
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]):
|
||||
|
||||
# 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]
|
||||
|
||||
# Make a plot (this one is only used for testing)
|
||||
def mkplot(row,title):
|
||||
df = row.df
|
||||
|
||||
|
||||
@@ -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 rowers.models import Workout,Rower,StrokeData,FavoriteChart
|
||||
|
||||
@@ -104,6 +107,7 @@ class WorkoutSerializer(serializers.ModelSerializer):
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
# This is just a fake one for URL registration purposes
|
||||
class StrokeDataSerializer(serializers.Serializer):
|
||||
workoutid = serializers.IntegerField
|
||||
strokedata = serializers.JSONField
|
||||
|
||||
@@ -21,12 +21,12 @@ from rowers.dataprepnodjango import update_strokedata
|
||||
|
||||
from django.core.mail import send_mail, BadHeaderError,EmailMessage
|
||||
|
||||
|
||||
# testing task
|
||||
@app.task
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
|
||||
# send email to me when an unrecognized file is uploaded
|
||||
@app.task
|
||||
def handle_sendemail_unrecognized(unrecognizedfile,useremail):
|
||||
|
||||
@@ -51,7 +51,7 @@ def handle_sendemail_unrecognized(unrecognizedfile,useremail):
|
||||
os.remove(unrecognizedfile)
|
||||
return 1
|
||||
|
||||
|
||||
# Send email with TCX attachment
|
||||
@app.task
|
||||
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)
|
||||
return 1
|
||||
|
||||
# Send email with CSV attachment
|
||||
@app.task
|
||||
def handle_sendemailcsv(first_name,last_name,email,csvfile):
|
||||
|
||||
@@ -104,6 +105,7 @@ def handle_sendemailcsv(first_name,last_name,email,csvfile):
|
||||
|
||||
return 1
|
||||
|
||||
# Calculate wind and stream corrections for OTW rowing
|
||||
@app.task
|
||||
def handle_otwsetpower(f1,boattype,weightvalue,
|
||||
first_name,last_name,email,workoutid,
|
||||
@@ -129,7 +131,7 @@ def handle_otwsetpower(f1,boattype,weightvalue,
|
||||
except KeyError:
|
||||
rg = rowingdata.getrigging('static/rigging/1x.txt')
|
||||
|
||||
# do calculation
|
||||
# do calculation, but do not overwrite NK Empower Power data
|
||||
powermeasured = False
|
||||
try:
|
||||
w = rowdata.df['wash']
|
||||
@@ -166,6 +168,7 @@ def handle_otwsetpower(f1,boattype,weightvalue,
|
||||
|
||||
return 1
|
||||
|
||||
# This function generates all the static (PNG image) plots
|
||||
@app.task
|
||||
def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename):
|
||||
hrmax = hrdata['hrmax']
|
||||
@@ -222,5 +225,6 @@ def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename):
|
||||
return imagename
|
||||
|
||||
|
||||
# Another simple task for debugging purposes
|
||||
def add2(x,y):
|
||||
return x+y
|
||||
|
||||
@@ -8,9 +8,8 @@ from rowers.models import Rower, Workout
|
||||
|
||||
from rowsandall_app.settings import FORECAST_IO_KEY
|
||||
|
||||
|
||||
# Get weather data from the DarkSky API
|
||||
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 += str(long)+","+str(lat)+","+str(unixtime)
|
||||
|
||||
@@ -21,6 +20,7 @@ def get_weather_data(long,lat,unixtime):
|
||||
else:
|
||||
return 0
|
||||
|
||||
# Get wind data (and translate from knots to m/s)
|
||||
def get_wind_data(lat,long,unixtime):
|
||||
data = get_weather_data(lat,long,unixtime)
|
||||
if data:
|
||||
@@ -39,6 +39,7 @@ def get_wind_data(lat,long,unixtime):
|
||||
|
||||
try:
|
||||
temperature = data['currently']['temperature']
|
||||
# Temp is given in Fahrenheit, so convert to Celsius for Europeans
|
||||
temperaturec = (temperature-32.)*(5./9.)
|
||||
temperaturec = int(10*temperaturec)/10.
|
||||
except KeyError:
|
||||
@@ -54,7 +55,8 @@ def get_wind_data(lat,long,unixtime):
|
||||
windbearing = 0
|
||||
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 = 0.01*int(100*windspeed)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user