incyclist-devices 2.3.36 → 2.3.38

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.
@@ -53,7 +53,7 @@ class AntFEAdapter extends adapter_1.default {
53
53
  return;
54
54
  }
55
55
  let isReset = request.reset && Object.keys(request).length === 1;
56
- const update = isReset ? this.getCyclingMode().getBikeInitRequest() : this.getCyclingMode().sendBikeUpdate(request);
56
+ const update = isReset ? this.getCyclingMode().getBikeInitRequest() : this.getCyclingMode().buildUpdate(request);
57
57
  this.logEvent({ message: 'send bike update requested', device: this.getName(), update, request });
58
58
  try {
59
59
  const fe = this.sensor;
@@ -76,7 +76,7 @@ class AntFEAdapter extends adapter_1.default {
76
76
  yield this.reconnect();
77
77
  }
78
78
  }
79
- this.logEvent({ message: 'sendBikeUpdate() error', device: this.getName(), error: err.message });
79
+ this.logEvent({ message: 'sendUpdate() error', device: this.getName(), error: err.message });
80
80
  }
81
81
  });
82
82
  }
@@ -61,7 +61,7 @@ class AntPwrAdapter extends adapter_1.default {
61
61
  try {
62
62
  if ((this.isPaused() || this.isStopped()) && !request.forced)
63
63
  return;
64
- return yield this.getCyclingMode().sendBikeUpdate(request);
64
+ return yield this.getCyclingMode().buildUpdate(request);
65
65
  }
66
66
  catch (err) {
67
67
  this.logEvent({ message: 'Error', fn: 'sendUpdate', error: err.message });
@@ -214,10 +214,9 @@ class IncyclistDevice extends events_1.default {
214
214
  return;
215
215
  if (!request.enforced && (this.isPaused() || this.isStopped()))
216
216
  return;
217
- if (!this.hasCapability(types_1.IncyclistCapability.Control))
218
- return this.getCyclingMode().sendBikeUpdate(request);
219
- else
217
+ if (this.hasCapability(types_1.IncyclistCapability.Control))
220
218
  throw new Error('method not implemented');
219
+ return this.getCyclingMode().buildUpdate(request);
221
220
  });
222
221
  }
223
222
  setUser(user) {
@@ -92,7 +92,7 @@ class PwrAdapter extends adapter_1.default {
92
92
  try {
93
93
  if (this.isPaused() || this.isStopped())
94
94
  return;
95
- return this.getCyclingMode().sendBikeUpdate(request);
95
+ return this.getCyclingMode().buildUpdate(request);
96
96
  }
97
97
  catch (err) {
98
98
  this.logEvent({ message: 'Error', fn: 'BleCP:sendUpdate', error: err.message });
@@ -264,7 +264,7 @@ class BleFmAdapter extends adapter_1.default {
264
264
  if (!enforced && (this.stopped && !this.isStarting()))
265
265
  return;
266
266
  try {
267
- const update = this.getCyclingMode().sendBikeUpdate(request);
267
+ const update = this.getCyclingMode().buildUpdate(request);
268
268
  this.logEvent({ message: 'send bike update requested', profile: this.getProfile(), mode: (_a = this.getCyclingMode()) === null || _a === void 0 ? void 0 : _a.getName(), update, request });
269
269
  const device = this.getSensor();
270
270
  if (this.hasCapability(types_1.IncyclistCapability.Control)) {
@@ -387,7 +387,7 @@ class BleZwiftPlaySensor extends sensor_1.TBleSensor {
387
387
  const { publicKey, privateKey } = this.createKeyPair();
388
388
  this.privateKey = (_a = this.privateKey) !== null && _a !== void 0 ? _a : Buffer.from(privateKey);
389
389
  this.publicKey = (_b = this.publicKey) !== null && _b !== void 0 ? _b : Buffer.from(publicKey);
390
- message = Buffer.concat([Buffer.from('RideOn'), Buffer.from([0x01, 0x02]), this.publicKey]);
390
+ message = Buffer.concat([Buffer.from('RideOn'), Buffer.from([0x02, 0x03]), this.publicKey]);
391
391
  }
392
392
  yield this.write((0, utils_1.fullUUID)('00000003-19ca-4651-86e5-fa29dcdd09d1'), message, { withoutResponse: true });
393
393
  this.isHubServicePaired = true;
@@ -32,6 +32,7 @@ export default class SmartTrainerCyclingMode extends PowerBasedCyclingModeBase i
32
32
  protected tsStart: number;
33
33
  protected simPower: number;
34
34
  protected simSlope: number;
35
+ protected prevData: any;
35
36
  protected readonly gearRatios: number[];
36
37
  constructor(adapter: IAdapter, props?: any);
37
38
  getBikeInitRequest(): UpdateRequest;
@@ -43,12 +44,15 @@ export default class SmartTrainerCyclingMode extends PowerBasedCyclingModeBase i
43
44
  protected checkSlopeWithSlopeDelta(request: UpdateRequest, newRequest?: UpdateRequest): void;
44
45
  protected checkSlopeWithSimulatedShifting(request: UpdateRequest, newRequest?: UpdateRequest): void;
45
46
  checkSlope(request: UpdateRequest, newRequest?: UpdateRequest): void;
47
+ checkCadenceChange(request: UpdateRequest, newRequest?: UpdateRequest): void;
48
+ calculateSimulatedPower(request: UpdateRequest): void;
46
49
  checkGearChange(request: UpdateRequest, newRequest?: UpdateRequest): void;
47
50
  protected verifySimPower(): void;
48
51
  protected checkEmptyRequest(newRequest: UpdateRequest): void;
49
52
  protected getVirtualShiftMode(): VirtshiftMode;
50
53
  updateData(bikeData: IncyclistBikeData, log?: boolean): IncyclistBikeData;
51
54
  getData(): Partial<IncyclistBikeData>;
55
+ protected updateRequired(request?: UpdateRequest): boolean;
52
56
  sendBikeUpdate(incoming: UpdateRequest): UpdateRequest;
53
57
  protected getGearString(): string;
54
58
  }
@@ -102,8 +102,10 @@ class SmartTrainerCyclingMode extends power_base_1.default {
102
102
  }
103
103
  }
104
104
  checkSlopeWithAdapterShifting(request, newRequest = {}) {
105
+ var _a;
105
106
  this.checkSlopeNoShiftig(request, newRequest);
106
- newRequest.gearRatio = this.gearRatios[this.gear];
107
+ const gear = (_a = this.gear) !== null && _a !== void 0 ? _a : this.getSetting('startGear');
108
+ newRequest.gearRatio = this.gearRatios[gear - 1];
107
109
  }
108
110
  getSlopeDelta() {
109
111
  return this.gearDelta * 0.5;
@@ -123,7 +125,7 @@ class SmartTrainerCyclingMode extends power_base_1.default {
123
125
  }
124
126
  }
125
127
  checkSlopeWithSimulatedShifting(request, newRequest = {}) {
126
- var _a, _b, _c, _d;
128
+ var _a, _b, _c, _d, _e;
127
129
  if (this.gear === undefined) {
128
130
  this.checkSlopeNoShiftig(request, newRequest);
129
131
  return;
@@ -139,15 +141,41 @@ class SmartTrainerCyclingMode extends power_base_1.default {
139
141
  if (slopeAdj !== undefined)
140
142
  this.simSlope = this.simSlope * slopeAdj / 100;
141
143
  }
142
- catch (_e) {
144
+ catch (_f) {
145
+ }
146
+ const virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(this.data.pedalRpm, this.gearRatios[this.gear - 1]);
147
+ const m = (_c = (_b = this.adapter) === null || _b === void 0 ? void 0 : _b.getWeight()) !== null && _c !== void 0 ? _c : 85;
148
+ const vCurrent = this.data.speed * 1000 / 3600;
149
+ const eKinCurrent = m * vCurrent * vCurrent / 2;
150
+ const newPower = calculations_1.default.calculatePower(m, virtualSpeed, (_d = this.simSlope) !== null && _d !== void 0 ? _d : 0);
151
+ const prevPower = this.data.power;
152
+ if (this.data.speed < 10 && this.data.isPedalling && (this.data.slope < 1 || this.data.speed === 0)) {
153
+ this.simPower = Math.max(newPower, prevPower);
154
+ console.log('# set simulated power', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
155
+ this.logger.logEvent({ message: 'set simulated power', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
156
+ }
157
+ else if (this.data.slope === prev && newPower < prevPower) {
158
+ this.simPower = prevPower;
159
+ console.log('# set simulated power:', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
160
+ this.logger.logEvent({ message: 'set simulated power', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
143
161
  }
144
- if (this.data.slope !== prev) {
145
- const virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(this.data.pedalRpm, this.gearRatios[this.gear - 1]);
146
- const m = (_c = (_b = this.adapter) === null || _b === void 0 ? void 0 : _b.getWeight()) !== null && _c !== void 0 ? _c : 85;
147
- this.simPower = calculations_1.default.calculatePower(m, virtualSpeed, (_d = this.simSlope) !== null && _d !== void 0 ? _d : 0);
148
- this.verifySimPower();
149
- this.logger.logEvent({ message: 'set simulater power', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope });
162
+ else {
163
+ const powerDiff = newPower - prevPower;
164
+ const vTarget = virtualSpeed * 1000 / 3600;
165
+ const eKinTarget = m * vTarget * vTarget / 2;
166
+ const eKinPrev = eKinCurrent;
167
+ const delta = eKinTarget - eKinPrev;
168
+ const eKinAfter1sec = eKinPrev - powerDiff * 1;
169
+ const vAfter1sec = Math.sqrt(2 * eKinAfter1sec / m) * 3600 / 1000;
170
+ this.simPower = calculations_1.default.calculatePower(m, vAfter1sec / 3.6, (_e = this.simSlope) !== null && _e !== void 0 ? _e : 0);
171
+ console.log('# set simulated power (Ekin):', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, eKinPrev, eKinTarget, delta, prevPower, newPower });
172
+ this.logger.logEvent({ message: 'set simulated power (Ekin)', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, eKinPrev, eKinTarget, delta, prevPower, newPower });
150
173
  }
174
+ this.verifySimPower();
175
+ }
176
+ else {
177
+ console.log('# set simulated power (same slope):', { simPower: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, cadence: this.data.pedalRpm, power: this.data.power });
178
+ this.logger.logEvent({ message: 'set simulated power (same slope)', simPower: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, cadence: this.data.pedalRpm, power: this.data.power });
151
179
  }
152
180
  newRequest.targetPower = this.simPower;
153
181
  }
@@ -169,8 +197,53 @@ class SmartTrainerCyclingMode extends power_base_1.default {
169
197
  break;
170
198
  }
171
199
  }
172
- checkGearChange(request, newRequest = {}) {
200
+ checkCadenceChange(request, newRequest = {}) {
201
+ const virtshiftMode = this.getVirtualShiftMode();
202
+ if (virtshiftMode !== 'Simulated') {
203
+ return;
204
+ }
205
+ if (request.targetPower !== undefined || request.targetPowerDelta !== undefined || request.gearDelta !== undefined || request.gearRatio !== undefined) {
206
+ console.log('# cadence change ignored due to other power/gear request', request);
207
+ return;
208
+ }
209
+ if (this.data.pedalRpm !== this.prevData.pedalRpm) {
210
+ console.log('# cadence changed ', { cadence: this.data.pedalRpm, prevCadence: this.prevData.pedalRpm });
211
+ this.calculateSimulatedPower(request);
212
+ delete request.slope;
213
+ }
214
+ }
215
+ calculateSimulatedPower(request) {
173
216
  var _a, _b, _c, _d;
217
+ const m = (_b = (_a = this.adapter) === null || _a === void 0 ? void 0 : _a.getWeight()) !== null && _b !== void 0 ? _b : 85;
218
+ const vCurrent = this.data.speed * 1000 / 3600;
219
+ const eKinCurrent = m * vCurrent * vCurrent / 2;
220
+ if (this.data.pedalRpm > 0) {
221
+ const virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(this.data.pedalRpm, this.gearRatios[this.gear - 1]);
222
+ const newPower = calculations_1.default.calculatePower(m, virtualSpeed, (_c = this.simSlope) !== null && _c !== void 0 ? _c : 0);
223
+ const prevPower = this.data.power;
224
+ if (this.data.speed < 10 && this.data.isPedalling && (this.data.slope < 1 || this.data.speed === 0)) {
225
+ this.simPower = Math.max(newPower, prevPower);
226
+ console.log('# set simulated power (starting)', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
227
+ this.logger.logEvent({ message: 'set simulated power (starting)', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
228
+ }
229
+ else {
230
+ const powerDiff = newPower - prevPower;
231
+ const vTarget = virtualSpeed * 1000 / 3600;
232
+ const eKinTarget = m * vTarget * vTarget / 2;
233
+ const eKinPrev = eKinCurrent;
234
+ const delta = eKinTarget - eKinPrev;
235
+ const eKinAfter1sec = eKinPrev - powerDiff * 1;
236
+ const vAfter1sec = Math.sqrt(2 * eKinAfter1sec / m) * 3600 / 1000;
237
+ this.simPower = calculations_1.default.calculatePower(m, vAfter1sec / 3.6, (_d = this.simSlope) !== null && _d !== void 0 ? _d : 0);
238
+ console.log('# set simulated power (Ekin):', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, eKinPrev, eKinTarget, delta, prevPower, newPower });
239
+ this.logger.logEvent({ message: 'set simulated power (Ekin)', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, eKinPrev, eKinTarget, delta, prevPower, newPower });
240
+ }
241
+ }
242
+ else {
243
+ delete this.simPower;
244
+ }
245
+ }
246
+ checkGearChange(request, newRequest = {}) {
174
247
  const virtshiftMode = this.getVirtualShiftMode();
175
248
  switch (virtshiftMode) {
176
249
  case 'SlopeDelta':
@@ -196,13 +269,10 @@ class SmartTrainerCyclingMode extends power_base_1.default {
196
269
  this.gear = this.gearRatios.length;
197
270
  }
198
271
  delete request.gearDelta;
199
- const virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(this.data.pedalRpm, this.gearRatios[this.gear - 1]);
200
- const m = (_b = (_a = this.adapter) === null || _a === void 0 ? void 0 : _a.getWeight()) !== null && _b !== void 0 ? _b : 85;
201
- this.simPower = calculations_1.default.calculatePower(m, virtualSpeed, (_d = (_c = this.simSlope) !== null && _c !== void 0 ? _c : this.data.slope) !== null && _d !== void 0 ? _d : 0);
202
- this.verifySimPower();
203
- this.logger.logEvent({ message: 'set simulater power', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope });
204
- this.adapter.sendUpdate({ targetPower: this.simPower }).then(() => {
205
- });
272
+ this.calculateSimulatedPower(request);
273
+ if (this.simPower !== undefined) {
274
+ this.adapter.sendUpdate({ targetPower: this.simPower }).then(() => { });
275
+ }
206
276
  }
207
277
  break;
208
278
  case 'Adapter':
@@ -259,6 +329,9 @@ class SmartTrainerCyclingMode extends power_base_1.default {
259
329
  if (this.data.pedalRpm > 0 && this.simPower < MIN_POWER) {
260
330
  this.simPower = MIN_POWER;
261
331
  }
332
+ if (!this.data.isPedalling) {
333
+ delete this.simPower;
334
+ }
262
335
  }
263
336
  checkEmptyRequest(newRequest) {
264
337
  if (Object.keys(newRequest).length === 0) {
@@ -288,8 +361,8 @@ class SmartTrainerCyclingMode extends power_base_1.default {
288
361
  return 'Disabled';
289
362
  }
290
363
  updateData(bikeData, log) {
291
- var _a, _b, _c, _d, _e;
292
- const prev = Object.assign({}, this.data);
364
+ var _a;
365
+ const prev = this.prevData = Object.assign({}, this.data);
293
366
  const data = super.updateData(bikeData, log);
294
367
  const mode = this.getVirtualShiftMode();
295
368
  let virtualSpeed;
@@ -304,14 +377,6 @@ class SmartTrainerCyclingMode extends power_base_1.default {
304
377
  this.gear = (_a = this.getSetting('startGear')) !== null && _a !== void 0 ? _a : 0;
305
378
  data.gearStr = this.getGearString();
306
379
  }
307
- else if (this.gear !== undefined) {
308
- if (prev.power !== data.power || prev.pedalRpm !== data.pedalRpm) {
309
- virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(data.pedalRpm, this.gearRatios[this.gear - 1]);
310
- const m = (_c = (_b = this.adapter) === null || _b === void 0 ? void 0 : _b.getWeight()) !== null && _c !== void 0 ? _c : 85;
311
- this.simPower = calculations_1.default.calculatePower(m, virtualSpeed, (_e = (_d = this.simSlope) !== null && _d !== void 0 ? _d : data.slope) !== null && _e !== void 0 ? _e : 0);
312
- this.verifySimPower();
313
- }
314
- }
315
380
  return data;
316
381
  }
317
382
  getData() {
@@ -319,6 +384,14 @@ class SmartTrainerCyclingMode extends power_base_1.default {
319
384
  const data = super.getData();
320
385
  return Object.assign(Object.assign({}, data), { gearStr });
321
386
  }
387
+ updateRequired(request) {
388
+ console.log('# SmartTrainerCyclingMode updateRequired check');
389
+ const virtshiftMode = this.getVirtualShiftMode();
390
+ if (virtshiftMode === 'Adapter' || virtshiftMode === 'Simulated') {
391
+ return true;
392
+ }
393
+ return super.updateRequired(request);
394
+ }
322
395
  sendBikeUpdate(incoming) {
323
396
  this.logger.logEvent({ message: "processing update request", request: incoming, prev: this.prevRequest, data: this.getData() });
324
397
  let newRequest = {};
@@ -328,6 +401,7 @@ class SmartTrainerCyclingMode extends power_base_1.default {
328
401
  if (req) {
329
402
  return req;
330
403
  }
404
+ this.checkCadenceChange(request, newRequest);
331
405
  this.checkGearChange(request, newRequest);
332
406
  this.checkSlope(request, newRequest);
333
407
  this.checkEmptyRequest(newRequest);
@@ -340,7 +414,7 @@ class SmartTrainerCyclingMode extends power_base_1.default {
340
414
  return newRequest;
341
415
  }
342
416
  getGearString() {
343
- var _a, _b, _c, _d, _e;
417
+ var _a, _b, _c, _d;
344
418
  const mode = this.getVirtualShiftMode();
345
419
  if (mode === "Disabled")
346
420
  return undefined;
@@ -351,10 +425,10 @@ class SmartTrainerCyclingMode extends power_base_1.default {
351
425
  if (mode === "SlopeDelta")
352
426
  return this.gearDelta > 0 ? `+${this.gearDelta}` : `${this.gearDelta}`;
353
427
  if (mode === 'Adapter') {
354
- this.gear = (_d = (_c = this.gear) !== null && _c !== void 0 ? _c : this.getSetting('startGear')) !== null && _d !== void 0 ? _d : 0;
428
+ this.gear = (_c = this.gear) !== null && _c !== void 0 ? _c : this.getSetting('startGear');
355
429
  return this.gear.toString();
356
430
  }
357
- return (_e = this.gear) === null || _e === void 0 ? void 0 : _e.toString();
431
+ return (_d = this.gear) === null || _d === void 0 ? void 0 : _d.toString();
358
432
  }
359
433
  }
360
434
  SmartTrainerCyclingMode.config = {
@@ -7,6 +7,7 @@ export declare abstract class CyclingModeBase extends CyclingMode implements ICy
7
7
  localConfig: CyclingModeConfig;
8
8
  protected static config: CyclingModeConfig;
9
9
  protected static isERG: boolean;
10
+ protected prevUpdate: UpdateRequest;
10
11
  static supportsERGMode(): boolean;
11
12
  constructor(adapter: IAdapter, props?: any);
12
13
  setAdapter(adapter: IAdapter): void;
@@ -23,6 +24,8 @@ export declare abstract class CyclingModeBase extends CyclingMode implements ICy
23
24
  getSettings(): Settings;
24
25
  setModeProperty(name: string, value: any): void;
25
26
  getModeProperty(name: string): any;
27
+ protected updateRequired(request?: UpdateRequest): boolean;
28
+ buildUpdate(request?: UpdateRequest): UpdateRequest;
26
29
  abstract getBikeInitRequest(): UpdateRequest;
27
30
  abstract sendBikeUpdate(request: UpdateRequest): UpdateRequest;
28
31
  abstract updateData(data: IncyclistBikeData): IncyclistBikeData;
package/lib/modes/base.js CHANGED
@@ -71,6 +71,26 @@ class CyclingModeBase extends types_1.CyclingMode {
71
71
  return prop.default;
72
72
  return undefined;
73
73
  }
74
+ updateRequired(request = {}) {
75
+ const prevRequest = Object.assign({}, this.prevUpdate);
76
+ this.prevUpdate = Object.assign({}, request);
77
+ if (prevRequest && !request.targetPowerDelta && !request.reset) {
78
+ if ((request.slope !== undefined && prevRequest.slope === request.slope) &&
79
+ (request.targetPower !== undefined && prevRequest.targetPower === request.targetPower)) {
80
+ return false;
81
+ }
82
+ }
83
+ return true;
84
+ }
85
+ buildUpdate(request) {
86
+ if (!request) {
87
+ return {};
88
+ }
89
+ if (!this.updateRequired(request)) {
90
+ return {};
91
+ }
92
+ return this.sendBikeUpdate(request);
93
+ }
74
94
  }
75
95
  exports.CyclingModeBase = CyclingModeBase;
76
96
  CyclingModeBase.config = { name: '', description: '', properties: [] };
@@ -47,4 +47,5 @@ export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements
47
47
  private checkIsStarting;
48
48
  calculateTargetPower(request: any, updateMode?: boolean): any;
49
49
  protected checkForTempPowerAdjustments(request: UpdateRequest): void;
50
+ protected applyCadenceFixes(): boolean;
50
51
  }
@@ -184,6 +184,9 @@ class ERGCyclingMode extends power_base_1.default {
184
184
  delete request.targetPowerDelta;
185
185
  }
186
186
  }
187
+ applyCadenceFixes() {
188
+ return false;
189
+ }
187
190
  }
188
191
  ERGCyclingMode.config = {
189
192
  isERG: true,
@@ -34,6 +34,7 @@ export default class PowerBasedCyclingModeBase extends CyclingModeBase {
34
34
  bikeType: any;
35
35
  slope: any;
36
36
  };
37
+ protected applyCadenceFixes(): boolean;
37
38
  copyBikeData(data: IncyclistBikeData, bikeData: IncyclistBikeData): IncyclistBikeData;
38
39
  calculatePowerAndDistance(speed: number, slope: number, m: number, t: number, props?: {}): {
39
40
  power: number;
@@ -177,8 +177,12 @@ class PowerBasedCyclingModeBase extends base_1.CyclingModeBase {
177
177
  this.copyBikeData(data, bikeData);
178
178
  return { data, prevData, prevRequest, bikeType, slope };
179
179
  }
180
+ applyCadenceFixes() {
181
+ return true;
182
+ }
180
183
  copyBikeData(data, bikeData) {
181
184
  var _a;
185
+ const prevCadence = data.pedalRpm;
182
186
  const keys = Object.keys(bikeData);
183
187
  keys.forEach(key => {
184
188
  if (bikeData[key] === null)
@@ -195,7 +199,12 @@ class PowerBasedCyclingModeBase extends base_1.CyclingModeBase {
195
199
  if (data.slope === undefined)
196
200
  data.slope = 0;
197
201
  if (bikeData.isPedalling === undefined)
198
- data.isPedalling = data.pedalRpm > 0;
202
+ (data.isPedalling = data.pedalRpm > 0 || data.power > 0);
203
+ if (this.applyCadenceFixes()) {
204
+ if (bikeData.pedalRpm === 0 && bikeData.power > 0 && prevCadence !== undefined) {
205
+ data.pedalRpm = prevCadence;
206
+ }
207
+ }
199
208
  if (((_a = this.prevRequest) === null || _a === void 0 ? void 0 : _a.slope) !== undefined) {
200
209
  data.slope = this.prevRequest.slope;
201
210
  }
@@ -41,7 +41,7 @@ export default interface ICyclingMode {
41
41
  getProperties(): CyclingModeProperty[];
42
42
  getProperty(name: string): CyclingModeProperty;
43
43
  getBikeInitRequest(): UpdateRequest;
44
- sendBikeUpdate(request: UpdateRequest): UpdateRequest;
44
+ buildUpdate(request: UpdateRequest): UpdateRequest;
45
45
  updateData(data: IncyclistBikeData): IncyclistBikeData;
46
46
  setSettings(settings: any): any;
47
47
  setSetting(name: string, value: any): void;
@@ -66,7 +66,7 @@ export declare class CyclingMode implements ICyclingMode {
66
66
  getProperties(): CyclingModeProperty[];
67
67
  getProperty(_name: string): CyclingModeProperty;
68
68
  getBikeInitRequest(): UpdateRequest;
69
- sendBikeUpdate(_request: UpdateRequest): UpdateRequest;
69
+ buildUpdate(_request: UpdateRequest): UpdateRequest;
70
70
  updateData(_data: IncyclistBikeData): IncyclistBikeData;
71
71
  setSettings(_settings: any): void;
72
72
  setSetting(_name: string, _value: any): void;
@@ -28,7 +28,7 @@ class CyclingMode {
28
28
  getBikeInitRequest() {
29
29
  throw new Error("Method not implemented.");
30
30
  }
31
- sendBikeUpdate(_request) {
31
+ buildUpdate(_request) {
32
32
  throw new Error("Method not implemented.");
33
33
  }
34
34
  updateData(_data) {
@@ -508,7 +508,7 @@ class DaumAdapter extends adapter_1.SerialIncyclistDevice {
508
508
  return;
509
509
  if (!this.deviceData.isPedalling || this.deviceData.pedalRpm === 0)
510
510
  return;
511
- let bikeRequest = this.getCyclingMode().sendBikeUpdate({ refresh: true }) || {};
511
+ let bikeRequest = this.getCyclingMode().buildUpdate({ refresh: true }) || {};
512
512
  const prev = this.requests[this.requests.length - 1] || {};
513
513
  if (bikeRequest.targetPower !== undefined && bikeRequest.targetPower !== prev.targetPower) {
514
514
  this.logEvent({ message: 'add request', request: bikeRequest });
@@ -521,7 +521,7 @@ class DaumAdapter extends adapter_1.SerialIncyclistDevice {
521
521
  }
522
522
  return new Promise((resolve) => {
523
523
  const fn = () => __awaiter(this, void 0, void 0, function* () {
524
- let bikeRequest = this.getCyclingMode().sendBikeUpdate(request);
524
+ let bikeRequest = this.getCyclingMode().buildUpdate(request);
525
525
  this.logEvent({ message: 'add request', request: bikeRequest });
526
526
  this.requests.push(bikeRequest);
527
527
  resolve(bikeRequest);
@@ -489,7 +489,7 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
489
489
  var _a;
490
490
  if (((_a = this.kettlerData) === null || _a === void 0 ? void 0 : _a.cadence) === 0)
491
491
  return;
492
- let bikeRequest = this.getCyclingMode().sendBikeUpdate({ refresh: true }) || {};
492
+ let bikeRequest = this.getCyclingMode().buildUpdate({ refresh: true }) || {};
493
493
  const prev = this.requests[this.requests.length - 1] || {};
494
494
  if (bikeRequest.targetPower !== undefined && bikeRequest.targetPower !== prev.targetPower) {
495
495
  this.logEvent({ message: 'add request', request: bikeRequest });
@@ -501,7 +501,7 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
501
501
  this.data.slope = request.slope;
502
502
  }
503
503
  return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
504
- let bikeRequest = this.getCyclingMode().sendBikeUpdate(request);
504
+ let bikeRequest = this.getCyclingMode().buildUpdate(request);
505
505
  this.logEvent({ message: 'add request', request: bikeRequest });
506
506
  this.requests.push(bikeRequest);
507
507
  resolve(bikeRequest);
@@ -188,7 +188,7 @@ class Simulator extends adpater_1.default {
188
188
  return __awaiter(this, void 0, void 0, function* () {
189
189
  if (this.paused)
190
190
  return;
191
- return yield this.getCyclingMode().sendBikeUpdate(request);
191
+ return this.getCyclingMode().buildUpdate(request);
192
192
  });
193
193
  }
194
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-devices",
3
- "version": "2.3.36",
3
+ "version": "2.3.38",
4
4
  "dependencies": {
5
5
  "@protobuf-ts/runtime": "^2.11.1",
6
6
  "@serialport/bindings-interface": "^1.2.2",
@@ -34,7 +34,7 @@
34
34
  "scripts": {
35
35
  "lint": "eslint . --ext .ts",
36
36
  "build": "tsc",
37
- "test": "npx jest --coverage",
37
+ "test:unit": "npx jest --coverage",
38
38
  "test:ci": "npx jest --coverage --forceExit",
39
39
  "dev": "tsc --watch",
40
40
  "postversion": "git push && git push --tags",