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.
@@ -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 <= this.getEnd()) {
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 <= s.end);
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: string;
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
- getRemainder(limits: CurrentStep, includeStepInfo?: boolean): CurrentStep;
34
- calc(ts: any, limit: any, includeStepInfo: boolean, isPower?: boolean): {};
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) / 60 % 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
- delete this.loadObserver;
81
- }
82
- getRepo() {
83
- if (!this.repo)
84
- this.repo = api_1.JsonRepository.create('workouts');
85
- return this.repo;
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
- const stringify = (json) => { try {
104
- JSON.stringify(json);
105
- }
106
- catch (_a) { } };
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
- if (idx === -1)
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.repo.write('db', this.workouts);
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
- setTimeout(() => { this.write(); }, this.tsLastWrite + 1000 - Date.now());
171
+ const delayUntilNextWrite = this.tsLastWrite + 1000 - Date.now();
172
+ setTimeout(() => {
173
+ this.write(true);
174
+ }, delayUntilNextWrite);
157
175
  }
158
176
  }
159
177
  emitUpdated(workout) {
@@ -286,7 +286,6 @@ let WorkoutListService = (() => {
286
286
  if (forUi && (!this.initialized))
287
287
  return null;
288
288
  const lists = this.lists.filter(l => l.getCards().length > 0);
289
- console.log('~~~ LISTS:', lists);
290
289
  return lists;
291
290
  }
292
291
  catch (err) {
@@ -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: any;
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
- update(startIfInitialized?: boolean): void;
34
- getDashboardDisplayProperties(): {
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
- if (this.updateInterval) {
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.getTime();
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.getTime();
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 timePrev = ts - completed - 1;
187
- const prevLimits = wo.getLimits(timePrev);
188
- if (prevLimits) {
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
- return {
252
- workout: this.workout, title: this.workout.name,
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 = undefined;
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.95",
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.40",
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",