|
|
const EventEmitter = require("events"); const createDriver = require("../drivers");
class Workout { /** * @param {import("../repositories/sqlite3")} repo * @param {number} id * @param {{ * id: string, * name: string, * driver: string, * connect: string, * maxLevel: number, * }} bike * @param {{ * id: number, * name: string, * cpm: number, * level: number, * warmupMin: number, * warmupCpm: number, * warmupLevel: number, * cooldownCpm: number, * cooldownLevel: number, * }} program * @param {Date} date */ constructor(repo, id, bike, program, date) { this.repo = repo; this.id = id; this.bike = bike; this.program = program; this.date = date; this.driver = null;
this.state = "disconnected";
this.offsetSeconds = 0; this.cooldownMin = -1; this.offsets = {};
this.events = new EventEmitter();
this.events.emit("state", this.state); }
async connect() { if (this.state !== "disconnected") { return Promise.resolve(); }
this.driver = createDriver(this.bike.driver, this.bike.connect); this.driver.events.on("workoutStatus", ws => this.handleworkoutStatus(ws));
return this.driver.connect().then((v) => { this.state = this.driver.state; this.events.emit("state", this.state); return v; }); }
start() { if (this.state === "started") { return Promise.resolve(); }
return this.driver.start().then((v) => { this.state = this.driver.state; this.events.emit("state", this.state); return v; }); }
pause() { if (this.state !== "started") { return Promise.resolve(); }
return this.driver.pause().then((v) => { this.state = this.driver.state; this.events.emit("state", this.state); return v; }); }
stop() { if (this.state === "started") { return Promise.resolve(); }
return this.driver.stop().then((v) => { this.state = this.driver.state; this.events.emit("state", this.state); return v; }); }
destroy() { this.events.emit("destroy"); this.events.removeAllListeners();
if (this.driver != null) { this.driver.destroy(); this.state = this.driver.state; this.events.emit("state", this.state); this.driver = null; } }
listMeasurements() { return this.repo.listMeasurements(this.id); }
handleworkoutStatus(ws) { if (this.offsetSeconds > 0) { const seconds = (ws.minutes * 60) + ws.seconds + this.offsetSeconds; ws.minutes = Math.floor(seconds / 60); ws.seconds = seconds % 60; for (const key in this.offsets) { if (!this.offsets.hasOwnProperty(key)) { continue; }
ws[key] += this.offsets[key]; } }
// Steer the level
let targetLevel = this.program.level; if (this.cooldownMin > -1 && ws.minutes >= this.cooldownMin) { targetLevel = this.program.cooldownLevel; } else if (this.program.warmupMin > ws.minutes) { targetLevel = this.program.warmupLevel; } if (targetLevel !== ws.level && this.state === "started") { this.driver.setLevel(targetLevel); }
this.repo.insertMeasurement({...ws, workoutId: this.id});
this.events.emit("workoutStatus", {...ws}); }
setCooldownMin(min) { this.cooldownMin = min; this.events.emit("cooldownMin", min); }
/** * @param {import("../repositories/sqlite3")} repo * @param {number} bikeId * @param {number} programId */ static async create(repo, bikeId, programId) { const bike = await repo.findBike(bikeId); if (bike == null) { throw new Error("bike not found"); } const program = await repo.findProgram(programId); if (program == null) { throw new Error("program not found"); }
const date = new Date(); const id = await repo.insertWorkout({ bikeId: bike.id, programId: program.id, date: date, cooldownMin: -1, });
return new Workout(repo, id, bike, program, date); }
/** * @param {import("../repositories/sqlite3")} repo * @param {number} id */ static async continue(repo, id) { const data = await repo.findWorkout(id); const bike = await repo.findBike(data.bikeId); const program = await repo.findProgram(data.programId);
const workout = new Workout(repo, id, bike, program, new Date(data.date)); workout.cooldownMin = data.cooldownMin;
const list = await repo.listMeasurements(id); if (list.length > 0) { const last = list[list.length - 1];
workout.offsetSeconds = (last.minutes * 60 + last.seconds); workout.offsets = { distance: last.distance, calories: last.calories, } }
return workout; } }
module.exports = Workout;
|