incyclist-services 1.1.95 → 1.1.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/devices/ride/service.d.ts +1 -0
- package/lib/devices/ride/service.js +23 -0
- package/lib/workouts/base/model/Segment.d.ts +4 -4
- package/lib/workouts/base/model/Segment.js +35 -30
- package/lib/workouts/base/model/Step.d.ts +8 -8
- package/lib/workouts/base/model/Step.js +21 -21
- package/lib/workouts/base/model/Workout.d.ts +1 -0
- package/lib/workouts/base/model/Workout.js +5 -0
- package/lib/workouts/list/cards/WorkoutCard.js +1 -1
- package/lib/workouts/list/loaders/db.d.ts +3 -3
- package/lib/workouts/list/loaders/db.js +48 -30
- package/lib/workouts/list/service.js +0 -1
- package/lib/workouts/ride/service.d.ts +7 -19
- package/lib/workouts/ride/service.js +103 -56
- package/lib/workouts/ride/types.d.ts +9 -0
- package/package.json +2 -2
|
@@ -55,6 +55,7 @@ export declare class DeviceRideService extends EventEmitter {
|
|
|
55
55
|
private getEnabledCapabilities;
|
|
56
56
|
sendUpdate(request: UpdateRequest): void;
|
|
57
57
|
getCyclingMode(udid?: string): CyclingMode;
|
|
58
|
+
resetCyclingMode(sendInit?: boolean): Promise<void>;
|
|
58
59
|
onCyclingModeChanged(udid: string, mode: string, settings: any): Promise<void>;
|
|
59
60
|
onDeviceDeleted(settings: IncyclistDeviceSettings): void;
|
|
60
61
|
enforceSimulator(enforced?: boolean): void;
|
|
@@ -852,6 +852,29 @@ class DeviceRideService extends events_1.default {
|
|
|
852
852
|
if (adapter)
|
|
853
853
|
return adapter.getCyclingMode();
|
|
854
854
|
}
|
|
855
|
+
resetCyclingMode(sendInit = false) {
|
|
856
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
857
|
+
try {
|
|
858
|
+
const adapters = this.getAdapterList();
|
|
859
|
+
const adapterInfo = adapters === null || adapters === void 0 ? void 0 : adapters.find(ai => ai.adapter.hasCapability(incyclist_devices_1.IncyclistCapability.Control));
|
|
860
|
+
if (!(adapterInfo === null || adapterInfo === void 0 ? void 0 : adapterInfo.adapter))
|
|
861
|
+
return;
|
|
862
|
+
const { udid, adapter } = adapterInfo;
|
|
863
|
+
const modeInfo = this.configurationService.getModeSettings(udid);
|
|
864
|
+
const mode = modeInfo === null || modeInfo === void 0 ? void 0 : modeInfo.mode;
|
|
865
|
+
const settings = modeInfo.settings;
|
|
866
|
+
if (adapter.getCyclingMode().getModeProperty('eppSupport'))
|
|
867
|
+
return;
|
|
868
|
+
const device = adapter;
|
|
869
|
+
device.setCyclingMode(mode, settings);
|
|
870
|
+
if (sendInit)
|
|
871
|
+
yield device.sendInitCommands();
|
|
872
|
+
}
|
|
873
|
+
catch (err) {
|
|
874
|
+
this.logEvent({ message: 'error', error: err.message, fn: 'resetCyclingMode' });
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
}
|
|
855
878
|
onCyclingModeChanged(udid, mode, settings) {
|
|
856
879
|
var _a;
|
|
857
880
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -7,12 +7,12 @@ export declare class Segment extends Step implements SegmentDefinition {
|
|
|
7
7
|
protected init(opts: SegmentDefinition, ignoreValidate: boolean): void;
|
|
8
8
|
validate(): void;
|
|
9
9
|
validateTiming(): boolean;
|
|
10
|
-
prepareNext(json: StepDefinition | SegmentDefinition): void;
|
|
11
|
-
push(s: any): void;
|
|
12
10
|
getDuration(): number;
|
|
13
|
-
getSingleDuration(): number;
|
|
14
11
|
getStart(): number;
|
|
15
12
|
getEnd(): number;
|
|
16
|
-
getStep(ts: number): Step;
|
|
17
13
|
getLimits(ts: any, includeStepInfo?: boolean): CurrentStep;
|
|
14
|
+
protected prepareNext(json: StepDefinition | SegmentDefinition): void;
|
|
15
|
+
push(s: any): void;
|
|
16
|
+
protected getSingleDuration(): number;
|
|
17
|
+
protected getStep(ts: number): Step;
|
|
18
18
|
}
|
|
@@ -63,6 +63,36 @@ class Segment extends Step_1.Step {
|
|
|
63
63
|
});
|
|
64
64
|
return true;
|
|
65
65
|
}
|
|
66
|
+
getDuration() {
|
|
67
|
+
return this.getSingleDuration() * this.repeat;
|
|
68
|
+
}
|
|
69
|
+
getStart() {
|
|
70
|
+
if (this.start !== undefined)
|
|
71
|
+
return this.start;
|
|
72
|
+
else {
|
|
73
|
+
if (this.steps.length > 0)
|
|
74
|
+
return this.steps[0].start;
|
|
75
|
+
else
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
getEnd() {
|
|
80
|
+
return this.getStart() + this.getDuration();
|
|
81
|
+
}
|
|
82
|
+
getLimits(ts, includeStepInfo = false) {
|
|
83
|
+
const step = this.getStep(ts);
|
|
84
|
+
if (step === undefined)
|
|
85
|
+
return undefined;
|
|
86
|
+
const segTime = ts - this.getStart();
|
|
87
|
+
const stepDuration = this.getSingleDuration();
|
|
88
|
+
let part = (segTime % stepDuration);
|
|
89
|
+
if (part === stepDuration)
|
|
90
|
+
part = 0;
|
|
91
|
+
part += this.getStart();
|
|
92
|
+
if (part === this.getStart() && segTime > 0 && segTime < stepDuration)
|
|
93
|
+
part += stepDuration;
|
|
94
|
+
return step.getLimits(part, includeStepInfo);
|
|
95
|
+
}
|
|
66
96
|
prepareNext(json) {
|
|
67
97
|
if (json === undefined)
|
|
68
98
|
return;
|
|
@@ -88,50 +118,25 @@ class Segment extends Step_1.Step {
|
|
|
88
118
|
this.end = this.start + this.duration;
|
|
89
119
|
this.validate();
|
|
90
120
|
}
|
|
91
|
-
getDuration() {
|
|
92
|
-
return this.getSingleDuration() * this.repeat;
|
|
93
|
-
}
|
|
94
121
|
getSingleDuration() {
|
|
95
122
|
if (this.steps.length === 0)
|
|
96
123
|
return 0;
|
|
97
124
|
return this.steps.map(s => s.duration).reduce((a, b) => a + b);
|
|
98
125
|
}
|
|
99
|
-
getStart() {
|
|
100
|
-
if (this.start !== undefined)
|
|
101
|
-
return this.start;
|
|
102
|
-
else {
|
|
103
|
-
if (this.steps.length > 0)
|
|
104
|
-
return this.steps[0].start;
|
|
105
|
-
else
|
|
106
|
-
return undefined;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
getEnd() {
|
|
110
|
-
return this.getStart() + this.getDuration();
|
|
111
|
-
}
|
|
112
126
|
getStep(ts) {
|
|
113
|
-
if (ts >= this.getStart() && ts
|
|
127
|
+
if (ts >= this.getStart() && ts < this.getEnd()) {
|
|
114
128
|
const segTime = ts - this.getStart();
|
|
115
129
|
let part = (segTime % this.getSingleDuration());
|
|
130
|
+
if (part === this.getSingleDuration())
|
|
131
|
+
part = 0;
|
|
116
132
|
part += this.getStart();
|
|
117
|
-
if (part === this.getStart() && segTime > 0)
|
|
133
|
+
if (part === this.getStart() && segTime > 0 && segTime < this.getSingleDuration())
|
|
118
134
|
part += this.getSingleDuration();
|
|
119
135
|
const found = this.steps.find(s => {
|
|
120
|
-
return (part >= s.start && part
|
|
136
|
+
return (part >= s.start && part < s.end);
|
|
121
137
|
});
|
|
122
138
|
return found;
|
|
123
139
|
}
|
|
124
140
|
}
|
|
125
|
-
getLimits(ts, includeStepInfo = false) {
|
|
126
|
-
const step = this.getStep(ts);
|
|
127
|
-
if (step === undefined)
|
|
128
|
-
return undefined;
|
|
129
|
-
const segTime = ts - this.getStart();
|
|
130
|
-
let part = (segTime % this.getSingleDuration());
|
|
131
|
-
part += this.getStart();
|
|
132
|
-
if (part === this.getStart() && segTime > 0)
|
|
133
|
-
part += this.getSingleDuration();
|
|
134
|
-
return step.getLimits(part, includeStepInfo);
|
|
135
|
-
}
|
|
136
141
|
}
|
|
137
142
|
exports.Segment = Segment;
|
|
@@ -15,7 +15,7 @@ export declare class Step implements StepDefinition {
|
|
|
15
15
|
power?: PowerLimit;
|
|
16
16
|
cadence?: Limit;
|
|
17
17
|
hrm?: Limit;
|
|
18
|
-
text
|
|
18
|
+
text?: string;
|
|
19
19
|
work: boolean;
|
|
20
20
|
steady: boolean;
|
|
21
21
|
cooldown: boolean;
|
|
@@ -24,12 +24,12 @@ export declare class Step implements StepDefinition {
|
|
|
24
24
|
getDuration(): number;
|
|
25
25
|
getStart(): number;
|
|
26
26
|
getEnd(): number;
|
|
27
|
-
validateTiming(): boolean;
|
|
28
|
-
validateLimit(p: Limit, name: string): boolean;
|
|
29
|
-
validatePower(): boolean;
|
|
30
|
-
validateCadence(): boolean;
|
|
31
|
-
validateHrm(): boolean;
|
|
32
27
|
getLimits(ts: number, includeStepInfo?: boolean): CurrentStep;
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
validateTiming(): boolean;
|
|
29
|
+
protected validateLimit(p: Limit, name: string): boolean;
|
|
30
|
+
protected validatePower(): boolean;
|
|
31
|
+
protected validateCadence(): boolean;
|
|
32
|
+
protected validateHrm(): boolean;
|
|
33
|
+
protected getRemainder(limits: CurrentStep, includeStepInfo?: boolean): CurrentStep;
|
|
34
|
+
protected calc(ts: any, limit: any, includeStepInfo: boolean, isPower?: boolean): {};
|
|
35
35
|
}
|
|
@@ -41,6 +41,27 @@ class Step {
|
|
|
41
41
|
getDuration() { return this.duration; }
|
|
42
42
|
getStart() { return this.start; }
|
|
43
43
|
getEnd() { return this.end; }
|
|
44
|
+
getLimits(ts, includeStepInfo = false) {
|
|
45
|
+
const rv = (limits) => this.getRemainder(limits, includeStepInfo);
|
|
46
|
+
if (ts >= this.start && ts <= this.end) {
|
|
47
|
+
const duration = this.duration;
|
|
48
|
+
const remaining = this.end - ts;
|
|
49
|
+
if (this.steady) {
|
|
50
|
+
const { power, cadence, hrm, text, work } = this;
|
|
51
|
+
return rv({ power, cadence, hrm, text, work, duration, remaining });
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const { text, work } = this;
|
|
55
|
+
const power = this.calc(ts, this.power, includeStepInfo, true);
|
|
56
|
+
const cadence = this.calc(ts, this.cadence, includeStepInfo);
|
|
57
|
+
const hrm = this.calc(ts, this.hrm, includeStepInfo);
|
|
58
|
+
return rv({ power, cadence, hrm, text, work, duration, remaining });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
44
65
|
validateTiming() {
|
|
45
66
|
if (this.start === undefined && this.end === undefined) {
|
|
46
67
|
throw new Error(`Invalid Step description, start or end needs to be provided `);
|
|
@@ -94,27 +115,6 @@ class Step {
|
|
|
94
115
|
validateHrm() {
|
|
95
116
|
return this.validateLimit(this.hrm, 'hrm');
|
|
96
117
|
}
|
|
97
|
-
getLimits(ts, includeStepInfo = false) {
|
|
98
|
-
const rv = (limits) => this.getRemainder(limits, includeStepInfo);
|
|
99
|
-
if (ts >= this.start && ts <= this.end) {
|
|
100
|
-
const duration = this.duration;
|
|
101
|
-
const remaining = this.end - ts;
|
|
102
|
-
if (this.steady) {
|
|
103
|
-
const { power, cadence, hrm, text, work } = this;
|
|
104
|
-
return rv({ power, cadence, hrm, text, work, duration, remaining });
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
const { text, work } = this;
|
|
108
|
-
const power = this.calc(ts, this.power, includeStepInfo, true);
|
|
109
|
-
const cadence = this.calc(ts, this.cadence, includeStepInfo);
|
|
110
|
-
const hrm = this.calc(ts, this.hrm, includeStepInfo);
|
|
111
|
-
return rv({ power, cadence, hrm, text, work, duration, remaining });
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
return undefined;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
118
|
getRemainder(limits, includeStepInfo = false) {
|
|
119
119
|
if (limits === undefined)
|
|
120
120
|
return;
|
|
@@ -8,6 +8,7 @@ export declare class Workout extends Segment implements WorkoutDefinition {
|
|
|
8
8
|
category?: Category;
|
|
9
9
|
constructor(opts: WorkoutDefinition);
|
|
10
10
|
get hash(): string;
|
|
11
|
+
getSegment(time: number): Segment;
|
|
11
12
|
addStep(step: StepDefinition): void;
|
|
12
13
|
addSegment(segment: SegmentDefinition): void;
|
|
13
14
|
}
|
|
@@ -39,6 +39,11 @@ class Workout extends Segment_1.Segment {
|
|
|
39
39
|
this._hash = (0, md5_1.default)(JSON.stringify({ name, description, steps, repeat }));
|
|
40
40
|
return this._hash;
|
|
41
41
|
}
|
|
42
|
+
getSegment(time) {
|
|
43
|
+
const s = this.steps.find(s => s.getStart() <= time && s.getEnd() > time);
|
|
44
|
+
if (s.type === 'segment')
|
|
45
|
+
return s;
|
|
46
|
+
}
|
|
42
47
|
addStep(step) {
|
|
43
48
|
if ((0, valid_1.valid)(step)) {
|
|
44
49
|
if (step.duration === undefined && step.start === undefined && step.end === undefined)
|
|
@@ -187,7 +187,7 @@ class WorkoutCard extends base_1.BaseCard {
|
|
|
187
187
|
return `${duration / 60}min`;
|
|
188
188
|
const secVal = duration % 60;
|
|
189
189
|
const minVal = (duration - secVal) / 60 % 60;
|
|
190
|
-
const h = (duration - secVal - minVal * 60) /
|
|
190
|
+
const h = Math.floor((duration - secVal - minVal * 60) / 3600);
|
|
191
191
|
const sec = secVal < 10 ? `0${secVal}` : secVal;
|
|
192
192
|
const min = minVal < 10 ? `0${minVal}` : minVal;
|
|
193
193
|
if (h > 0)
|
|
@@ -16,12 +16,12 @@ export declare class WorkoutsDbLoader extends Loader {
|
|
|
16
16
|
constructor();
|
|
17
17
|
load(): Observer;
|
|
18
18
|
stopLoad(): void;
|
|
19
|
-
protected getRepo(): JsonRepository;
|
|
20
|
-
protected _load(): Promise<void>;
|
|
21
19
|
save(workout: Workout | Plan): Promise<void>;
|
|
22
20
|
delete(workout: Workout | Plan): Promise<void>;
|
|
21
|
+
protected getRepo(): JsonRepository;
|
|
22
|
+
protected _load(): Promise<void>;
|
|
23
23
|
protected writeRepo(): Promise<void>;
|
|
24
|
-
protected write(): void;
|
|
24
|
+
protected write(enforced?: boolean): void;
|
|
25
25
|
protected emitUpdated(workout: Workout | Plan): void;
|
|
26
26
|
protected emitAdded(workout: Workout | Plan): void;
|
|
27
27
|
protected emitDone(): void;
|
|
@@ -55,6 +55,7 @@ const loader_1 = require("./loader");
|
|
|
55
55
|
const Workout_1 = require("../../base/model/Workout");
|
|
56
56
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
57
57
|
const utils_1 = require("../../../utils");
|
|
58
|
+
const valid_1 = require("../../../utils/valid");
|
|
58
59
|
let WorkoutsDbLoader = (() => {
|
|
59
60
|
let _classDecorators = [types_1.Singleton];
|
|
60
61
|
let _classDescriptor;
|
|
@@ -77,41 +78,36 @@ let WorkoutsDbLoader = (() => {
|
|
|
77
78
|
return this.loadObserver;
|
|
78
79
|
}
|
|
79
80
|
stopLoad() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
_load() {
|
|
88
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
-
const workouts = yield this.getRepo().read('db');
|
|
90
|
-
if (workouts) {
|
|
91
|
-
const items = workouts;
|
|
92
|
-
items.forEach(item => {
|
|
93
|
-
const workout = new Workout_1.Workout(item);
|
|
94
|
-
this.workouts.push(workout);
|
|
95
|
-
this.emitAdded(workout);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
this.emitDone();
|
|
99
|
-
});
|
|
81
|
+
if (this.loadObserver) {
|
|
82
|
+
this.loadObserver.emit('done');
|
|
83
|
+
(0, utils_1.waitNextTick)().then(() => {
|
|
84
|
+
delete this.loadObserver;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
100
87
|
}
|
|
101
88
|
save(workout) {
|
|
102
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
if (!(0, valid_1.valid)(workout))
|
|
91
|
+
return;
|
|
92
|
+
const stringify = (json) => {
|
|
93
|
+
try {
|
|
94
|
+
return JSON.stringify(json);
|
|
95
|
+
}
|
|
96
|
+
catch (_a) {
|
|
97
|
+
}
|
|
98
|
+
};
|
|
107
99
|
let prev;
|
|
108
100
|
const idx = this.workouts.findIndex(d => d.id === workout.id);
|
|
109
|
-
|
|
101
|
+
let changed = false;
|
|
102
|
+
if (idx === -1) {
|
|
103
|
+
changed = true;
|
|
110
104
|
this.workouts.push(workout);
|
|
105
|
+
}
|
|
111
106
|
else {
|
|
107
|
+
prev = stringify(Object.assign({}, this.workouts[idx]));
|
|
112
108
|
this.workouts[idx] = workout;
|
|
109
|
+
changed = stringify(Object.assign({}, this.workouts[idx])) !== prev;
|
|
113
110
|
}
|
|
114
|
-
const changed = !prev || stringify(this.workouts) !== prev;
|
|
115
111
|
if (changed) {
|
|
116
112
|
this.isDirty = true;
|
|
117
113
|
this.write();
|
|
@@ -129,13 +125,32 @@ let WorkoutsDbLoader = (() => {
|
|
|
129
125
|
yield this.write();
|
|
130
126
|
});
|
|
131
127
|
}
|
|
128
|
+
getRepo() {
|
|
129
|
+
if (!this.repo)
|
|
130
|
+
this.repo = api_1.JsonRepository.create('workouts');
|
|
131
|
+
return this.repo;
|
|
132
|
+
}
|
|
133
|
+
_load() {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
+
const workouts = yield this.getRepo().read('db');
|
|
136
|
+
if (workouts) {
|
|
137
|
+
const items = workouts;
|
|
138
|
+
items.forEach(item => {
|
|
139
|
+
const workout = new Workout_1.Workout(item);
|
|
140
|
+
this.workouts.push(workout);
|
|
141
|
+
this.emitAdded(workout);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
this.emitDone();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
132
147
|
writeRepo() {
|
|
133
148
|
return __awaiter(this, void 0, void 0, function* () {
|
|
134
149
|
if (this.saveObserver)
|
|
135
150
|
yield this.saveObserver.wait();
|
|
136
151
|
const save = () => __awaiter(this, void 0, void 0, function* () {
|
|
137
152
|
try {
|
|
138
|
-
yield this.
|
|
153
|
+
yield this.getRepo().write('db', this.workouts);
|
|
139
154
|
}
|
|
140
155
|
catch (err) {
|
|
141
156
|
this.logger.logEvent({ message: 'could not safe repo', error: err.message });
|
|
@@ -146,14 +161,17 @@ let WorkoutsDbLoader = (() => {
|
|
|
146
161
|
process.nextTick(() => { delete this.saveObserver; });
|
|
147
162
|
});
|
|
148
163
|
}
|
|
149
|
-
write() {
|
|
150
|
-
if (this.isDirty && (this.tsLastWrite === undefined || Date.now() - this.tsLastWrite >= 1000)) {
|
|
164
|
+
write(enforced = false) {
|
|
165
|
+
if (enforced || (this.isDirty && (this.tsLastWrite === undefined || Date.now() - this.tsLastWrite >= 1000))) {
|
|
151
166
|
this.isDirty = false;
|
|
152
167
|
this.tsLastWrite = Date.now();
|
|
153
168
|
this.writeRepo();
|
|
154
169
|
}
|
|
155
170
|
if (this.isDirty && Date.now() - this.tsLastWrite < 1000) {
|
|
156
|
-
|
|
171
|
+
const delayUntilNextWrite = this.tsLastWrite + 1000 - Date.now();
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
this.write(true);
|
|
174
|
+
}, delayUntilNextWrite);
|
|
157
175
|
}
|
|
158
176
|
}
|
|
159
177
|
emitUpdated(workout) {
|
|
@@ -4,6 +4,7 @@ import { Observer } from "../../base/types/observer";
|
|
|
4
4
|
import { PowerLimit, Workout } from "../base/model";
|
|
5
5
|
import { WorkoutListService } from "../list";
|
|
6
6
|
import { WorkoutSettings } from "../list/cards/types";
|
|
7
|
+
import { ActiveWorkoutLimit, WorkoutDisplayProperties } from "./types";
|
|
7
8
|
export declare class WorkoutRide extends IncyclistService {
|
|
8
9
|
protected manualTimeOffset: number;
|
|
9
10
|
protected manualPowerOffset: number;
|
|
@@ -17,9 +18,8 @@ export declare class WorkoutRide extends IncyclistService {
|
|
|
17
18
|
protected tsPauseStart: number;
|
|
18
19
|
protected tsCurrent: number;
|
|
19
20
|
protected trainingTime: number;
|
|
20
|
-
protected currentLimits:
|
|
21
|
+
protected currentLimits: ActiveWorkoutLimit;
|
|
21
22
|
protected updateInterval: NodeJS.Timeout;
|
|
22
|
-
protected id: any;
|
|
23
23
|
constructor();
|
|
24
24
|
init(): Observer;
|
|
25
25
|
start(paused?: boolean): Workout;
|
|
@@ -30,37 +30,25 @@ export declare class WorkoutRide extends IncyclistService {
|
|
|
30
30
|
backward(): void;
|
|
31
31
|
powerUp(delta: number): void;
|
|
32
32
|
powerDown(delta: number): void;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
workout?: undefined;
|
|
36
|
-
title?: undefined;
|
|
37
|
-
ftp?: undefined;
|
|
38
|
-
current?: undefined;
|
|
39
|
-
start?: undefined;
|
|
40
|
-
stop?: undefined;
|
|
41
|
-
} | {
|
|
42
|
-
workout: Workout;
|
|
43
|
-
title: string;
|
|
44
|
-
ftp: number;
|
|
45
|
-
current: any;
|
|
46
|
-
start: any;
|
|
47
|
-
stop: any;
|
|
48
|
-
};
|
|
33
|
+
getDashboardDisplayProperties(): WorkoutDisplayProperties;
|
|
34
|
+
getCurrentLimits(): ActiveWorkoutLimit;
|
|
49
35
|
inUse(): boolean;
|
|
50
36
|
isActive(): boolean;
|
|
51
37
|
getWorkout(): Workout;
|
|
52
38
|
getObserver(): Observer;
|
|
39
|
+
protected update(startIfInitialized?: boolean): void;
|
|
53
40
|
protected resetTimes(): void;
|
|
54
41
|
protected setCurrentLimits(trainingTime?: number): void;
|
|
55
42
|
protected getZoomParameters(time: number): {
|
|
56
43
|
start: any;
|
|
57
44
|
stop: any;
|
|
58
45
|
};
|
|
46
|
+
protected getStepTitle(time: number): string;
|
|
59
47
|
protected getPowerVal(power: PowerLimit, key: 'min' | 'max'): number;
|
|
60
|
-
protected getTime(): number;
|
|
61
48
|
protected getFtpFromUserSettings(): any;
|
|
62
49
|
protected resetWorkout(): void;
|
|
63
50
|
emit(eventName: string, ...args: any[]): boolean;
|
|
51
|
+
protected stopWorker(): void;
|
|
64
52
|
}
|
|
65
53
|
export declare const useWorkoutRide: () => WorkoutRide;
|
|
66
54
|
export declare const getWorkoutRide: () => WorkoutRide;
|
|
@@ -48,7 +48,6 @@ const valid_1 = require("../../utils/valid");
|
|
|
48
48
|
const list_1 = require("../list");
|
|
49
49
|
const DEFAULT_FTP = 200;
|
|
50
50
|
const WORKOUT_ZOOM = 1200;
|
|
51
|
-
let _instance = 0;
|
|
52
51
|
let WorkoutRide = (() => {
|
|
53
52
|
let _classDecorators = [types_1.Singleton];
|
|
54
53
|
let _classDescriptor;
|
|
@@ -59,17 +58,16 @@ let WorkoutRide = (() => {
|
|
|
59
58
|
constructor() {
|
|
60
59
|
super('WorkoutRide');
|
|
61
60
|
this.state = 'idle';
|
|
62
|
-
this.id = _instance++;
|
|
63
61
|
}
|
|
64
62
|
init() {
|
|
65
63
|
var _a, _b;
|
|
66
64
|
try {
|
|
67
65
|
this.workoutList = (0, list_1.getWorkoutList)();
|
|
68
|
-
this.resetTimes();
|
|
69
|
-
this.manualPowerOffset = 0;
|
|
70
66
|
this.workout = this.workoutList.getSelected();
|
|
71
67
|
if (!this.workout)
|
|
72
68
|
return;
|
|
69
|
+
this.resetTimes();
|
|
70
|
+
this.manualPowerOffset = 0;
|
|
73
71
|
this.settings = (_a = this.workoutList.getStartSettings()) !== null && _a !== void 0 ? _a : {};
|
|
74
72
|
if (!(0, valid_1.valid)(this.settings.ftp)) {
|
|
75
73
|
this.settings.ftp = (_b = this.getFtpFromUserSettings()) !== null && _b !== void 0 ? _b : 200;
|
|
@@ -90,7 +88,7 @@ let WorkoutRide = (() => {
|
|
|
90
88
|
}
|
|
91
89
|
start(paused = false) {
|
|
92
90
|
try {
|
|
93
|
-
if (this.state !== 'initialized') {
|
|
91
|
+
if (this.state !== 'initialized' || !this.workout) {
|
|
94
92
|
return;
|
|
95
93
|
}
|
|
96
94
|
this.state = 'active';
|
|
@@ -102,6 +100,7 @@ let WorkoutRide = (() => {
|
|
|
102
100
|
this.emit('started');
|
|
103
101
|
this.logEvent({ message: 'workout started', settings: this.settings });
|
|
104
102
|
if (!this.updateInterval) {
|
|
103
|
+
this.update();
|
|
105
104
|
this.updateInterval = setInterval(() => { this.update(); }, 500);
|
|
106
105
|
}
|
|
107
106
|
if (paused)
|
|
@@ -131,6 +130,7 @@ let WorkoutRide = (() => {
|
|
|
131
130
|
resume() {
|
|
132
131
|
try {
|
|
133
132
|
if (this.state === 'initialized' || this.state === 'completed') {
|
|
133
|
+
this.state = 'initialized';
|
|
134
134
|
this.start();
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
@@ -152,13 +152,12 @@ let WorkoutRide = (() => {
|
|
|
152
152
|
}
|
|
153
153
|
stop() {
|
|
154
154
|
try {
|
|
155
|
+
if (!this.workout || this.state === 'idle')
|
|
156
|
+
return;
|
|
155
157
|
this.state = 'completed';
|
|
156
158
|
this.logger.logEvent({ message: 'workout completed' });
|
|
157
159
|
this.emit('completed');
|
|
158
|
-
|
|
159
|
-
clearInterval(this.updateInterval);
|
|
160
|
-
this.updateInterval = undefined;
|
|
161
|
-
}
|
|
160
|
+
this.stopWorker();
|
|
162
161
|
(0, utils_1.waitNextTick)()
|
|
163
162
|
.then(() => { this.resetWorkout(); });
|
|
164
163
|
}
|
|
@@ -168,10 +167,11 @@ let WorkoutRide = (() => {
|
|
|
168
167
|
}
|
|
169
168
|
forward() {
|
|
170
169
|
try {
|
|
171
|
-
const ts = this.
|
|
170
|
+
const ts = this.trainingTime;
|
|
172
171
|
const wo = this.workout;
|
|
173
172
|
const limits = wo.getLimits(ts);
|
|
174
173
|
this.manualTimeOffset += limits.remaining;
|
|
174
|
+
this.update();
|
|
175
175
|
}
|
|
176
176
|
catch (err) {
|
|
177
177
|
this.logError(err, 'forward');
|
|
@@ -179,26 +179,40 @@ let WorkoutRide = (() => {
|
|
|
179
179
|
}
|
|
180
180
|
backward() {
|
|
181
181
|
try {
|
|
182
|
-
const ts = this.
|
|
182
|
+
const ts = this.trainingTime;
|
|
183
183
|
const wo = this.workout;
|
|
184
184
|
const limits = wo.getLimits(ts);
|
|
185
185
|
const completed = limits.duration - limits.remaining;
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
this.manualTimeOffset -= (completed + prevLimits.duration);
|
|
186
|
+
const stepBusyLmit = Math.min(15, limits.duration / 2);
|
|
187
|
+
if (completed >= stepBusyLmit) {
|
|
188
|
+
this.manualTimeOffset -= completed;
|
|
190
189
|
}
|
|
190
|
+
else {
|
|
191
|
+
const timePrev = ts - completed - 0.1;
|
|
192
|
+
if (timePrev < 0) {
|
|
193
|
+
this.manualTimeOffset -= completed;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
const prevLimits = wo.getLimits(timePrev);
|
|
197
|
+
if (prevLimits) {
|
|
198
|
+
this.manualTimeOffset -= (completed + prevLimits.duration);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
this.update();
|
|
191
203
|
}
|
|
192
204
|
catch (err) {
|
|
193
205
|
this.logError(err, 'backward');
|
|
194
206
|
}
|
|
195
207
|
}
|
|
196
208
|
powerUp(delta) {
|
|
209
|
+
var _a;
|
|
197
210
|
try {
|
|
198
|
-
if (this.settings.ftp)
|
|
211
|
+
if ((_a = this.settings) === null || _a === void 0 ? void 0 : _a.ftp) {
|
|
199
212
|
this.settings.ftp = this.settings.ftp * (1 + delta / 100);
|
|
213
|
+
this.workoutList.setStartSettings(this.settings);
|
|
214
|
+
}
|
|
200
215
|
this.manualPowerOffset += delta;
|
|
201
|
-
this.workoutList.setStartSettings(this.settings);
|
|
202
216
|
this.setCurrentLimits();
|
|
203
217
|
this.emit('update', this.getDashboardDisplayProperties());
|
|
204
218
|
}
|
|
@@ -207,11 +221,13 @@ let WorkoutRide = (() => {
|
|
|
207
221
|
}
|
|
208
222
|
}
|
|
209
223
|
powerDown(delta) {
|
|
224
|
+
var _a;
|
|
210
225
|
try {
|
|
211
|
-
if (this.settings.ftp)
|
|
226
|
+
if ((_a = this.settings) === null || _a === void 0 ? void 0 : _a.ftp) {
|
|
212
227
|
this.settings.ftp = this.settings.ftp / (1 + delta / 100);
|
|
228
|
+
this.workoutList.setStartSettings(this.settings);
|
|
229
|
+
}
|
|
213
230
|
this.manualPowerOffset -= delta;
|
|
214
|
-
this.workoutList.setStartSettings(this.settings);
|
|
215
231
|
this.setCurrentLimits();
|
|
216
232
|
this.emit('update', this.getDashboardDisplayProperties());
|
|
217
233
|
}
|
|
@@ -219,47 +235,32 @@ let WorkoutRide = (() => {
|
|
|
219
235
|
this.logError(err, 'powerDown');
|
|
220
236
|
}
|
|
221
237
|
}
|
|
222
|
-
update(startIfInitialized = false) {
|
|
223
|
-
var _a, _b;
|
|
224
|
-
try {
|
|
225
|
-
const prevTime = Math.round(this.currentLimits.time);
|
|
226
|
-
if (startIfInitialized && this.state === 'initialized') {
|
|
227
|
-
this.start();
|
|
228
|
-
}
|
|
229
|
-
else if (this.state !== 'active')
|
|
230
|
-
return;
|
|
231
|
-
const time = (_b = ((_a = Date.now() - this.tsStart - this.offset) !== null && _a !== void 0 ? _a : 0) / 1000 + this.manualTimeOffset) !== null && _b !== void 0 ? _b : 0;
|
|
232
|
-
const end = this.workout.getEnd();
|
|
233
|
-
if (time > end) {
|
|
234
|
-
this.stop();
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
this.setCurrentLimits(time);
|
|
238
|
-
if (Math.round(time) !== prevTime)
|
|
239
|
-
this.emit('update', this.getDashboardDisplayProperties());
|
|
240
|
-
}
|
|
241
|
-
catch (err) {
|
|
242
|
-
this.logError(err, 'update');
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
238
|
getDashboardDisplayProperties() {
|
|
246
239
|
try {
|
|
247
240
|
if (this.state === 'idle' || this.state === 'completed') {
|
|
248
241
|
return {};
|
|
249
242
|
}
|
|
250
243
|
const { start, stop } = this.getZoomParameters(this.trainingTime);
|
|
251
|
-
|
|
252
|
-
|
|
244
|
+
const title = this.getStepTitle(this.trainingTime);
|
|
245
|
+
const props = {
|
|
246
|
+
workout: this.workout, title,
|
|
253
247
|
ftp: this.settings.ftp,
|
|
254
248
|
current: this.currentLimits,
|
|
255
249
|
start, stop
|
|
256
250
|
};
|
|
251
|
+
return props;
|
|
257
252
|
}
|
|
258
253
|
catch (err) {
|
|
259
254
|
this.logError(err, 'getDashboardDisplayProperties');
|
|
260
255
|
return {};
|
|
261
256
|
}
|
|
262
257
|
}
|
|
258
|
+
getCurrentLimits() {
|
|
259
|
+
if (this.state === 'idle' || this.state === 'completed') {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
return this.currentLimits;
|
|
263
|
+
}
|
|
263
264
|
inUse() {
|
|
264
265
|
return this.state !== 'idle' && this.state !== 'completed';
|
|
265
266
|
}
|
|
@@ -276,12 +277,37 @@ let WorkoutRide = (() => {
|
|
|
276
277
|
return undefined;
|
|
277
278
|
return this.observer;
|
|
278
279
|
}
|
|
280
|
+
update(startIfInitialized = false) {
|
|
281
|
+
var _a, _b, _c, _d;
|
|
282
|
+
if (!this.workout)
|
|
283
|
+
return;
|
|
284
|
+
try {
|
|
285
|
+
const prevTime = Math.round((_b = (_a = this.currentLimits) === null || _a === void 0 ? void 0 : _a.time) !== null && _b !== void 0 ? _b : 0);
|
|
286
|
+
if (startIfInitialized && this.state === 'initialized') {
|
|
287
|
+
this.start();
|
|
288
|
+
}
|
|
289
|
+
else if (this.state !== 'active')
|
|
290
|
+
return;
|
|
291
|
+
const time = (_d = ((_c = Date.now() - this.tsStart - this.offset) !== null && _c !== void 0 ? _c : 0) / 1000 + this.manualTimeOffset) !== null && _d !== void 0 ? _d : 0;
|
|
292
|
+
const end = this.workout.getEnd();
|
|
293
|
+
if (time >= end) {
|
|
294
|
+
this.stop();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
this.setCurrentLimits(time);
|
|
298
|
+
if (Math.round(time) !== prevTime)
|
|
299
|
+
this.emit('update', this.getDashboardDisplayProperties());
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
this.logError(err, 'update');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
279
305
|
resetTimes() {
|
|
280
306
|
this.manualTimeOffset = 0;
|
|
281
307
|
this.tsStart = undefined;
|
|
282
308
|
this.tsCurrent = undefined;
|
|
283
309
|
this.tsPauseStart = undefined;
|
|
284
|
-
this.offset =
|
|
310
|
+
this.offset = 0;
|
|
285
311
|
}
|
|
286
312
|
setCurrentLimits(trainingTime) {
|
|
287
313
|
var _a, _b, _c, _d;
|
|
@@ -293,7 +319,7 @@ let WorkoutRide = (() => {
|
|
|
293
319
|
const limits = wo.getLimits(time);
|
|
294
320
|
const request = { time: 0, duration: 0, remaining: 0 };
|
|
295
321
|
if (limits !== undefined) {
|
|
296
|
-
request.time = time;
|
|
322
|
+
request.time = Math.round(time);
|
|
297
323
|
request.minPower = this.getPowerVal(limits.power, 'min');
|
|
298
324
|
request.maxPower = this.getPowerVal(limits.power, 'max');
|
|
299
325
|
request.minCadence = ((_a = limits === null || limits === void 0 ? void 0 : limits.cadence) === null || _a === void 0 ? void 0 : _a.min) ? Math.round(limits.cadence.min) : undefined;
|
|
@@ -318,6 +344,31 @@ let WorkoutRide = (() => {
|
|
|
318
344
|
}
|
|
319
345
|
return { start, stop };
|
|
320
346
|
}
|
|
347
|
+
getStepTitle(time) {
|
|
348
|
+
if (!this.workout)
|
|
349
|
+
return;
|
|
350
|
+
let title = this.workout.name;
|
|
351
|
+
const limit = this.workout.getLimits(time, true);
|
|
352
|
+
const segment = this.workout.getSegment(time);
|
|
353
|
+
let ch = ': ';
|
|
354
|
+
if (segment && segment.text) {
|
|
355
|
+
title += `${ch}${segment.text}`;
|
|
356
|
+
ch = ' - ';
|
|
357
|
+
}
|
|
358
|
+
if (segment && segment.text && segment.repeat > 0) {
|
|
359
|
+
const repeatTime = segment.duration / segment.repeat;
|
|
360
|
+
const repeatCount = Math.floor((time - segment.getStart()) / repeatTime) + 1;
|
|
361
|
+
title += `(${repeatCount}/${segment.repeat})`;
|
|
362
|
+
}
|
|
363
|
+
if (limit.text)
|
|
364
|
+
title += `${ch}${limit.text}`;
|
|
365
|
+
if (limit.text && segment && !segment.text && segment.repeat > 0) {
|
|
366
|
+
const repeatTime = segment.duration / segment.repeat;
|
|
367
|
+
const repeatCount = Math.floor((time - segment.getStart()) / repeatTime) + 1;
|
|
368
|
+
title += `(${repeatCount}/${segment.repeat})`;
|
|
369
|
+
}
|
|
370
|
+
return title;
|
|
371
|
+
}
|
|
321
372
|
getPowerVal(power, key) {
|
|
322
373
|
var _a, _b;
|
|
323
374
|
if (power === undefined)
|
|
@@ -333,16 +384,6 @@ let WorkoutRide = (() => {
|
|
|
333
384
|
}
|
|
334
385
|
return Math.round(val + this.manualPowerOffset);
|
|
335
386
|
}
|
|
336
|
-
getTime() {
|
|
337
|
-
if (this.state === 'initialized' || this.state === 'idle')
|
|
338
|
-
return 0;
|
|
339
|
-
let ts = (this.tsCurrent - this.tsStart - (this.offset || 0)) / 1000 + this.manualTimeOffset;
|
|
340
|
-
if (ts < 0) {
|
|
341
|
-
this.manualTimeOffset -= ts;
|
|
342
|
-
ts = 0;
|
|
343
|
-
}
|
|
344
|
-
return ts;
|
|
345
|
-
}
|
|
346
387
|
getFtpFromUserSettings() {
|
|
347
388
|
try {
|
|
348
389
|
const userSettings = (0, settings_1.useUserSettings)();
|
|
@@ -366,6 +407,12 @@ let WorkoutRide = (() => {
|
|
|
366
407
|
this.observer.emit(eventName, ...args);
|
|
367
408
|
return true;
|
|
368
409
|
}
|
|
410
|
+
stopWorker() {
|
|
411
|
+
if (this.updateInterval) {
|
|
412
|
+
clearInterval(this.updateInterval);
|
|
413
|
+
this.updateInterval = undefined;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
369
416
|
};
|
|
370
417
|
__setFunctionName(_classThis, "WorkoutRide");
|
|
371
418
|
(() => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Workout } from "../base/model";
|
|
1
2
|
export interface WorkoutRequest {
|
|
2
3
|
time: number;
|
|
3
4
|
minPower?: number;
|
|
@@ -11,3 +12,11 @@ export interface ActiveWorkoutLimit extends WorkoutRequest {
|
|
|
11
12
|
duration: number;
|
|
12
13
|
remaining: number;
|
|
13
14
|
}
|
|
15
|
+
export interface WorkoutDisplayProperties {
|
|
16
|
+
workout?: Workout;
|
|
17
|
+
title?: string;
|
|
18
|
+
ftp?: number;
|
|
19
|
+
current?: ActiveWorkoutLimit;
|
|
20
|
+
start?: number;
|
|
21
|
+
stop?: number;
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incyclist-services",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.97",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"gd-eventlog": "^0.1.26"
|
|
6
6
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"axios": "^1.6.1",
|
|
42
|
-
"incyclist-devices": "^2.1.
|
|
42
|
+
"incyclist-devices": "^2.1.41",
|
|
43
43
|
"md5": "^2.3.0",
|
|
44
44
|
"promise.any": "^2.0.6",
|
|
45
45
|
"uuid": "^9.0.0",
|