incyclist-devices 2.3.28 → 2.3.31

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.
Files changed (41) hide show
  1. package/lib/antv2/types.d.ts +1 -1
  2. package/lib/base/adpater.d.ts +2 -0
  3. package/lib/base/adpater.js +24 -11
  4. package/lib/ble/base/adapter.js +2 -1
  5. package/lib/ble/base/interface.d.ts +1 -0
  6. package/lib/ble/base/interface.js +29 -4
  7. package/lib/ble/base/peripheral.d.ts +3 -2
  8. package/lib/ble/base/peripheral.js +62 -38
  9. package/lib/ble/base/sensor.d.ts +2 -0
  10. package/lib/ble/base/sensor.js +16 -4
  11. package/lib/ble/fm/adapter.js +10 -8
  12. package/lib/ble/index.js +2 -0
  13. package/lib/ble/types.d.ts +4 -2
  14. package/lib/ble/zwift/click/adapter.d.ts +19 -0
  15. package/lib/ble/zwift/click/adapter.js +74 -0
  16. package/lib/ble/zwift/click/index.d.ts +2 -0
  17. package/lib/ble/zwift/click/index.js +18 -0
  18. package/lib/ble/zwift/click/sensor.d.ts +40 -0
  19. package/lib/ble/zwift/click/sensor.js +221 -0
  20. package/lib/ble/zwift/play/adapter.d.ts +19 -0
  21. package/lib/ble/zwift/play/adapter.js +76 -0
  22. package/lib/ble/zwift/play/index.d.ts +2 -0
  23. package/lib/ble/zwift/play/index.js +18 -0
  24. package/lib/ble/zwift/play/sensor.d.ts +43 -0
  25. package/lib/ble/zwift/play/sensor.js +246 -0
  26. package/lib/modes/antble-smarttrainer.d.ts +22 -3
  27. package/lib/modes/antble-smarttrainer.js +226 -3
  28. package/lib/modes/daum-classic-standard.d.ts +2 -1
  29. package/lib/modes/daum-classic-standard.js +6 -0
  30. package/lib/modes/power-base.js +17 -3
  31. package/lib/modes/types.d.ts +1 -0
  32. package/lib/serial/daum/DaumAdapter.d.ts +1 -0
  33. package/lib/serial/daum/DaumAdapter.js +14 -0
  34. package/lib/types/adapter.d.ts +1 -0
  35. package/lib/types/capabilities.d.ts +2 -1
  36. package/lib/types/capabilities.js +1 -0
  37. package/lib/types/data.d.ts +2 -0
  38. package/lib/utils/calculations.d.ts +1 -0
  39. package/lib/utils/calculations.js +13 -1
  40. package/lib/utils/utils.js +33 -26
  41. package/package.json +22 -10
@@ -1,13 +1,52 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  const types_1 = require("./types");
7
40
  const power_base_1 = __importDefault(require("./power-base"));
41
+ const calculations_1 = __importStar(require("../utils/calculations"));
8
42
  class SmartTrainerCyclingMode extends power_base_1.default {
9
43
  constructor(adapter, props) {
10
44
  super(adapter, props);
45
+ this.gearDelta = 0;
46
+ this.gearRatios = [
47
+ 0.75, 0.87, 0.99, 1.11, 1.23, 1.38, 1.53, 1.68, 1.86, 2.04, 2.22, 2.40,
48
+ 2.61, 2.82, 3.03, 3.24, 3.49, 3.74, 3.99, 4.24, 4.54, 4.84, 5.14, 5.49
49
+ ];
11
50
  this.initLogger('SmartTrainerMode');
12
51
  }
13
52
  getBikeInitRequest() {
@@ -23,7 +62,20 @@ class SmartTrainerCyclingMode extends power_base_1.default {
23
62
  return this.prevRequest;
24
63
  }
25
64
  }
26
- checkSlope(request, newRequest = {}) {
65
+ getConfig() {
66
+ const config = super.getConfig();
67
+ let virtshift = config.properties.find(p => p.key === 'virtshift');
68
+ if (!virtshift) {
69
+ virtshift = { key: 'virtshift', name: 'Virtual Shifting', description: 'Enable virtual shifting', type: types_1.CyclingModeProperyType.SingleSelect, options: ['Disabled', 'Enabled', 'Mixed'], default: 'Disabled' };
70
+ config.properties.push(virtshift);
71
+ }
72
+ if (this.adapter.supportsVirtualShifting()) {
73
+ virtshift.default = 'Enabled';
74
+ virtshift.options = ['Disabled', 'Enabled'];
75
+ }
76
+ return config;
77
+ }
78
+ checkSlopeNoShiftig(request, newRequest = {}) {
27
79
  if (request.slope !== undefined) {
28
80
  const targetSlope = newRequest.slope = parseFloat(request.slope.toFixed(1));
29
81
  this.data.slope = newRequest.slope;
@@ -36,6 +88,116 @@ class SmartTrainerCyclingMode extends power_base_1.default {
36
88
  }
37
89
  }
38
90
  }
91
+ checkSlopeWithAdapterShifting(request, newRequest = {}) {
92
+ return this.checkSlopeNoShiftig(request, newRequest);
93
+ }
94
+ getSlopeDelta() {
95
+ return this.gearDelta * 0.5;
96
+ }
97
+ checkSlopeWithSlopeDelta(request, newRequest = {}) {
98
+ if (request.slope !== undefined) {
99
+ const targetSlope = newRequest.slope = parseFloat(request.slope.toFixed(1));
100
+ this.data.slope = newRequest.slope;
101
+ const requestedSlope = targetSlope + this.getSlopeDelta();
102
+ try {
103
+ const slopeAdj = requestedSlope >= 0 ? this.getSetting('slopeAdj') : this.getSetting('slopeAdjDown');
104
+ newRequest.slope = slopeAdj !== undefined ? requestedSlope * slopeAdj / 100 : requestedSlope;
105
+ }
106
+ catch (_a) {
107
+ console.error('# Error calculating requested slope');
108
+ }
109
+ }
110
+ }
111
+ checkSlopeWithSimulatedShifting(request, newRequest = {}) {
112
+ var _a, _b, _c, _d;
113
+ if (this.gear === undefined) {
114
+ return this.checkSlopeNoShiftig(request, newRequest);
115
+ }
116
+ if (request.slope !== undefined) {
117
+ const prev = (_a = this.data.slope) !== null && _a !== void 0 ? _a : 0;
118
+ this.data.slope = parseFloat(request.slope.toFixed(1));
119
+ delete request.slope;
120
+ delete newRequest.slope;
121
+ this.simSlope = this.data.slope;
122
+ try {
123
+ const slopeAdj = this.simSlope >= 0 ? this.getSetting('slopeAdj') : this.getSetting('slopeAdjDown');
124
+ if (slopeAdj !== undefined)
125
+ this.simSlope = this.simSlope * slopeAdj / 100;
126
+ }
127
+ catch (_e) {
128
+ }
129
+ if (this.data.slope === prev) {
130
+ newRequest.targetPower = this.simPower;
131
+ return;
132
+ }
133
+ else {
134
+ const virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(this.data.pedalRpm, this.gearRatios[this.gear - 1]);
135
+ const m = (_c = (_b = this.adapter) === null || _b === void 0 ? void 0 : _b.getWeight()) !== null && _c !== void 0 ? _c : 85;
136
+ this.simPower = calculations_1.default.calculatePower(m, virtualSpeed, (_d = this.simSlope) !== null && _d !== void 0 ? _d : 0);
137
+ newRequest.targetPower = this.simPower;
138
+ }
139
+ if (this.simPower < 0)
140
+ this.simPower = 0;
141
+ }
142
+ else {
143
+ newRequest.targetPower = this.simPower;
144
+ }
145
+ }
146
+ checkSlope(request, newRequest = {}) {
147
+ const virtshiftMode = this.getVirtualShiftMode();
148
+ switch (virtshiftMode) {
149
+ case 'SlopeDelta':
150
+ this.checkSlopeWithSlopeDelta(request, newRequest);
151
+ break;
152
+ case 'Simulated':
153
+ this.checkSlopeWithSimulatedShifting(request, newRequest);
154
+ break;
155
+ case 'Adapter':
156
+ this.checkSlopeWithAdapterShifting(request, newRequest);
157
+ break;
158
+ case 'Disabled':
159
+ default:
160
+ this.checkSlopeNoShiftig(request, newRequest);
161
+ break;
162
+ }
163
+ }
164
+ checkGearChange(request, newRequest = {}) {
165
+ var _a, _b, _c, _d;
166
+ const virtshiftMode = this.getVirtualShiftMode();
167
+ switch (virtshiftMode) {
168
+ case 'SlopeDelta':
169
+ if (request.gearDelta !== undefined) {
170
+ this.gearDelta += request.gearDelta;
171
+ request.slope = this.data.slope;
172
+ delete request.gearDelta;
173
+ }
174
+ break;
175
+ case 'Simulated':
176
+ if (request.gearDelta !== undefined) {
177
+ if (this.gear === undefined) {
178
+ this.gear = 10 + request.gearDelta;
179
+ }
180
+ else {
181
+ this.gear += request.gearDelta;
182
+ }
183
+ if (this.gear < 1) {
184
+ this.gear = 1;
185
+ }
186
+ if (this.gear > this.gearRatios.length) {
187
+ this.gear = this.gearRatios.length;
188
+ }
189
+ delete request.gearDelta;
190
+ const virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(this.data.pedalRpm, this.gearRatios[this.gear - 1]);
191
+ const m = (_b = (_a = this.adapter) === null || _a === void 0 ? void 0 : _a.getWeight()) !== null && _b !== void 0 ? _b : 85;
192
+ 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);
193
+ }
194
+ break;
195
+ case 'Adapter':
196
+ case 'Disabled':
197
+ default:
198
+ break;
199
+ }
200
+ }
39
201
  checkEmptyRequest(newRequest) {
40
202
  if (Object.keys(newRequest).length === 0) {
41
203
  if (this.prevRequest) {
@@ -44,14 +206,56 @@ class SmartTrainerCyclingMode extends power_base_1.default {
44
206
  }
45
207
  }
46
208
  }
209
+ getVirtualShiftMode() {
210
+ const virtshiftMode = this.getSetting('virtshift');
211
+ if (virtshiftMode === 'Disabled') {
212
+ return 'Disabled';
213
+ }
214
+ if (this.adapter.supportsVirtualShifting()) {
215
+ if (virtshiftMode === 'Enabled') {
216
+ return 'Adapter';
217
+ }
218
+ }
219
+ else {
220
+ return virtshiftMode === 'Mixed' ? 'SlopeDelta' : 'Simulated';
221
+ }
222
+ }
223
+ updateData(bikeData, log) {
224
+ var _a, _b, _c, _d;
225
+ const prev = Object.assign({}, this.data);
226
+ const data = super.updateData(bikeData, log);
227
+ const mode = this.getVirtualShiftMode();
228
+ let virtualSpeed;
229
+ data.gearStr = this.getGearString();
230
+ if (mode !== 'Simulated') {
231
+ return data;
232
+ }
233
+ if (data.power > 0 && !this.tsStart) {
234
+ this.tsStart = Date.now();
235
+ }
236
+ if (this.gear === undefined && this.tsStart && data.power > 0 && (Date.now() - this.tsStart > 3000)) {
237
+ this.setInitialGear(data);
238
+ data.gearStr = this.getGearString();
239
+ }
240
+ else if (this.gear !== undefined) {
241
+ if (prev.power !== data.power || prev.pedalRpm !== data.pedalRpm) {
242
+ virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(data.pedalRpm, this.gearRatios[this.gear - 1]);
243
+ const m = (_b = (_a = this.adapter) === null || _a === void 0 ? void 0 : _a.getWeight()) !== null && _b !== void 0 ? _b : 85;
244
+ this.simPower = calculations_1.default.calculatePower(m, virtualSpeed, (_d = (_c = this.simSlope) !== null && _c !== void 0 ? _c : data.slope) !== null && _d !== void 0 ? _d : 0);
245
+ }
246
+ }
247
+ return data;
248
+ }
47
249
  sendBikeUpdate(incoming) {
48
250
  this.logger.logEvent({ message: "processing update request", request: incoming, prev: this.prevRequest, data: this.getData() });
49
251
  let newRequest = {};
50
252
  const request = Object.assign({}, incoming);
51
253
  try {
52
254
  const req = this.checkForResetOrEmpty(request);
53
- if (req)
255
+ if (req) {
54
256
  return req;
257
+ }
258
+ this.checkGearChange(request, newRequest);
55
259
  this.checkSlope(request, newRequest);
56
260
  this.checkEmptyRequest(newRequest);
57
261
  this.prevRequest = JSON.parse(JSON.stringify(newRequest));
@@ -62,6 +266,25 @@ class SmartTrainerCyclingMode extends power_base_1.default {
62
266
  }
63
267
  return newRequest;
64
268
  }
269
+ setInitialGear(data) {
270
+ var _a, _b;
271
+ const m = (_b = (_a = this.adapter) === null || _a === void 0 ? void 0 : _a.getWeight()) !== null && _b !== void 0 ? _b : 85;
272
+ const virtualSpeeds = this.gearRatios.map(r => (0, calculations_1.calculateVirtualSpeed)(data.pedalRpm, r));
273
+ const requiredPowers = virtualSpeeds.map(v => { var _a; return calculations_1.default.calculatePower(m, v, (_a = data.slope) !== null && _a !== void 0 ? _a : 0); });
274
+ const deltas = requiredPowers.map((p, i) => ({ gear: i + 1, delta: Math.abs(p - data.power) }));
275
+ deltas.sort((a, b) => a.delta - b.delta);
276
+ this.gear = deltas[0].gear;
277
+ }
278
+ getGearString() {
279
+ const mode = this.getVirtualShiftMode();
280
+ if (mode === "Disabled")
281
+ return undefined;
282
+ if (this.gear === undefined || this.gear === null)
283
+ return '';
284
+ if (mode === "SlopeDelta")
285
+ return this.gear > 0 ? `+${this.gear}` : `${this.gear}`;
286
+ return this.gear.toString();
287
+ }
65
288
  }
66
289
  SmartTrainerCyclingMode.config = {
67
290
  name: "Smart Trainer",
@@ -70,7 +293,7 @@ SmartTrainerCyclingMode.config = {
70
293
  properties: [
71
294
  { key: 'bikeType', name: 'Bike Type', description: '', type: types_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
72
295
  { key: 'slopeAdj', name: 'Bike Reality Factor', description: 'Percentage of slope that should be sent to the SmartTrainer. Should be used in case the slopes are feeling too hard', type: types_1.CyclingModeProperyType.Integer, default: 100, min: 0, max: 200 },
73
- { key: 'slopeAdjDown', name: 'Bike Reality Factor downhill', description: 'Percentage of slope that should be sent during downhill sections. Should be used to avoid spinning out', type: types_1.CyclingModeProperyType.Integer, default: 50, min: 0, max: 100 }
296
+ { key: 'slopeAdjDown', name: 'Bike Reality Factor downhill', description: 'Percentage of slope that should be sent during downhill sections. Should be used to avoid spinning out', type: types_1.CyclingModeProperyType.Integer, default: 50, min: 0, max: 100 },
74
297
  ]
75
298
  };
76
299
  exports.default = SmartTrainerCyclingMode;
@@ -1,4 +1,4 @@
1
- import ICyclingMode, { Settings, UpdateRequest } from "./types";
1
+ import ICyclingMode, { CyclingModeConfig, Settings, UpdateRequest } from "./types";
2
2
  import { IncyclistBikeData } from "../types";
3
3
  import SmartTrainerCyclingMode from "./antble-smarttrainer";
4
4
  import { IncyclistDeviceAdapter } from "../base/adpater";
@@ -11,6 +11,7 @@ export default class DaumClassicCyclingMode extends SmartTrainerCyclingMode impl
11
11
  event: DaumClassicEvent;
12
12
  constructor(adapter: IncyclistDeviceAdapter, props?: Settings);
13
13
  getBikeInitRequest(): UpdateRequest;
14
+ getConfig(): CyclingModeConfig;
14
15
  checkForResetOrEmpty(request: UpdateRequest): UpdateRequest | undefined;
15
16
  protected updateSpeedAndDistance(_power: number, _slope: any, _bikeType: any, data: IncyclistBikeData, prevData: any): number;
16
17
  }
@@ -25,6 +25,12 @@ class DaumClassicCyclingMode extends antble_smarttrainer_1.default {
25
25
  getBikeInitRequest() {
26
26
  return { slope: 0 };
27
27
  }
28
+ getConfig() {
29
+ if (this.localConfig)
30
+ return this.localConfig;
31
+ let cm = this.constructor;
32
+ return cm.config;
33
+ }
28
34
  checkForResetOrEmpty(request) {
29
35
  if (!request || request.reset) {
30
36
  this.prevRequest = {};
@@ -54,10 +54,12 @@ class PowerBasedCyclingModeBase extends base_1.CyclingModeBase {
54
54
  }
55
55
  }
56
56
  checkRefresh(request, newRequest) {
57
+ var _a;
57
58
  if (request.refresh && request.targetPower === undefined) {
58
59
  delete request.refresh;
59
- if (this.prevRequest)
60
- newRequest.targetPower = this.prevRequest.targetPower;
60
+ if (this.prevRequest) {
61
+ newRequest.targetPower = (_a = this.prevRequest.targetPower) !== null && _a !== void 0 ? _a : this.data.power;
62
+ }
61
63
  }
62
64
  }
63
65
  checkTargetPowerSet(request, newRequest) {
@@ -73,9 +75,19 @@ class PowerBasedCyclingModeBase extends base_1.CyclingModeBase {
73
75
  }
74
76
  }
75
77
  checkSlope(request) {
78
+ var _a;
76
79
  if (request.slope !== undefined) {
77
80
  this.data.slope = request.slope;
78
81
  delete request.slope;
82
+ if (request.targetPower === undefined && request.minPower === undefined && request.maxPower === undefined) {
83
+ if (this.prevRequest) {
84
+ this.prevRequest.targetPower = (_a = this.prevRequest.targetPower) !== null && _a !== void 0 ? _a : (this.data.power || undefined);
85
+ }
86
+ else {
87
+ this.prevRequest = { targetPower: this.data.power || undefined };
88
+ }
89
+ request.refresh = this.prevRequest.targetPower !== undefined;
90
+ }
79
91
  }
80
92
  }
81
93
  checkEmptyRequest(newRequest) {
@@ -213,8 +225,10 @@ class PowerBasedCyclingModeBase extends base_1.CyclingModeBase {
213
225
  const request = Object.assign({}, incoming);
214
226
  try {
215
227
  const req = this.checkForResetOrEmpty(request);
216
- if (req)
228
+ if (req) {
229
+ delete req.refresh;
217
230
  return req;
231
+ }
218
232
  this.checkSlope(request);
219
233
  this.checkForTempPowerAdjustments(request);
220
234
  this.checkTargetPowerSet(request, newRequest);
@@ -5,6 +5,7 @@ export type UpdateRequest = {
5
5
  maxPower?: number;
6
6
  targetPower?: number;
7
7
  targetPowerDelta?: number;
8
+ gearDelta?: number;
8
9
  reset?: boolean;
9
10
  refresh?: boolean;
10
11
  init?: boolean;
@@ -61,5 +61,6 @@ export default class DaumAdapter<S extends SerialDeviceSettings, P extends Devic
61
61
  sendRequest(request: any): Promise<any>;
62
62
  refreshRequests(): void;
63
63
  processClientRequest(request: any): Promise<UpdateRequest>;
64
+ protected reset(): void;
64
65
  getDeviceInfo(): Promise<any>;
65
66
  }
@@ -529,6 +529,20 @@ class DaumAdapter extends adapter_1.SerialIncyclistDevice {
529
529
  fn();
530
530
  });
531
531
  }
532
+ reset() {
533
+ if (this.iv) {
534
+ const { sync, update, emitter } = this.iv;
535
+ if (sync)
536
+ clearInterval(sync);
537
+ if (update)
538
+ clearInterval(update);
539
+ if (emitter)
540
+ emitter.removeAllListeners();
541
+ }
542
+ if (this.internalEmitter) {
543
+ this.internalEmitter.removeAllListeners();
544
+ }
545
+ }
532
546
  getDeviceInfo() {
533
547
  return __awaiter(this, void 0, void 0, function* () {
534
548
  throw new Error('Method not implemented.');
@@ -34,6 +34,7 @@ export interface IAdapter extends EventEmitter, IBike, ISensor {
34
34
  getName(): string;
35
35
  getID(): string;
36
36
  getUniqueName(): string;
37
+ supportsVirtualShifting(): boolean;
37
38
  getDisplayName(): string;
38
39
  getSettings(): DeviceSettings;
39
40
  isSame(adapter: IAdapter): boolean;
@@ -3,5 +3,6 @@ export declare enum IncyclistCapability {
3
3
  Speed = "speed",
4
4
  Cadence = "cadence",
5
5
  HeartRate = "heartrate",
6
- Control = "control"
6
+ Control = "control",
7
+ AppControl = "app_control"
7
8
  }
@@ -8,4 +8,5 @@ var IncyclistCapability;
8
8
  IncyclistCapability["Cadence"] = "cadence";
9
9
  IncyclistCapability["HeartRate"] = "heartrate";
10
10
  IncyclistCapability["Control"] = "control";
11
+ IncyclistCapability["AppControl"] = "app_control";
11
12
  })(IncyclistCapability || (exports.IncyclistCapability = IncyclistCapability = {}));
@@ -6,6 +6,7 @@ export type IncyclistAdapterData = {
6
6
  heartrate?: number;
7
7
  distance?: number;
8
8
  timestamp?: number;
9
+ gearStr?: string;
9
10
  deviceTime?: number;
10
11
  deviceDistanceCounter?: number;
11
12
  internalDistanceCounter?: number;
@@ -19,5 +20,6 @@ export type IncyclistBikeData = {
19
20
  distanceInternal?: number;
20
21
  time?: number;
21
22
  gear?: number;
23
+ gearStr?: string;
22
24
  slope?: number;
23
25
  };
@@ -10,4 +10,5 @@ export default class C {
10
10
  wheelCirc?: number;
11
11
  }): number;
12
12
  }
13
+ export declare const calculateVirtualSpeed: (rpm: number, gearRatio: number, wheelCirc?: number) => number;
13
14
  export declare function solveCubic(p: any, q: any): any[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IllegalArgumentException = void 0;
3
+ exports.calculateVirtualSpeed = exports.IllegalArgumentException = void 0;
4
4
  exports.solveCubic = solveCubic;
5
5
  const g = 9.80665;
6
6
  const rho = 1.2041;
@@ -103,6 +103,18 @@ class C {
103
103
  }
104
104
  }
105
105
  exports.default = C;
106
+ const calculateVirtualSpeed = (rpm, gearRatio, wheelCirc = 2125) => {
107
+ if (rpm === undefined || rpm === null || rpm < 0)
108
+ throw new IllegalArgumentException("rpm must be a positive number");
109
+ if (!gearRatio || gearRatio < 0)
110
+ throw new IllegalArgumentException("gearRatio must be a positive number");
111
+ if (!wheelCirc || wheelCirc < 0)
112
+ throw new IllegalArgumentException("wheelCirc must be a positive number");
113
+ let distRotation = wheelCirc * gearRatio / 1000;
114
+ let speed = rpm * distRotation * 60 / 1000;
115
+ return speed / 3.6;
116
+ };
117
+ exports.calculateVirtualSpeed = calculateVirtualSpeed;
106
118
  function acosh(x) {
107
119
  return Math.log(x + Math.sqrt(x * x - 1.0));
108
120
  }
@@ -26,39 +26,46 @@ const resolveNextTick = () => {
26
26
  };
27
27
  exports.resolveNextTick = resolveNextTick;
28
28
  function runWithRetries(fn, maxRetries, timeBetween) {
29
- return new Promise((resolve, reject) => {
30
- let retries = 0;
31
- let tLastFailure = undefined;
32
- let busy = false;
33
- let iv = setInterval(() => __awaiter(this, void 0, void 0, function* () {
34
- const tNow = Date.now();
35
- if (busy) {
36
- return;
37
- }
38
- if (tLastFailure === undefined || tNow - tLastFailure > timeBetween) {
39
- try {
40
- busy = true;
41
- const data = yield fn();
42
- clearInterval(iv);
43
- iv = undefined;
44
- busy = false;
45
- return resolve(data);
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ let iv;
31
+ const res = yield new Promise((resolve, reject) => {
32
+ let retries = 0;
33
+ let tLastFailure = undefined;
34
+ let busy = false;
35
+ iv = setInterval(() => __awaiter(this, void 0, void 0, function* () {
36
+ const tNow = Date.now();
37
+ if (busy) {
38
+ return;
46
39
  }
47
- catch (err) {
48
- tLastFailure = Date.now();
49
- retries++;
50
- if (retries >= maxRetries) {
40
+ if (tLastFailure === undefined || tNow - tLastFailure > timeBetween) {
41
+ try {
42
+ busy = true;
43
+ const data = yield fn();
51
44
  clearInterval(iv);
52
45
  iv = undefined;
53
46
  busy = false;
54
- return reject(err);
47
+ return resolve(data);
55
48
  }
56
- else {
57
- busy = false;
49
+ catch (err) {
50
+ tLastFailure = Date.now();
51
+ retries++;
52
+ if (retries >= maxRetries) {
53
+ clearInterval(iv);
54
+ iv = undefined;
55
+ busy = false;
56
+ return reject(err);
57
+ }
58
+ else {
59
+ busy = false;
60
+ }
58
61
  }
59
62
  }
60
- }
61
- }), 50);
63
+ }), 50);
64
+ });
65
+ if (iv) {
66
+ clearInterval(iv);
67
+ }
68
+ return res;
62
69
  });
63
70
  }
64
71
  function floatVal(d) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-devices",
3
- "version": "2.3.28",
3
+ "version": "2.3.31",
4
4
  "dependencies": {
5
5
  "@serialport/bindings-interface": "^1.2.2",
6
6
  "@serialport/parser-byte-length": "^9.0.1",
@@ -16,15 +16,16 @@
16
16
  "devDependencies": {
17
17
  "@serialport/binding-mock": "^10.2.2",
18
18
  "@serialport/bindings-cpp": "^10.8.0",
19
- "@stoprocent/noble": "^1.15.2",
20
- "@types/jest": "^29.5.14",
21
- "@types/node": "^22.15.18",
19
+ "@stoprocent/noble": "^2.3.5",
20
+ "@types/jest": "^30.0.0",
21
+ "@types/node": "^24.3.1",
22
+ "@typescript-eslint/eslint-plugin": "^8.43.0",
23
+ "@typescript-eslint/parser": "^8.43.0",
22
24
  "bonjour-service": "^1.3.0",
23
- "eslint": "^8.57.1",
24
- "eslint-config-react-app": "^7.0.1",
25
- "jest": "^29.7.0",
26
- "ts-jest": "^29.3.4",
27
- "typescript": "^5.8.3"
25
+ "eslint": "^9.35.0",
26
+ "jest": "^30.1.3",
27
+ "ts-jest": "^29.4.1",
28
+ "typescript": "^5.9.2"
28
29
  },
29
30
  "scripts": {
30
31
  "lint": "eslint . --ext .ts",
@@ -43,7 +44,18 @@
43
44
  "lib": "./src"
44
45
  },
45
46
  "eslintConfig": {
46
- "extends": "react-app",
47
+ "extends": [
48
+ "eslint:recommended",
49
+ "plugin:@typescript-eslint/recommended"
50
+ ],
51
+ "parser": "@typescript-eslint/parser",
52
+ "parserOptions": {
53
+ "ecmaVersion": "latest",
54
+ "sourceType": "module"
55
+ },
56
+ "plugins": [
57
+ "@typescript-eslint"
58
+ ],
47
59
  "rules": {
48
60
  "jsx-a11y/anchor-is-valid": [
49
61
  "off"