incyclist-devices 2.3.37 → 2.3.39
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/antv2/base/adapter.js +5 -5
- package/lib/antv2/fe/adapter.js +2 -2
- package/lib/antv2/pwr/adapter.js +1 -1
- package/lib/base/adpater.js +2 -3
- package/lib/ble/cp/adapter.js +1 -1
- package/lib/ble/cp/sensor.js +1 -1
- package/lib/ble/fm/adapter.d.ts +1 -0
- package/lib/ble/fm/adapter.js +8 -2
- package/lib/ble/hr/sensor.js +1 -1
- package/lib/ble/utils.js +1 -1
- package/lib/ble/zwift/play/sensor.js +1 -2
- package/lib/direct-connect/base/peripheral.js +0 -1
- package/lib/direct-connect/messages/DiscoverCharacteristics.d.ts +1 -1
- package/lib/direct-connect/messages/DiscoverCharacteristics.js +3 -2
- package/lib/direct-connect/messages/DiscoverServices.d.ts +1 -1
- package/lib/direct-connect/messages/DiscoverServices.js +5 -3
- package/lib/direct-connect/messages/message.d.ts +1 -1
- package/lib/direct-connect/messages/message.js +2 -1
- package/lib/features/features.d.ts +11 -0
- package/lib/features/features.js +29 -0
- package/lib/features/index.d.ts +1 -0
- package/lib/features/index.js +17 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/modes/antble-smarttrainer.d.ts +5 -0
- package/lib/modes/antble-smarttrainer.js +82 -27
- package/lib/modes/base.d.ts +3 -0
- package/lib/modes/base.js +20 -0
- package/lib/modes/daum-erg.d.ts +1 -0
- package/lib/modes/daum-erg.js +3 -0
- package/lib/modes/daum-premium-standard.js +1 -1
- package/lib/modes/daum-smarttrainer.js +7 -7
- package/lib/modes/power-base.d.ts +1 -0
- package/lib/modes/power-base.js +7 -2
- package/lib/modes/types.d.ts +2 -2
- package/lib/modes/types.js +1 -1
- package/lib/serial/bindings/tcp.js +8 -8
- package/lib/serial/daum/DaumAdapter.js +2 -2
- package/lib/serial/daum/classic/adapter.d.ts +1 -1
- package/lib/serial/daum/classic/adapter.js +9 -10
- package/lib/serial/daum/classic/mock.js +1 -1
- package/lib/serial/daum/premium/comms.js +5 -5
- package/lib/serial/daum/premium/mock.js +1 -1
- package/lib/serial/daum/premium/utils.js +12 -12
- package/lib/serial/kettler/ergo-racer/adapter.d.ts +1 -1
- package/lib/serial/kettler/ergo-racer/adapter.js +43 -50
- package/lib/simulator/Simulator.js +1 -1
- package/lib/utils/utils.js +5 -5
- package/package.json +2 -2
|
@@ -171,7 +171,7 @@ class AntAdapter extends adpater_1.default {
|
|
|
171
171
|
clearInterval(iv);
|
|
172
172
|
resolve(true);
|
|
173
173
|
}
|
|
174
|
-
if (
|
|
174
|
+
if (this.promiseWaitForData === undefined || this.promiseWaitForData === null || this.stopped) {
|
|
175
175
|
resolve(false);
|
|
176
176
|
clearInterval(iv);
|
|
177
177
|
}
|
|
@@ -186,7 +186,7 @@ class AntAdapter extends adpater_1.default {
|
|
|
186
186
|
return true;
|
|
187
187
|
}
|
|
188
188
|
const tsStart = Date.now();
|
|
189
|
-
if (this.promiseWaitForData) {
|
|
189
|
+
if (this.promiseWaitForData !== undefined && this.promiseWaitForData !== null) {
|
|
190
190
|
let hasData = false;
|
|
191
191
|
try {
|
|
192
192
|
hasData = yield this.promiseWaitForData;
|
|
@@ -201,7 +201,7 @@ class AntAdapter extends adpater_1.default {
|
|
|
201
201
|
this.promiseWaitForData = null;
|
|
202
202
|
return hasData;
|
|
203
203
|
}
|
|
204
|
-
catch (
|
|
204
|
+
catch (_b) {
|
|
205
205
|
this.promiseWaitForData = null;
|
|
206
206
|
return false;
|
|
207
207
|
}
|
|
@@ -257,7 +257,7 @@ class AntAdapter extends adpater_1.default {
|
|
|
257
257
|
try {
|
|
258
258
|
return yield this.start();
|
|
259
259
|
}
|
|
260
|
-
catch (
|
|
260
|
+
catch (_a) {
|
|
261
261
|
return false;
|
|
262
262
|
}
|
|
263
263
|
});
|
|
@@ -350,7 +350,7 @@ class AntAdapter extends adpater_1.default {
|
|
|
350
350
|
return __awaiter(this, void 0, void 0, function* () {
|
|
351
351
|
var _a, _b;
|
|
352
352
|
this.startStatus.sensorStarted = this.sensorConnected;
|
|
353
|
-
if (this.startStatus.sensorStarted
|
|
353
|
+
if (this.startStatus.sensorStarted)
|
|
354
354
|
return;
|
|
355
355
|
this.logEvent({ message: 'start sensor', device: this.getName(), props });
|
|
356
356
|
try {
|
package/lib/antv2/fe/adapter.js
CHANGED
|
@@ -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().
|
|
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: '
|
|
79
|
+
this.logEvent({ message: 'sendUpdate() error', device: this.getName(), error: err.message });
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
82
|
}
|
package/lib/antv2/pwr/adapter.js
CHANGED
|
@@ -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().
|
|
64
|
+
return yield this.getCyclingMode().buildUpdate(request);
|
|
65
65
|
}
|
|
66
66
|
catch (err) {
|
|
67
67
|
this.logEvent({ message: 'Error', fn: 'sendUpdate', error: err.message });
|
package/lib/base/adpater.js
CHANGED
|
@@ -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 (
|
|
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) {
|
package/lib/ble/cp/adapter.js
CHANGED
|
@@ -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().
|
|
95
|
+
return this.getCyclingMode().buildUpdate(request);
|
|
96
96
|
}
|
|
97
97
|
catch (err) {
|
|
98
98
|
this.logEvent({ message: 'Error', fn: 'BleCP:sendUpdate', error: err.message });
|
package/lib/ble/cp/sensor.js
CHANGED
|
@@ -69,7 +69,7 @@ class BleCyclingPowerDevice extends sensor_1.TBleSensor {
|
|
|
69
69
|
this.time = time;
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
catch (
|
|
72
|
+
catch (_a) {
|
|
73
73
|
}
|
|
74
74
|
const { instantaneousPower, balance, accTorque, rpm, time } = this;
|
|
75
75
|
return { instantaneousPower, balance, accTorque, rpm, time, raw: `2a63:${data.toString('hex')}` };
|
package/lib/ble/fm/adapter.d.ts
CHANGED
|
@@ -33,4 +33,5 @@ export default class BleFmAdapter extends BleAdapter<IndoorBikeData, BleFitnessM
|
|
|
33
33
|
protected updateCapabilitiesFromFeatures(features: IndoorBikeFeatures): void;
|
|
34
34
|
sendUpdate(request: any, enforced?: boolean): Promise<UpdateRequest | void>;
|
|
35
35
|
sendInitCommands(): Promise<boolean>;
|
|
36
|
+
protected getFeatureToggle(): import("../../features").FeatureToggle;
|
|
36
37
|
}
|
package/lib/ble/fm/adapter.js
CHANGED
|
@@ -23,6 +23,7 @@ const types_1 = require("../../types");
|
|
|
23
23
|
const utils_1 = require("../../utils/utils");
|
|
24
24
|
const utils_2 = require("../utils");
|
|
25
25
|
const play_1 = require("../zwift/play");
|
|
26
|
+
const features_1 = require("../../features");
|
|
26
27
|
const ZWIFT_PLAY_UUID = '0000000119ca465186e5fa29dcdd09d1';
|
|
27
28
|
class BleFmAdapter extends adapter_1.default {
|
|
28
29
|
constructor(settings, props) {
|
|
@@ -49,6 +50,8 @@ class BleFmAdapter extends adapter_1.default {
|
|
|
49
50
|
}
|
|
50
51
|
supportsVirtualShifting() {
|
|
51
52
|
var _a, _b;
|
|
53
|
+
if (!this.getFeatureToggle().has('VirtualShifting'))
|
|
54
|
+
return false;
|
|
52
55
|
return (_b = (_a = this.device) === null || _a === void 0 ? void 0 : _a.getSupportedServiceUUids()) === null || _b === void 0 ? void 0 : _b.some(s => (0, utils_2.matches)(s, ZWIFT_PLAY_UUID));
|
|
53
56
|
}
|
|
54
57
|
getSupportedCyclingModes() {
|
|
@@ -264,7 +267,7 @@ class BleFmAdapter extends adapter_1.default {
|
|
|
264
267
|
if (!enforced && (this.stopped && !this.isStarting()))
|
|
265
268
|
return;
|
|
266
269
|
try {
|
|
267
|
-
const update = this.getCyclingMode().
|
|
270
|
+
const update = this.getCyclingMode().buildUpdate(request);
|
|
268
271
|
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
272
|
const device = this.getSensor();
|
|
270
273
|
if (this.hasCapability(types_1.IncyclistCapability.Control)) {
|
|
@@ -284,7 +287,7 @@ class BleFmAdapter extends adapter_1.default {
|
|
|
284
287
|
if (!this.zwiftPlay) {
|
|
285
288
|
this.initVirtualShifting();
|
|
286
289
|
}
|
|
287
|
-
if (this.zwiftPlay && !isNaN(update.gearRatio)) {
|
|
290
|
+
if (this.zwiftPlay && !Number.isNaN(update.gearRatio)) {
|
|
288
291
|
let slope = (_a = update.slope) !== null && _a !== void 0 ? _a : 0;
|
|
289
292
|
if (slope === 0)
|
|
290
293
|
slope = 0.01;
|
|
@@ -335,6 +338,9 @@ class BleFmAdapter extends adapter_1.default {
|
|
|
335
338
|
}
|
|
336
339
|
});
|
|
337
340
|
}
|
|
341
|
+
getFeatureToggle() {
|
|
342
|
+
return (0, features_1.useFeatureToggle)();
|
|
343
|
+
}
|
|
338
344
|
}
|
|
339
345
|
BleFmAdapter.INCYCLIST_PROFILE_NAME = 'Smart Trainer';
|
|
340
346
|
exports.default = BleFmAdapter;
|
package/lib/ble/hr/sensor.js
CHANGED
package/lib/ble/utils.js
CHANGED
|
@@ -52,7 +52,6 @@ class BleZwiftPlaySensor extends sensor_1.TBleSensor {
|
|
|
52
52
|
}
|
|
53
53
|
onData(characteristic, data, isNotify) {
|
|
54
54
|
const uuid = (0, utils_1.beautifyUUID)(characteristic).toLowerCase();
|
|
55
|
-
console.log('# data', uuid, data === null || data === void 0 ? void 0 : data.toString('hex'));
|
|
56
55
|
if (uuid === '00000002-19ca-4651-86e5-fa29dcdd09d1') {
|
|
57
56
|
this.onMeasurement(data);
|
|
58
57
|
}
|
|
@@ -387,7 +386,7 @@ class BleZwiftPlaySensor extends sensor_1.TBleSensor {
|
|
|
387
386
|
const { publicKey, privateKey } = this.createKeyPair();
|
|
388
387
|
this.privateKey = (_a = this.privateKey) !== null && _a !== void 0 ? _a : Buffer.from(privateKey);
|
|
389
388
|
this.publicKey = (_b = this.publicKey) !== null && _b !== void 0 ? _b : Buffer.from(publicKey);
|
|
390
|
-
message = Buffer.concat([Buffer.from('RideOn'), Buffer.from([
|
|
389
|
+
message = Buffer.concat([Buffer.from('RideOn'), Buffer.from([0x02, 0x03]), this.publicKey]);
|
|
391
390
|
}
|
|
392
391
|
yield this.write((0, utils_1.fullUUID)('00000003-19ca-4651-86e5-fa29dcdd09d1'), message, { withoutResponse: true });
|
|
393
392
|
this.isHubServicePaired = true;
|
|
@@ -154,7 +154,6 @@ class DirectConnectPeripheral {
|
|
|
154
154
|
if (this.subscribed.includes(uuid)) {
|
|
155
155
|
return true;
|
|
156
156
|
}
|
|
157
|
-
console.log('# subscribe ', characteristicUUID);
|
|
158
157
|
const seqNo = this.getNextSeqNo();
|
|
159
158
|
const message = new messages_1.EnableCharacteristicNotificationsMessage();
|
|
160
159
|
const request = message.createRequest(seqNo, { characteristicUUID: (0, utils_1.parseUUID)(characteristicUUID), enable: true });
|
|
@@ -18,5 +18,5 @@ export declare class DiscoverCharacteristicsMessage extends Message<TDCDiscoverC
|
|
|
18
18
|
parseRequestBody(body: Buffer): TDCDiscoverCharacteristicsRequestBody;
|
|
19
19
|
buildRequestBody(body: TDCDiscoverCharacteristicsRequestBody): Buffer;
|
|
20
20
|
buildResponseBody(body: TDCDiscoverCharacteristicsResponseBody): Buffer;
|
|
21
|
-
parseResponseBody(
|
|
21
|
+
parseResponseBody(responseBody: Buffer): TDCDiscoverCharacteristicsResponseBody;
|
|
22
22
|
}
|
|
@@ -25,9 +25,10 @@ class DiscoverCharacteristicsMessage extends message_1.Message {
|
|
|
25
25
|
]));
|
|
26
26
|
return Buffer.concat([serviceUUIDBuffer, ...characteristicBuffers]);
|
|
27
27
|
}
|
|
28
|
-
parseResponseBody(
|
|
28
|
+
parseResponseBody(responseBody) {
|
|
29
|
+
const body = Buffer.from(responseBody);
|
|
29
30
|
const length = body.length;
|
|
30
|
-
const serviceUUID = body.subarray(0, 16).toString("hex");
|
|
31
|
+
const serviceUUID = Buffer.from(body.subarray(0, 16)).toString("hex");
|
|
31
32
|
const characteristicDefinitions = [];
|
|
32
33
|
for (let i = 16; i < length; i += 17) {
|
|
33
34
|
const characteristicUUID = Buffer.from(body.subarray(i, i + 16)).toString("hex");
|
|
@@ -10,6 +10,6 @@ export interface TDCDiscoverServicesResponseBody extends TDCBody {
|
|
|
10
10
|
export declare class DiscoverServiceMessage extends Message<EmptyBody, TDCDiscoverServicesResponseBody> {
|
|
11
11
|
constructor();
|
|
12
12
|
buildResponseBody(body: TDCDiscoverServicesResponseBody): Buffer;
|
|
13
|
-
parseResponseBody(
|
|
13
|
+
parseResponseBody(responseBody: Buffer): TDCDiscoverServicesResponseBody;
|
|
14
14
|
verifyHeader(header: TDCMessageHeader): boolean;
|
|
15
15
|
}
|
|
@@ -12,13 +12,15 @@ class DiscoverServiceMessage extends message_1.Message {
|
|
|
12
12
|
const serviceBuffers = body.serviceDefinitions.map((service) => {
|
|
13
13
|
return Buffer.from(service.serviceUUID, "hex");
|
|
14
14
|
});
|
|
15
|
-
|
|
15
|
+
const response = Buffer.concat(serviceBuffers);
|
|
16
|
+
return response;
|
|
16
17
|
}
|
|
17
|
-
parseResponseBody(
|
|
18
|
+
parseResponseBody(responseBody) {
|
|
19
|
+
const body = Buffer.from(responseBody);
|
|
18
20
|
const serviceDefinitions = [];
|
|
19
21
|
const length = body.length;
|
|
20
22
|
for (let i = 0; i < length; i += 16) {
|
|
21
|
-
const serviceUUID = body.subarray(i, i + 16).toString("hex");
|
|
23
|
+
const serviceUUID = Buffer.from(body.subarray(i, i + 16)).toString("hex");
|
|
22
24
|
serviceDefinitions.push({ serviceUUID });
|
|
23
25
|
}
|
|
24
26
|
return { serviceDefinitions };
|
|
@@ -9,7 +9,7 @@ export declare class Message<TReq extends TDCBody, TRes extends TDCBody> {
|
|
|
9
9
|
createRequest(seqNum: any, body: TReq): Buffer;
|
|
10
10
|
parseRequest(buffer: Buffer): TDCRequest<TReq>;
|
|
11
11
|
prepareResponse(request: TDCRequest<TReq>, respCode: number, body: TRes): TDCResponse<TRes>;
|
|
12
|
-
parseResponse(
|
|
12
|
+
parseResponse(response: Buffer): TDCResponse<TRes>;
|
|
13
13
|
buildHeader(header: TDCMessageHeader, length: number): Buffer;
|
|
14
14
|
buildResponseBody(body: TRes): Buffer;
|
|
15
15
|
buildRequestBody(body: TReq): Buffer;
|
|
@@ -40,7 +40,8 @@ class Message {
|
|
|
40
40
|
const header = Object.assign(Object.assign({}, request.header), { respCode });
|
|
41
41
|
return { header, body };
|
|
42
42
|
}
|
|
43
|
-
parseResponse(
|
|
43
|
+
parseResponse(response) {
|
|
44
|
+
const buffer = Buffer.from(response);
|
|
44
45
|
const header = (0, exports.parseHeader)(buffer);
|
|
45
46
|
this.verifyHeader(header);
|
|
46
47
|
const bodyBuffer = buffer.subarray(6);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Feature = 'VirtualShifting';
|
|
2
|
+
export declare class FeatureToggle {
|
|
3
|
+
protected static _instance: FeatureToggle;
|
|
4
|
+
static getInstance(): FeatureToggle;
|
|
5
|
+
protected enabled: Array<string>;
|
|
6
|
+
constructor();
|
|
7
|
+
add(feature: Feature): void;
|
|
8
|
+
remove(feature: Feature): void;
|
|
9
|
+
has(feature: Feature): boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const useFeatureToggle: () => FeatureToggle;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useFeatureToggle = exports.FeatureToggle = void 0;
|
|
4
|
+
class FeatureToggle {
|
|
5
|
+
static getInstance() {
|
|
6
|
+
if (!FeatureToggle._instance)
|
|
7
|
+
FeatureToggle._instance = new FeatureToggle();
|
|
8
|
+
return FeatureToggle._instance;
|
|
9
|
+
}
|
|
10
|
+
constructor() {
|
|
11
|
+
this.enabled = [];
|
|
12
|
+
}
|
|
13
|
+
add(feature) {
|
|
14
|
+
this.enabled.push(feature);
|
|
15
|
+
}
|
|
16
|
+
remove(feature) {
|
|
17
|
+
const index = this.enabled.indexOf(feature);
|
|
18
|
+
if (index > -1)
|
|
19
|
+
this.enabled.splice(index, 1);
|
|
20
|
+
}
|
|
21
|
+
has(feature) {
|
|
22
|
+
return this.enabled.includes(feature);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.FeatureToggle = FeatureToggle;
|
|
26
|
+
const useFeatureToggle = () => {
|
|
27
|
+
return FeatureToggle.getInstance();
|
|
28
|
+
};
|
|
29
|
+
exports.useFeatureToggle = useFeatureToggle;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './features';
|
|
@@ -0,0 +1,17 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./features"), exports);
|
package/lib/index.d.ts
CHANGED
|
@@ -13,4 +13,5 @@ export * from './serial';
|
|
|
13
13
|
export * from './ble';
|
|
14
14
|
export * from './antv2';
|
|
15
15
|
export * from './direct-connect';
|
|
16
|
+
export * from './features';
|
|
16
17
|
export { IAdapter, IncyclistDevice, IncyclistDeviceAdapter, DeviceSettings, DeviceProperties, AdapterFactory, InterfaceFactory, IncyclistInterface, INTERFACE, InterfaceProps, ICyclingMode, IncyclistAdapterData as DeviceData, IncyclistCapability, calc, };
|
package/lib/index.js
CHANGED
|
@@ -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,13 +44,17 @@ 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;
|
|
58
|
+
protected getFeatureToogle(): import("../features").FeatureToggle;
|
|
54
59
|
}
|
|
55
60
|
export {};
|
|
@@ -39,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
const types_1 = require("./types");
|
|
40
40
|
const power_base_1 = __importDefault(require("./power-base"));
|
|
41
41
|
const calculations_1 = __importStar(require("../utils/calculations"));
|
|
42
|
+
const features_1 = require("../features");
|
|
42
43
|
const MIN_POWER = 25;
|
|
43
44
|
class SmartTrainerCyclingMode extends power_base_1.default {
|
|
44
45
|
constructor(adapter, props) {
|
|
@@ -71,6 +72,9 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
71
72
|
}
|
|
72
73
|
getConfig() {
|
|
73
74
|
const config = super.getConfig();
|
|
75
|
+
if (!this.getFeatureToogle().has('VirtualShifting')) {
|
|
76
|
+
return config;
|
|
77
|
+
}
|
|
74
78
|
let virtshift = config.properties.find(p => p.key === 'virtshift');
|
|
75
79
|
let startGear = config.properties.find(p => p.key === 'startGear');
|
|
76
80
|
if (!virtshift) {
|
|
@@ -90,7 +94,7 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
90
94
|
}
|
|
91
95
|
checkSlopeNoShiftig(request, newRequest = {}) {
|
|
92
96
|
if (request.slope !== undefined) {
|
|
93
|
-
const targetSlope = newRequest.slope = parseFloat(request.slope.toFixed(1));
|
|
97
|
+
const targetSlope = newRequest.slope = Number.parseFloat(request.slope.toFixed(1));
|
|
94
98
|
this.data.slope = newRequest.slope;
|
|
95
99
|
try {
|
|
96
100
|
const slopeAdj = targetSlope >= 0 ? this.getSetting('slopeAdj') : this.getSetting('slopeAdjDown');
|
|
@@ -112,7 +116,7 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
112
116
|
}
|
|
113
117
|
checkSlopeWithSlopeDelta(request, newRequest = {}) {
|
|
114
118
|
if (request.slope !== undefined) {
|
|
115
|
-
const targetSlope = newRequest.slope = parseFloat(request.slope.toFixed(1));
|
|
119
|
+
const targetSlope = newRequest.slope = Number.parseFloat(request.slope.toFixed(1));
|
|
116
120
|
this.data.slope = newRequest.slope;
|
|
117
121
|
const requestedSlope = targetSlope + this.getSlopeDelta();
|
|
118
122
|
try {
|
|
@@ -130,9 +134,13 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
130
134
|
this.checkSlopeNoShiftig(request, newRequest);
|
|
131
135
|
return;
|
|
132
136
|
}
|
|
133
|
-
if (request.slope
|
|
137
|
+
if (request.slope === undefined) {
|
|
138
|
+
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 });
|
|
139
|
+
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 });
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
134
142
|
const prev = (_a = this.data.slope) !== null && _a !== void 0 ? _a : 0;
|
|
135
|
-
this.data.slope = parseFloat(request.slope.toFixed(1));
|
|
143
|
+
this.data.slope = Number.parseFloat(request.slope.toFixed(1));
|
|
136
144
|
delete request.slope;
|
|
137
145
|
delete newRequest.slope;
|
|
138
146
|
this.simSlope = this.data.slope;
|
|
@@ -151,11 +159,13 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
151
159
|
const prevPower = this.data.power;
|
|
152
160
|
if (this.data.speed < 10 && this.data.isPedalling && (this.data.slope < 1 || this.data.speed === 0)) {
|
|
153
161
|
this.simPower = Math.max(newPower, prevPower);
|
|
154
|
-
|
|
162
|
+
console.log('# set simulated power', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
|
|
163
|
+
this.logger.logEvent({ message: 'set simulated power', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
|
|
155
164
|
}
|
|
156
165
|
else if (this.data.slope === prev && newPower < prevPower) {
|
|
157
166
|
this.simPower = prevPower;
|
|
158
|
-
|
|
167
|
+
console.log('# set simulated power:', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
|
|
168
|
+
this.logger.logEvent({ message: 'set simulated power', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
|
|
159
169
|
}
|
|
160
170
|
else {
|
|
161
171
|
const powerDiff = newPower - prevPower;
|
|
@@ -166,7 +176,8 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
166
176
|
const eKinAfter1sec = eKinPrev - powerDiff * 1;
|
|
167
177
|
const vAfter1sec = Math.sqrt(2 * eKinAfter1sec / m) * 3600 / 1000;
|
|
168
178
|
this.simPower = calculations_1.default.calculatePower(m, vAfter1sec / 3.6, (_e = this.simSlope) !== null && _e !== void 0 ? _e : 0);
|
|
169
|
-
|
|
179
|
+
console.log('# set simulated power (Ekin):', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, eKinPrev, eKinTarget, delta, prevPower, newPower });
|
|
180
|
+
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 });
|
|
170
181
|
}
|
|
171
182
|
this.verifySimPower();
|
|
172
183
|
}
|
|
@@ -190,8 +201,53 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
190
201
|
break;
|
|
191
202
|
}
|
|
192
203
|
}
|
|
193
|
-
|
|
204
|
+
checkCadenceChange(request, newRequest = {}) {
|
|
205
|
+
const virtshiftMode = this.getVirtualShiftMode();
|
|
206
|
+
if (virtshiftMode !== 'Simulated') {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (request.targetPower !== undefined || request.targetPowerDelta !== undefined || request.gearDelta !== undefined || request.gearRatio !== undefined) {
|
|
210
|
+
console.log('# cadence change ignored due to other power/gear request', request);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (this.data.pedalRpm !== this.prevData.pedalRpm) {
|
|
214
|
+
console.log('# cadence changed ', { cadence: this.data.pedalRpm, prevCadence: this.prevData.pedalRpm });
|
|
215
|
+
this.calculateSimulatedPower(request);
|
|
216
|
+
delete request.slope;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
calculateSimulatedPower(request) {
|
|
194
220
|
var _a, _b, _c, _d;
|
|
221
|
+
const m = (_b = (_a = this.adapter) === null || _a === void 0 ? void 0 : _a.getWeight()) !== null && _b !== void 0 ? _b : 85;
|
|
222
|
+
const vCurrent = this.data.speed * 1000 / 3600;
|
|
223
|
+
const eKinCurrent = m * vCurrent * vCurrent / 2;
|
|
224
|
+
if (this.data.pedalRpm > 0) {
|
|
225
|
+
const virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(this.data.pedalRpm, this.gearRatios[this.gear - 1]);
|
|
226
|
+
const newPower = calculations_1.default.calculatePower(m, virtualSpeed, (_c = this.simSlope) !== null && _c !== void 0 ? _c : 0);
|
|
227
|
+
const prevPower = this.data.power;
|
|
228
|
+
if (this.data.speed < 10 && this.data.isPedalling && (this.data.slope < 1 || this.data.speed === 0)) {
|
|
229
|
+
this.simPower = Math.max(newPower, prevPower);
|
|
230
|
+
console.log('# set simulated power (starting)', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
|
|
231
|
+
this.logger.logEvent({ message: 'set simulated power (starting)', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, prevPower, newPower });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
const powerDiff = newPower - prevPower;
|
|
235
|
+
const vTarget = virtualSpeed * 1000 / 3600;
|
|
236
|
+
const eKinTarget = m * vTarget * vTarget / 2;
|
|
237
|
+
const eKinPrev = eKinCurrent;
|
|
238
|
+
const delta = eKinTarget - eKinPrev;
|
|
239
|
+
const eKinAfter1sec = eKinPrev - powerDiff * 1;
|
|
240
|
+
const vAfter1sec = Math.sqrt(2 * eKinAfter1sec / m) * 3600 / 1000;
|
|
241
|
+
this.simPower = calculations_1.default.calculatePower(m, vAfter1sec / 3.6, (_d = this.simSlope) !== null && _d !== void 0 ? _d : 0);
|
|
242
|
+
console.log('# set simulated power (Ekin):', { power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope, eKinPrev, eKinTarget, delta, prevPower, newPower });
|
|
243
|
+
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 });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
delete this.simPower;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
checkGearChange(request, newRequest = {}) {
|
|
195
251
|
const virtshiftMode = this.getVirtualShiftMode();
|
|
196
252
|
switch (virtshiftMode) {
|
|
197
253
|
case 'SlopeDelta':
|
|
@@ -217,17 +273,10 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
217
273
|
this.gear = this.gearRatios.length;
|
|
218
274
|
}
|
|
219
275
|
delete request.gearDelta;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const m = (_b = (_a = this.adapter) === null || _a === void 0 ? void 0 : _a.getWeight()) !== null && _b !== void 0 ? _b : 85;
|
|
223
|
-
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);
|
|
224
|
-
this.verifySimPower();
|
|
225
|
-
this.logger.logEvent({ message: 'set simulater power', power: this.simPower, gear: this.gear, simSlope: this.simSlope, routeSlope: this.data.slope });
|
|
276
|
+
this.calculateSimulatedPower(request);
|
|
277
|
+
if (this.simPower !== undefined) {
|
|
226
278
|
this.adapter.sendUpdate({ targetPower: this.simPower }).then(() => { });
|
|
227
279
|
}
|
|
228
|
-
else {
|
|
229
|
-
delete this.simPower;
|
|
230
|
-
}
|
|
231
280
|
}
|
|
232
281
|
break;
|
|
233
282
|
case 'Adapter':
|
|
@@ -297,6 +346,9 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
297
346
|
}
|
|
298
347
|
}
|
|
299
348
|
getVirtualShiftMode() {
|
|
349
|
+
if (!this.getFeatureToogle().has('VirtualShifting')) {
|
|
350
|
+
return 'Disabled';
|
|
351
|
+
}
|
|
300
352
|
const virtshiftMode = this.getSetting('virtshift');
|
|
301
353
|
if (virtshiftMode === 'Disabled') {
|
|
302
354
|
return 'Disabled';
|
|
@@ -316,8 +368,8 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
316
368
|
return 'Disabled';
|
|
317
369
|
}
|
|
318
370
|
updateData(bikeData, log) {
|
|
319
|
-
var _a
|
|
320
|
-
const prev = Object.assign({}, this.data);
|
|
371
|
+
var _a;
|
|
372
|
+
const prev = this.prevData = Object.assign({}, this.data);
|
|
321
373
|
const data = super.updateData(bikeData, log);
|
|
322
374
|
const mode = this.getVirtualShiftMode();
|
|
323
375
|
let virtualSpeed;
|
|
@@ -332,14 +384,6 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
332
384
|
this.gear = (_a = this.getSetting('startGear')) !== null && _a !== void 0 ? _a : 0;
|
|
333
385
|
data.gearStr = this.getGearString();
|
|
334
386
|
}
|
|
335
|
-
else if (this.gear !== undefined) {
|
|
336
|
-
if (prev.power !== data.power || prev.pedalRpm !== data.pedalRpm) {
|
|
337
|
-
virtualSpeed = (0, calculations_1.calculateVirtualSpeed)(data.pedalRpm, this.gearRatios[this.gear - 1]);
|
|
338
|
-
const m = (_c = (_b = this.adapter) === null || _b === void 0 ? void 0 : _b.getWeight()) !== null && _c !== void 0 ? _c : 85;
|
|
339
|
-
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);
|
|
340
|
-
this.verifySimPower();
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
387
|
return data;
|
|
344
388
|
}
|
|
345
389
|
getData() {
|
|
@@ -347,6 +391,13 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
347
391
|
const data = super.getData();
|
|
348
392
|
return Object.assign(Object.assign({}, data), { gearStr });
|
|
349
393
|
}
|
|
394
|
+
updateRequired(request) {
|
|
395
|
+
const virtshiftMode = this.getVirtualShiftMode();
|
|
396
|
+
if (virtshiftMode === 'Adapter' || virtshiftMode === 'Simulated') {
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
return super.updateRequired(request);
|
|
400
|
+
}
|
|
350
401
|
sendBikeUpdate(incoming) {
|
|
351
402
|
this.logger.logEvent({ message: "processing update request", request: incoming, prev: this.prevRequest, data: this.getData() });
|
|
352
403
|
let newRequest = {};
|
|
@@ -356,6 +407,7 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
356
407
|
if (req) {
|
|
357
408
|
return req;
|
|
358
409
|
}
|
|
410
|
+
this.checkCadenceChange(request, newRequest);
|
|
359
411
|
this.checkGearChange(request, newRequest);
|
|
360
412
|
this.checkSlope(request, newRequest);
|
|
361
413
|
this.checkEmptyRequest(newRequest);
|
|
@@ -384,6 +436,9 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
384
436
|
}
|
|
385
437
|
return (_d = this.gear) === null || _d === void 0 ? void 0 : _d.toString();
|
|
386
438
|
}
|
|
439
|
+
getFeatureToogle() {
|
|
440
|
+
return (0, features_1.useFeatureToggle)();
|
|
441
|
+
}
|
|
387
442
|
}
|
|
388
443
|
SmartTrainerCyclingMode.config = {
|
|
389
444
|
name: "Smart Trainer",
|
package/lib/modes/base.d.ts
CHANGED
|
@@ -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;
|