Read distance, calories, max_rpm, min_rpm, average_rpm etc from workout rather then recalculating on each render, still need to modify add workout endpoint to calculate properties and set on workout

This commit is contained in:
Peter Stockings
2023-07-29 20:24:41 +10:00
parent a4004c6e00
commit 2e37b1e22a

104
app.py
View File

@@ -14,6 +14,7 @@ import sparklines
app = Flask(__name__)
# TODO CHANGE SECRET KEY TO ENVIRONMENT VARIABLE
app.config['SECRET_KEY'] = 'secret!'
app.config["SQLALCHEMY_ECHO"] = False # True for debugging
uri = os.getenv("DATABASE_URL")
if uri and uri.startswith("postgres://"):
uri = uri.replace("postgres://", "postgresql://", 1)
@@ -50,8 +51,23 @@ class Workout(db.Model):
created_at = db.Column(db.DateTime, nullable=False, default=db.func.now())
bike_id = db.Column(db.Integer, db.ForeignKey(
'bikes.id', ondelete='CASCADE'), nullable=False)
started_at = db.Column(db.DateTime, nullable=False)
duration = db.Column(db.Numeric, nullable=False)
average_rpm = db.Column(db.Numeric, nullable=False)
min_rpm = db.Column(db.Integer, nullable=False)
max_rpm = db.Column(db.Integer, nullable=False)
calories = db.Column(db.Numeric, nullable=False)
distance = db.Column(db.Numeric, nullable=False)
average_bpm = db.Column(db.Numeric, nullable=False)
min_bpm = db.Column(db.Integer, nullable=False)
max_bpm = db.Column(db.Integer, nullable=False)
is_heart_rate_available = db.Column(
db.Boolean, nullable=False, default=False)
is_cadence_available = db.Column(db.Boolean, nullable=False, default=False)
cadence_readings = db.relationship(
'CadenceReading', backref='workout', lazy=True)
heart_rate_readings = db.relationship(
'HeartRateReading', backref='workout', lazy=True)
bike = db.relationship('Bike', backref='workouts', lazy=True)
@@ -154,38 +170,38 @@ def workouts(user_id):
@app.route('/user/<int:user_id>/workout/<int:workout_id>/<string:graph_type>', methods=['GET', 'DELETE'])
def workout(user_id, workout_id, graph_type):
workout = Workout.query.filter_by(user_id=user_id, id=workout_id).first()
if workout:
# Get the cadence readings for the workout
cadence_readings = CadenceReading.query.filter_by(
workout_id=workout_id).all()
if cadence_readings:
x_values = [reading.created_at for reading in cadence_readings]
workout = Workout.query.filter_by(user_id=user_id, id=workout_id).join(
Workout.cadence_readings).join(Workout.heart_rate_readings).first()
if not workout:
return jsonify({'message': 'Workout {} not found for user {}.'.format(workout_id, user_id)}), 404
if workout.is_cadence_available:
x_values = [reading.created_at for reading in workout.cadence_readings]
if graph_type == 'cadence':
y_values = [reading.rpm for reading in cadence_readings]
y_values = [reading.rpm for reading in workout.cadence_readings]
return create_graph(x_values=x_values, y_values=y_values, y_label='Cadence (RPM)', filename='cadence'), 200
elif graph_type == 'speed':
y_values = [reading.speed for reading in cadence_readings]
y_values = [reading.speed for reading in workout.cadence_readings]
return create_graph(x_values=x_values, y_values=y_values, y_label='Speed (KPH)', filename='speed'), 200
elif graph_type == 'distance':
y_values = [reading.distance for reading in cadence_readings]
y_values = [
reading.distance for reading in workout.cadence_readings]
return create_graph(x_values=x_values, y_values=y_values, y_label='Distance (KM)', filename='distance'), 200
elif graph_type == 'calories':
y_values = [reading.calories for reading in cadence_readings]
y_values = [
reading.calories for reading in workout.cadence_readings]
return create_graph(x_values=x_values, y_values=y_values, y_label='Calories (KCAL)', filename='calories'), 200
elif graph_type == 'power':
y_values = [reading.power for reading in cadence_readings]
y_values = [reading.power for reading in workout.cadence_readings]
return create_graph(x_values=x_values, y_values=y_values, y_label='Power (WATTS)', filename='power'), 200
heart_rate_readings = HeartRateReading.query.filter_by(
workout_id=workout_id).all()
if heart_rate_readings:
x_values = [reading.created_at for reading in heart_rate_readings]
y_values = [reading.bpm for reading in heart_rate_readings]
if workout.is_heart_rate_available:
x_values = [
reading.created_at for reading in workout.heart_rate_readings]
y_values = [reading.bpm for reading in workout.heart_rate_readings]
return create_graph(x_values=x_values, y_values=y_values, y_label='Heart Rate (BPM)', filename='heart_rate'), 200
else:
return jsonify({'message': 'No cadence readings for workout {}.'.format(workout_id)}), 404
else:
return jsonify({'message': 'Workout {} not found for user {}.'.format(workout_id, user_id)}), 404
return jsonify({'message': 'Unable to generate {} for workout {}.'.format(graph_type, workout_id)}), 409
@app.route('/user/<int:user_id>/workout/<int:workout_id>/view', methods=['GET'])
@@ -296,32 +312,28 @@ def get_workouts_for_user(user_id):
workouts_data = []
workouts = Workout.query.filter_by(user_id=user_id).order_by(
Workout.created_at.desc()).all()
for workout in workouts:
cadence_readings = CadenceReading.query.filter_by(
workout_id=workout.id).all()
if cadence_readings:
start_time = min(
reading.created_at for reading in cadence_readings)
end_time = max(
reading.created_at for reading in cadence_readings)
duration = end_time - start_time
average_rpm = sum(
reading.rpm for reading in cadence_readings) / len(cadence_readings)
calories = cadence_readings[-1].calories
distance = cadence_readings[-1].distance
for workout in workouts:
duration = timedelta(
seconds=int(workout.duration)) if workout.duration else timedelta(seconds=0)
average_rpm = workout.average_rpm if workout.average_rpm else 0
min_rpm = workout.min_rpm if workout.min_rpm else 0
max_rpm = workout.max_rpm if workout.max_rpm else 0
calories = workout.calories if workout.calories else 0
distance = workout.distance if workout.distance else 0
average_bpm = workout.average_bpm if workout.average_bpm else 0
min_bpm = workout.min_bpm if workout.min_bpm else 0
max_bpm = workout.max_bpm if workout.max_bpm else 0
is_heart_rate_available = workout.is_heart_rate_available
is_cadence_available = workout.is_cadence_available
start_time = workout.started_at
selected_graph_types = ['speed']
is_heart_rate_available = False
heart_rate_readings = HeartRateReading.query.filter_by(
workout_id=workout.id).all()
average_bpm = 0
if heart_rate_readings:
if is_heart_rate_available:
selected_graph_types.append('heart_rate')
is_heart_rate_available = True
average_bpm = sum(heartrate.bpm for heartrate in heart_rate_readings) / \
len(heart_rate_readings)
if is_cadence_available or is_heart_rate_available:
workouts_data.append({
'id': workout.id,
'user_id': user_id,
@@ -331,13 +343,19 @@ def get_workouts_for_user(user_id):
'duration': format_duration(duration),
'duration_minutes': duration.total_seconds() / 60,
'average_rpm': int(average_rpm),
'min_rpm': int(min_rpm),
'max_rpm': int(max_rpm),
'calories': int(calories),
'distance': int(distance),
'bike_display_name': workout.bike.display_name,
'selected_graph_types': selected_graph_types,
'is_heart_rate_available': is_heart_rate_available,
'average_bpm': int(average_bpm)
'is_cadence_available': is_cadence_available,
'average_bpm': int(average_bpm),
'min_bpm': int(min_bpm),
'max_bpm': int(max_bpm),
})
return workouts_data