incyclist-devices 2.3.38 → 2.3.41
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/base/interface.d.ts +2 -1
- package/lib/antv2/base/interface.js +2 -0
- package/lib/ble/base/interface.d.ts +1 -0
- package/lib/ble/base/interface.js +2 -0
- package/lib/ble/cp/sensor.js +1 -1
- package/lib/ble/fm/adapter.d.ts +1 -0
- package/lib/ble/fm/adapter.js +7 -1
- package/lib/ble/hr/sensor.js +1 -1
- package/lib/ble/types.d.ts +1 -0
- package/lib/ble/utils.js +1 -1
- package/lib/ble/zwift/play/sensor.js +0 -1
- package/lib/direct-connect/base/interface.d.ts +4 -0
- package/lib/direct-connect/base/interface.js +60 -3
- 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 +1 -0
- package/lib/modes/antble-smarttrainer.js +18 -9
- package/lib/modes/daum-premium-standard.js +1 -1
- package/lib/modes/daum-smarttrainer.js +7 -7
- package/lib/serial/base/serial-interface.d.ts +2 -1
- package/lib/serial/base/serial-interface.js +2 -0
- package/lib/serial/bindings/tcp.js +8 -8
- 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 +41 -48
- package/lib/types/interface.d.ts +1 -0
- package/lib/utils/utils.js +5 -5
- package/package.json +1 -1
|
@@ -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 {
|
|
@@ -2,7 +2,7 @@ import EventEmitter from "events";
|
|
|
2
2
|
import { EventLogger } from "gd-eventlog";
|
|
3
3
|
import { Channel, IAntDevice, IChannel, ISensor } from "incyclist-ant-plus";
|
|
4
4
|
import { AntDeviceSettings, AntScanProps, AntInterfaceProps } from "../types";
|
|
5
|
-
import { IncyclistInterface } from "../../types";
|
|
5
|
+
import { DeviceSettings, IncyclistInterface } from "../../types";
|
|
6
6
|
import AntDeviceBinding from "./binding";
|
|
7
7
|
type ChannelUsage = 'scan' | 'sensor';
|
|
8
8
|
interface ChannelInfo {
|
|
@@ -52,5 +52,6 @@ export default class AntInterface extends EventEmitter implements IncyclistInter
|
|
|
52
52
|
private blockChannel;
|
|
53
53
|
private unblockChannel;
|
|
54
54
|
stopSensor(sensor: ISensor): Promise<boolean>;
|
|
55
|
+
addKnownDevice(_settings: DeviceSettings): void;
|
|
55
56
|
}
|
|
56
57
|
export {};
|
|
@@ -94,6 +94,7 @@ export declare class BleInterface extends EventEmitter implements IBleInterface<
|
|
|
94
94
|
protected find(service: BlePeripheralAnnouncement): Announcement;
|
|
95
95
|
protected getAll(): Announcement[];
|
|
96
96
|
setDebug(enabled: boolean): void;
|
|
97
|
+
addKnownDevice(_settings: BleDeviceSettings): void;
|
|
97
98
|
protected connectBle(): Promise<boolean>;
|
|
98
99
|
protected waitForBleConnected(): Promise<boolean>;
|
|
99
100
|
protected onError(err: Error): void;
|
|
@@ -583,6 +583,8 @@ class BleInterface extends events_1.default {
|
|
|
583
583
|
setDebug(enabled) {
|
|
584
584
|
this.debug = enabled;
|
|
585
585
|
}
|
|
586
|
+
addKnownDevice(_settings) {
|
|
587
|
+
}
|
|
586
588
|
connectBle() {
|
|
587
589
|
return __awaiter(this, void 0, void 0, function* () {
|
|
588
590
|
this.currentBleState = this.getBinding().state;
|
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() {
|
|
@@ -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/types.d.ts
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
|
}
|
|
@@ -11,6 +11,7 @@ import { InterfaceFactory } from "../../ble/base/types";
|
|
|
11
11
|
interface Announcement {
|
|
12
12
|
service: MulticastDnsAnnouncement;
|
|
13
13
|
ts: number;
|
|
14
|
+
source?: string;
|
|
14
15
|
}
|
|
15
16
|
export default class DirectConnectInterface extends EventEmitter implements IBleInterface<MulticastDnsAnnouncement> {
|
|
16
17
|
protected static _instance: DirectConnectInterface;
|
|
@@ -33,6 +34,7 @@ export default class DirectConnectInterface extends EventEmitter implements IBle
|
|
|
33
34
|
createPeripheral(announcement: MulticastDnsAnnouncement): IBlePeripheral;
|
|
34
35
|
createDeviceSetting(service: MulticastDnsAnnouncement): BleDeviceSettings;
|
|
35
36
|
createPeripheralFromSettings(settings: DeviceSettings): IBlePeripheral;
|
|
37
|
+
addKnownDevice(settings: BleDeviceSettings): void;
|
|
36
38
|
getLogger(): EventLogger;
|
|
37
39
|
setLogger(logger: EventLogger): void;
|
|
38
40
|
getName(): string;
|
|
@@ -66,6 +68,8 @@ export default class DirectConnectInterface extends EventEmitter implements IBle
|
|
|
66
68
|
logError(err: Error, fn: string, args?: any): void;
|
|
67
69
|
protected getProtocol(announcement: MulticastDnsAnnouncement): BleProtocol;
|
|
68
70
|
protected getBestDeviceMatch(DeviceClasses: (typeof TBleSensor)[]): typeof TBleSensor;
|
|
71
|
+
protected createAnnouncementFromSettings(settings: BleDeviceSettings): MulticastDnsAnnouncement;
|
|
72
|
+
protected getServiceUUIDs(settings: BleDeviceSettings): string[];
|
|
69
73
|
protected getAdapterFactory(): BleAdapterFactory<any>;
|
|
70
74
|
}
|
|
71
75
|
export declare class DirectConnectInterfaceFactory extends InterfaceFactory {
|
|
@@ -19,7 +19,10 @@ const task_1 = require("../../utils/task");
|
|
|
19
19
|
const peripheral_1 = require("./peripheral");
|
|
20
20
|
const ble_1 = require("../../ble");
|
|
21
21
|
const types_1 = require("../../ble/base/types");
|
|
22
|
+
const consts_1 = require("../../ble/consts");
|
|
23
|
+
const consts_2 = require("../../ble/wahoo/consts");
|
|
22
24
|
const DC_TYPE = 'wahoo-fitness-tnp';
|
|
25
|
+
const DC_PORT = 36866;
|
|
23
26
|
const DC_EXPIRATION_TIMEOUT = 10 * 1000 * 60;
|
|
24
27
|
let instanceId = 0;
|
|
25
28
|
class DirectConnectInterface extends events_1.default {
|
|
@@ -66,12 +69,16 @@ class DirectConnectInterface extends events_1.default {
|
|
|
66
69
|
return peripheral_1.DirectConnectPeripheral.create(announcement);
|
|
67
70
|
}
|
|
68
71
|
createDeviceSetting(service) {
|
|
72
|
+
var _a, _b;
|
|
69
73
|
try {
|
|
70
74
|
const name = service.name;
|
|
71
75
|
const protocol = this.getProtocol(service);
|
|
72
|
-
|
|
76
|
+
const address = service.address;
|
|
77
|
+
const services = (_b = (_a = service.serviceUUIDs) === null || _a === void 0 ? void 0 : _a.map(uuid => (0, ble_1.beautifyUUID)(uuid, false))) === null || _b === void 0 ? void 0 : _b.join(',');
|
|
78
|
+
console.log('# created device setting from announcement', name, service.serviceUUIDs, services);
|
|
79
|
+
return { interface: DirectConnectInterface.INTERFACE_NAME, name, protocol, address, services };
|
|
73
80
|
}
|
|
74
|
-
catch (
|
|
81
|
+
catch (_c) {
|
|
75
82
|
return null;
|
|
76
83
|
}
|
|
77
84
|
}
|
|
@@ -81,6 +88,12 @@ class DirectConnectInterface extends events_1.default {
|
|
|
81
88
|
return null;
|
|
82
89
|
return this.createPeripheral(info.service);
|
|
83
90
|
}
|
|
91
|
+
addKnownDevice(settings) {
|
|
92
|
+
const announcement = this.createAnnouncementFromSettings(settings);
|
|
93
|
+
if (announcement) {
|
|
94
|
+
this.addService(announcement, 'known-device');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
84
97
|
getLogger() {
|
|
85
98
|
return this.logger;
|
|
86
99
|
}
|
|
@@ -236,6 +249,7 @@ class DirectConnectInterface extends events_1.default {
|
|
|
236
249
|
const device = this.createDeviceSetting(service);
|
|
237
250
|
if (!device)
|
|
238
251
|
return;
|
|
252
|
+
console.log('# emitting device', device, service);
|
|
239
253
|
this.emit('device', device, service);
|
|
240
254
|
}
|
|
241
255
|
buildDeviceSettings(matching = []) {
|
|
@@ -243,15 +257,22 @@ class DirectConnectInterface extends events_1.default {
|
|
|
243
257
|
}
|
|
244
258
|
addService(service, source) {
|
|
245
259
|
var _a, _b;
|
|
260
|
+
console.log(`# DirectConnectInterface.addService from ${source}`, service.name, service.serviceUUIDs);
|
|
261
|
+
const src = source === 'known-device' ? 'known-device' : 'mdns';
|
|
246
262
|
try {
|
|
247
263
|
service.transport = this.getName();
|
|
248
264
|
const existing = this.find(service);
|
|
249
265
|
if (existing) {
|
|
250
266
|
const idx = this.services.indexOf(existing);
|
|
251
267
|
this.services[idx] = { ts: Date.now(), service };
|
|
268
|
+
if (src !== 'known-device' && existing.source === 'known-device') {
|
|
269
|
+
this.services[idx].source = src;
|
|
270
|
+
this.logEvent({ message: 'device re-announced', device: service.name, announcement: service, source });
|
|
271
|
+
this.emitDevice(service);
|
|
272
|
+
}
|
|
252
273
|
}
|
|
253
274
|
else {
|
|
254
|
-
this.services.push({ ts: Date.now(), service });
|
|
275
|
+
this.services.push({ ts: Date.now(), service, source: src });
|
|
255
276
|
if (!((_a = service.serviceUUIDs) === null || _a === void 0 ? void 0 : _a.length))
|
|
256
277
|
return;
|
|
257
278
|
this.logEvent({ message: 'device announced', device: service.name, announcement: service, source });
|
|
@@ -306,6 +327,42 @@ class DirectConnectInterface extends events_1.default {
|
|
|
306
327
|
details.sort((a, b) => b.priority - a.priority);
|
|
307
328
|
return details[0].class;
|
|
308
329
|
}
|
|
330
|
+
createAnnouncementFromSettings(settings) {
|
|
331
|
+
if (settings.protocol && settings.address) {
|
|
332
|
+
const announcement = {
|
|
333
|
+
name: settings.name,
|
|
334
|
+
address: settings.address,
|
|
335
|
+
protocol: 'tcp',
|
|
336
|
+
port: DC_PORT,
|
|
337
|
+
type: DC_TYPE,
|
|
338
|
+
transport: 'wifi',
|
|
339
|
+
serviceUUIDs: this.getServiceUUIDs(settings),
|
|
340
|
+
};
|
|
341
|
+
console.log('# created announcement from settings', announcement);
|
|
342
|
+
return announcement;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
getServiceUUIDs(settings) {
|
|
346
|
+
if (settings.services && settings.services.length > 0) {
|
|
347
|
+
return settings.services.split(',').map(s => s.trim());
|
|
348
|
+
}
|
|
349
|
+
switch (settings.protocol) {
|
|
350
|
+
case 'fm':
|
|
351
|
+
return ['1826'];
|
|
352
|
+
case 'hr':
|
|
353
|
+
return ['180d'];
|
|
354
|
+
case 'wahoo':
|
|
355
|
+
return [consts_1.CSP, consts_2.WAHOO_ADVANCED_FTMS];
|
|
356
|
+
case 'cp':
|
|
357
|
+
return [consts_1.CSP];
|
|
358
|
+
case 'csc':
|
|
359
|
+
return [consts_1.CSC];
|
|
360
|
+
case 'zwift-play':
|
|
361
|
+
return ['0000000119ca465186e5fa29dcdd09d1'];
|
|
362
|
+
default:
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
309
366
|
getAdapterFactory() {
|
|
310
367
|
return ble_1.BleAdapterFactory.getInstance('wifi');
|
|
311
368
|
}
|
|
@@ -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
|
@@ -55,5 +55,6 @@ export default class SmartTrainerCyclingMode extends PowerBasedCyclingModeBase i
|
|
|
55
55
|
protected updateRequired(request?: UpdateRequest): boolean;
|
|
56
56
|
sendBikeUpdate(incoming: UpdateRequest): UpdateRequest;
|
|
57
57
|
protected getGearString(): string;
|
|
58
|
+
protected getFeatureToogle(): import("../features").FeatureToggle;
|
|
58
59
|
}
|
|
59
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;
|
|
@@ -173,10 +181,6 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
173
181
|
}
|
|
174
182
|
this.verifySimPower();
|
|
175
183
|
}
|
|
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 });
|
|
179
|
-
}
|
|
180
184
|
newRequest.targetPower = this.simPower;
|
|
181
185
|
}
|
|
182
186
|
checkSlope(request, newRequest = {}) {
|
|
@@ -342,6 +346,9 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
342
346
|
}
|
|
343
347
|
}
|
|
344
348
|
getVirtualShiftMode() {
|
|
349
|
+
if (!this.getFeatureToogle().has('VirtualShifting')) {
|
|
350
|
+
return 'Disabled';
|
|
351
|
+
}
|
|
345
352
|
const virtshiftMode = this.getSetting('virtshift');
|
|
346
353
|
if (virtshiftMode === 'Disabled') {
|
|
347
354
|
return 'Disabled';
|
|
@@ -385,7 +392,6 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
385
392
|
return Object.assign(Object.assign({}, data), { gearStr });
|
|
386
393
|
}
|
|
387
394
|
updateRequired(request) {
|
|
388
|
-
console.log('# SmartTrainerCyclingMode updateRequired check');
|
|
389
395
|
const virtshiftMode = this.getVirtualShiftMode();
|
|
390
396
|
if (virtshiftMode === 'Adapter' || virtshiftMode === 'Simulated') {
|
|
391
397
|
return true;
|
|
@@ -430,6 +436,9 @@ class SmartTrainerCyclingMode extends power_base_1.default {
|
|
|
430
436
|
}
|
|
431
437
|
return (_d = this.gear) === null || _d === void 0 ? void 0 : _d.toString();
|
|
432
438
|
}
|
|
439
|
+
getFeatureToogle() {
|
|
440
|
+
return (0, features_1.useFeatureToggle)();
|
|
441
|
+
}
|
|
433
442
|
}
|
|
434
443
|
SmartTrainerCyclingMode.config = {
|
|
435
444
|
name: "Smart Trainer",
|
|
@@ -43,7 +43,7 @@ class DaumClassicCyclingMode extends power_meter_1.default {
|
|
|
43
43
|
this.distanceOffset = calculateDistance - distanceBike;
|
|
44
44
|
distanceInternal = calculateDistance;
|
|
45
45
|
}
|
|
46
|
-
data.speed = parseFloat(speed.toFixed(1));
|
|
46
|
+
data.speed = Number.parseFloat(speed.toFixed(1));
|
|
47
47
|
data.power = Math.round(power);
|
|
48
48
|
data.distanceInternal = distanceInternal;
|
|
49
49
|
data.slope = slope;
|
|
@@ -53,12 +53,11 @@ class SmartTrainerCyclingMode extends base_1.CyclingModeBase {
|
|
|
53
53
|
const minMaxStr = this.getSetting(`${source}Rings`);
|
|
54
54
|
const values = minMaxStr.split('-');
|
|
55
55
|
if (values[0] && values[1] && values[0] < values[1]) {
|
|
56
|
-
return [parseInt(values[0]), parseInt(values[1])];
|
|
56
|
+
return [Number.parseInt(values[0]), Number.parseInt(values[1])];
|
|
57
57
|
}
|
|
58
58
|
if (values[0] && values[1] && values[0] > values[1]) {
|
|
59
|
-
return [parseInt(values[1]), parseInt(values[0])];
|
|
59
|
+
return [Number.parseInt(values[1]), Number.parseInt(values[0])];
|
|
60
60
|
}
|
|
61
|
-
return;
|
|
62
61
|
}
|
|
63
62
|
sendBikeUpdate(request) {
|
|
64
63
|
const getData = () => {
|
|
@@ -70,7 +69,7 @@ class SmartTrainerCyclingMode extends base_1.CyclingModeBase {
|
|
|
70
69
|
const event = Object.assign({}, this.event);
|
|
71
70
|
if (this.data === undefined)
|
|
72
71
|
event.noData = true;
|
|
73
|
-
const slope = request.slope === undefined ? request.slope : parseFloat(request.slope.toFixed(1));
|
|
72
|
+
const slope = request.slope === undefined ? request.slope : Number.parseFloat(request.slope.toFixed(1));
|
|
74
73
|
if (slope !== undefined && (event.noData || Math.abs(slope - this.data.slope) >= 0.1))
|
|
75
74
|
event.slopeUpdate = true;
|
|
76
75
|
if (this.prevRequest === undefined)
|
|
@@ -231,7 +230,7 @@ class SmartTrainerCyclingMode extends base_1.CyclingModeBase {
|
|
|
231
230
|
const v = speed / 3.6;
|
|
232
231
|
distanceInternal += (v * duration);
|
|
233
232
|
}
|
|
234
|
-
data.speed = parseFloat(speed.toFixed(1));
|
|
233
|
+
data.speed = Number.parseFloat(speed.toFixed(1));
|
|
235
234
|
data.power = Math.round(power);
|
|
236
235
|
data.distanceInternal = distanceInternal;
|
|
237
236
|
data.distance = distance;
|
|
@@ -294,17 +293,18 @@ class SmartTrainerCyclingMode extends base_1.CyclingModeBase {
|
|
|
294
293
|
return speed;
|
|
295
294
|
}
|
|
296
295
|
calculateTargetPower(request, speed) {
|
|
296
|
+
var _a, _b;
|
|
297
297
|
const defaultPower = this.getSetting('startPower');
|
|
298
298
|
const minPower = this.getSetting('minPower');
|
|
299
299
|
const bikeType = this.getSetting('bikeType').toLowerCase();
|
|
300
300
|
const m = this.getWeight();
|
|
301
301
|
const prevData = this.data || {};
|
|
302
|
-
const slope = parseFloat((request.slope
|
|
302
|
+
const slope = Number.parseFloat(((_b = (_a = request.slope) !== null && _a !== void 0 ? _a : prevData.slope) !== null && _b !== void 0 ? _b : 0).toFixed(1));
|
|
303
303
|
let target = request.targetPower || defaultPower;
|
|
304
304
|
if (prevData.speed !== undefined || speed !== undefined) {
|
|
305
305
|
const v = speed ? speed / 3.6 : prevData.speed / 3.6;
|
|
306
306
|
const calculatedPower = calculations_1.default.calculatePower(m, v, slope, { bikeType });
|
|
307
|
-
const power = (calculatedPower
|
|
307
|
+
const power = Math.max(calculatedPower, minPower);
|
|
308
308
|
let belowMin = (calculatedPower < minPower);
|
|
309
309
|
const powerDelta = power - prevData.power || 0;
|
|
310
310
|
let target;
|
|
@@ -2,7 +2,7 @@ import EventEmitter from "events";
|
|
|
2
2
|
import { BindingInterface } from "@serialport/bindings-interface";
|
|
3
3
|
import { SerialPortStream } from '@serialport/stream';
|
|
4
4
|
import { SerialDeviceSettings, SerialScannerProps, PortMapping, SerialInterfaceProps } from "../types";
|
|
5
|
-
import { IncyclistInterface } from "../../types";
|
|
5
|
+
import { DeviceSettings, IncyclistInterface } from "../../types";
|
|
6
6
|
import { EventLogger } from "gd-eventlog";
|
|
7
7
|
export default class SerialInterface extends EventEmitter implements IncyclistInterface {
|
|
8
8
|
ifaceName: string;
|
|
@@ -31,4 +31,5 @@ export default class SerialInterface extends EventEmitter implements IncyclistIn
|
|
|
31
31
|
closePort(path: string): Promise<Boolean>;
|
|
32
32
|
scan(props: SerialScannerProps): Promise<SerialDeviceSettings[]>;
|
|
33
33
|
stopScan(): Promise<boolean>;
|
|
34
|
+
addKnownDevice(_settings: DeviceSettings): void;
|
|
34
35
|
}
|
|
@@ -38,7 +38,7 @@ function scanPort(host, port) {
|
|
|
38
38
|
try {
|
|
39
39
|
socket.destroy();
|
|
40
40
|
}
|
|
41
|
-
catch (
|
|
41
|
+
catch (_a) { }
|
|
42
42
|
socket.removeAllListeners();
|
|
43
43
|
};
|
|
44
44
|
socket.setTimeout(1000);
|
|
@@ -47,7 +47,7 @@ function scanPort(host, port) {
|
|
|
47
47
|
socket.on('ready', () => { resolve(true); cleanup(); });
|
|
48
48
|
socket.connect(port, host);
|
|
49
49
|
}
|
|
50
|
-
catch (
|
|
50
|
+
catch (_a) {
|
|
51
51
|
resolve(false);
|
|
52
52
|
}
|
|
53
53
|
});
|
|
@@ -109,10 +109,10 @@ exports.TCPBinding = {
|
|
|
109
109
|
return reject(new TypeError('"path" is not valid'));
|
|
110
110
|
host = res[0];
|
|
111
111
|
port = Number(res[1]);
|
|
112
|
-
if (isNaN(port))
|
|
112
|
+
if (Number.isNaN(port))
|
|
113
113
|
return reject(new TypeError('"path" is not valid'));
|
|
114
114
|
}
|
|
115
|
-
catch (
|
|
115
|
+
catch (_a) {
|
|
116
116
|
return reject(new TypeError('"path" is not valid'));
|
|
117
117
|
}
|
|
118
118
|
const socket = new net_1.default.Socket();
|
|
@@ -207,11 +207,11 @@ class TCPPortBinding {
|
|
|
207
207
|
if (!Buffer.isBuffer(buffer)) {
|
|
208
208
|
throw new TypeError('"buffer" is not a Buffer');
|
|
209
209
|
}
|
|
210
|
-
if (typeof offset !== 'number' || isNaN(offset)) {
|
|
211
|
-
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
|
210
|
+
if (typeof offset !== 'number' || Number.isNaN(offset)) {
|
|
211
|
+
throw new TypeError(`"offset" is not an integer got "${Number.isNaN(offset) ? 'NaN' : typeof offset}"`);
|
|
212
212
|
}
|
|
213
|
-
if (typeof length !== 'number' || isNaN(length)) {
|
|
214
|
-
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
|
213
|
+
if (typeof length !== 'number' || Number.isNaN(length)) {
|
|
214
|
+
throw new TypeError(`"length" is not an integer got "${Number.isNaN(length) ? 'NaN' : typeof length}"`);
|
|
215
215
|
}
|
|
216
216
|
if (buffer.length < offset + length) {
|
|
217
217
|
throw new Error('buffer is too small');
|
|
@@ -4,7 +4,7 @@ import { SerialDeviceSettings, SerialCommProps } from "../../types";
|
|
|
4
4
|
import { IncyclistBikeData, ControllerConfig } from "../../../types";
|
|
5
5
|
import Daum8008 from './comms';
|
|
6
6
|
export default class DaumClassicAdapter extends DaumAdapter<SerialDeviceSettings, DaumClassicProperties, Daum8008> {
|
|
7
|
-
static NAME
|
|
7
|
+
static readonly NAME = "Daum Classic";
|
|
8
8
|
protected static controllers: ControllerConfig;
|
|
9
9
|
protected name: string;
|
|
10
10
|
protected id: string;
|
|
@@ -41,7 +41,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
41
41
|
else {
|
|
42
42
|
serial = props.interface;
|
|
43
43
|
}
|
|
44
|
-
if (!serial ||
|
|
44
|
+
if (!(serial === null || serial === void 0 ? void 0 : serial.binding))
|
|
45
45
|
throw new Error(`unknonwn interface: ${ifaceName}`);
|
|
46
46
|
const path = `${port}`;
|
|
47
47
|
return { serial, path };
|
|
@@ -57,8 +57,8 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
57
57
|
}
|
|
58
58
|
performCheck() {
|
|
59
59
|
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
-
|
|
61
|
-
const check =
|
|
60
|
+
const info = {};
|
|
61
|
+
const check = () => __awaiter(this, void 0, void 0, function* () {
|
|
62
62
|
this.logEvent({ message: "checking device", port: this.getPort() });
|
|
63
63
|
try {
|
|
64
64
|
yield this.stop();
|
|
@@ -66,8 +66,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
66
66
|
this.logEvent({ message: "checking device failed", port: this.getPort(), reason: 'timeout' });
|
|
67
67
|
});
|
|
68
68
|
if (!connected) {
|
|
69
|
-
|
|
70
|
-
return;
|
|
69
|
+
return false;
|
|
71
70
|
}
|
|
72
71
|
this.stopped = false;
|
|
73
72
|
const address = yield this.getComms().getAddress();
|
|
@@ -79,14 +78,14 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
79
78
|
this.pause();
|
|
80
79
|
this.started = false;
|
|
81
80
|
this.logEvent({ message: "checking device success", port: this.getPort(), info });
|
|
82
|
-
|
|
81
|
+
return true;
|
|
83
82
|
}
|
|
84
83
|
catch (err) {
|
|
85
84
|
this.logEvent({ message: "checking device failed", port: this.getPort(), reason: err.message });
|
|
86
|
-
|
|
85
|
+
return false;
|
|
87
86
|
}
|
|
88
|
-
})
|
|
89
|
-
return yield (0, utils_1.waitWithTimeout)(check, 5000, () => {
|
|
87
|
+
});
|
|
88
|
+
return yield (0, utils_1.waitWithTimeout)(check(), 5000, () => {
|
|
90
89
|
this.logEvent({ message: "checking device failed", port: this.getPort(), reason: 'Timeout' });
|
|
91
90
|
return false;
|
|
92
91
|
});
|
|
@@ -128,7 +127,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
128
127
|
try {
|
|
129
128
|
yield this.getComms().setBikeType(bikeType.toLowerCase());
|
|
130
129
|
}
|
|
131
|
-
catch (
|
|
130
|
+
catch (_a) {
|
|
132
131
|
}
|
|
133
132
|
startState.setBikeType = true;
|
|
134
133
|
}
|
|
@@ -405,25 +405,25 @@ class Daum8i extends comms_1.default {
|
|
|
405
405
|
return __awaiter(this, void 0, void 0, function* () {
|
|
406
406
|
const powerStr = typeof power === 'string' ? Number.parseFloat(power).toFixed(2) : power.toFixed(2);
|
|
407
407
|
const str = yield this.sendStrCommand('setPower', `S23${powerStr}`);
|
|
408
|
-
return parseInt(str);
|
|
408
|
+
return Number.parseInt(str);
|
|
409
409
|
});
|
|
410
410
|
}
|
|
411
411
|
getPower() {
|
|
412
412
|
return __awaiter(this, void 0, void 0, function* () {
|
|
413
413
|
const str = yield this.sendStrCommand('getPower', 'S23');
|
|
414
|
-
return parseInt(str);
|
|
414
|
+
return Number.parseInt(str);
|
|
415
415
|
});
|
|
416
416
|
}
|
|
417
417
|
setGear(gear) {
|
|
418
418
|
return __awaiter(this, void 0, void 0, function* () {
|
|
419
419
|
const str = yield this.sendStrCommand('setGear', `M71${gear}`);
|
|
420
|
-
return parseInt(str);
|
|
420
|
+
return Number.parseInt(str);
|
|
421
421
|
});
|
|
422
422
|
}
|
|
423
423
|
getGear() {
|
|
424
424
|
return __awaiter(this, void 0, void 0, function* () {
|
|
425
425
|
const str = yield this.sendStrCommand('getGear', 'M71');
|
|
426
|
-
return parseInt(str);
|
|
426
|
+
return Number.parseInt(str);
|
|
427
427
|
});
|
|
428
428
|
}
|
|
429
429
|
sendReservedDaum8iCommand(logString, command, data) {
|
|
@@ -442,7 +442,7 @@ class Daum8i extends comms_1.default {
|
|
|
442
442
|
}
|
|
443
443
|
const cmdData = Uint8Array.from(buffer);
|
|
444
444
|
const res = yield this.sendBinaryCommand(logString || 'ReservedCommand', 'M70', (0, utils_1.bin2esc)(cmdData));
|
|
445
|
-
const resData = Uint8Array.from(res, x => x.
|
|
445
|
+
const resData = Uint8Array.from(res, x => x.codePointAt(0));
|
|
446
446
|
const cmd = (0, utils_1.esc2bin)(resData);
|
|
447
447
|
return cmd;
|
|
448
448
|
});
|
|
@@ -26,7 +26,7 @@ exports.DEBUG_LOGGER = {
|
|
|
26
26
|
logEvent: (event) => console.log(JSON.stringify(event))
|
|
27
27
|
};
|
|
28
28
|
const GS = 0x1D;
|
|
29
|
-
const GS_CHAR = String.
|
|
29
|
+
const GS_CHAR = String.fromCodePoint(GS);
|
|
30
30
|
function responseLog(str) {
|
|
31
31
|
if (str.includes(GS_CHAR)) {
|
|
32
32
|
return str.split(GS_CHAR).join('/');
|
|
@@ -177,7 +177,7 @@ function hexstr(arr, start, len) {
|
|
|
177
177
|
return str;
|
|
178
178
|
}
|
|
179
179
|
function ascii(c) {
|
|
180
|
-
return c.
|
|
180
|
+
return c.codePointAt(0);
|
|
181
181
|
}
|
|
182
182
|
function getAsciiArrayFromStr(str) {
|
|
183
183
|
if (str === undefined || str === null)
|
|
@@ -185,7 +185,7 @@ function getAsciiArrayFromStr(str) {
|
|
|
185
185
|
const n = str.length;
|
|
186
186
|
let result = [];
|
|
187
187
|
for (let i = 0; i < n; i++) {
|
|
188
|
-
result.push(str.
|
|
188
|
+
result.push(str.codePointAt(i));
|
|
189
189
|
}
|
|
190
190
|
return result;
|
|
191
191
|
}
|
|
@@ -282,16 +282,16 @@ function routeToEpp(route, date) {
|
|
|
282
282
|
}
|
|
283
283
|
function parseTrainingData(payload) {
|
|
284
284
|
const gearVal = (v) => v > 0 ? v - 1 : undefined;
|
|
285
|
-
const vals = payload.split(String.
|
|
285
|
+
const vals = payload.split(String.fromCodePoint(GS));
|
|
286
286
|
const data = {
|
|
287
|
-
time: parseInt(vals[0]),
|
|
288
|
-
heartrate: parseInt(vals[1]),
|
|
289
|
-
speed: parseFloat(vals[2]) * 3.6,
|
|
290
|
-
slope: parseFloat(vals[3]),
|
|
291
|
-
distanceInternal: parseInt(vals[4]),
|
|
292
|
-
pedalRpm: parseFloat(vals[5]),
|
|
293
|
-
power: parseInt(vals[6]),
|
|
294
|
-
gear: gearVal(parseInt(vals[10])),
|
|
287
|
+
time: Number.parseInt(vals[0]),
|
|
288
|
+
heartrate: Number.parseInt(vals[1]),
|
|
289
|
+
speed: Number.parseFloat(vals[2]) * 3.6,
|
|
290
|
+
slope: Number.parseFloat(vals[3]),
|
|
291
|
+
distanceInternal: Number.parseInt(vals[4]),
|
|
292
|
+
pedalRpm: Number.parseFloat(vals[5]),
|
|
293
|
+
power: Number.parseInt(vals[6]),
|
|
294
|
+
gear: gearVal(Number.parseInt(vals[10])),
|
|
295
295
|
};
|
|
296
296
|
data.isPedalling = (data.pedalRpm > 0);
|
|
297
297
|
return data;
|
|
@@ -25,7 +25,7 @@ export interface KettlerBikeData {
|
|
|
25
25
|
export default class KettlerRacerAdapter extends SerialIncyclistDevice<DeviceProperties> {
|
|
26
26
|
private id;
|
|
27
27
|
private iv;
|
|
28
|
-
private requests;
|
|
28
|
+
private readonly requests;
|
|
29
29
|
private internalData;
|
|
30
30
|
private kettlerData;
|
|
31
31
|
private updateBusy;
|
|
@@ -171,18 +171,13 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
|
|
|
171
171
|
}
|
|
172
172
|
send(logStr, message, timeout) {
|
|
173
173
|
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
catch (err) {
|
|
182
|
-
reject(err);
|
|
183
|
-
}
|
|
174
|
+
const opened = yield this.waitForOpened();
|
|
175
|
+
if (!opened) {
|
|
176
|
+
throw (new Error('connection error'));
|
|
177
|
+
}
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
184
179
|
this.comms.send({ logStr, message, onResponse: resolve, onError: reject, timeout });
|
|
185
|
-
})
|
|
180
|
+
});
|
|
186
181
|
});
|
|
187
182
|
}
|
|
188
183
|
parseExtendedStatus(data) {
|
|
@@ -193,39 +188,39 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
|
|
|
193
188
|
const states = data.split('\t');
|
|
194
189
|
const result = {};
|
|
195
190
|
if (states.length === 8) {
|
|
196
|
-
const hr = parseInt(states[0]);
|
|
197
|
-
if (!isNaN(hr)) {
|
|
191
|
+
const hr = Number.parseInt(states[0]);
|
|
192
|
+
if (!Number.isNaN(hr)) {
|
|
198
193
|
result.heartrate = hr;
|
|
199
194
|
}
|
|
200
|
-
|
|
201
|
-
if (!isNaN(cadence)) {
|
|
195
|
+
const cadence = Number.parseInt(states[1]);
|
|
196
|
+
if (!Number.isNaN(cadence)) {
|
|
202
197
|
result.cadence = cadence;
|
|
203
198
|
}
|
|
204
|
-
const speed = parseInt(states[2]);
|
|
205
|
-
if (!isNaN(speed)) {
|
|
199
|
+
const speed = Number.parseInt(states[2]);
|
|
200
|
+
if (!Number.isNaN(speed)) {
|
|
206
201
|
result.speed = speed * 0.1;
|
|
207
202
|
}
|
|
208
|
-
const distance = parseInt(states[3]);
|
|
209
|
-
if (!isNaN(distance)) {
|
|
203
|
+
const distance = Number.parseInt(states[3]);
|
|
204
|
+
if (!Number.isNaN(distance)) {
|
|
210
205
|
result.distance = distance * 100;
|
|
211
206
|
}
|
|
212
|
-
const requestedPower = parseInt(states[4]);
|
|
213
|
-
if (!isNaN(requestedPower)) {
|
|
207
|
+
const requestedPower = Number.parseInt(states[4]);
|
|
208
|
+
if (!Number.isNaN(requestedPower)) {
|
|
214
209
|
result.requestedPower = requestedPower;
|
|
215
210
|
}
|
|
216
|
-
const energy = parseInt(states[5]);
|
|
217
|
-
if (!isNaN(energy)) {
|
|
211
|
+
const energy = Number.parseInt(states[5]);
|
|
212
|
+
if (!Number.isNaN(energy)) {
|
|
218
213
|
result.energy = energy;
|
|
219
214
|
}
|
|
220
215
|
const timeStr = states[6];
|
|
221
216
|
const time = timeStr.split(':');
|
|
222
|
-
const hours = parseInt(time[0]);
|
|
223
|
-
const minutes = parseInt(time[1]);
|
|
224
|
-
if (!isNaN(hours) && !isNaN(minutes)) {
|
|
217
|
+
const hours = Number.parseInt(time[0]);
|
|
218
|
+
const minutes = Number.parseInt(time[1]);
|
|
219
|
+
if (!Number.isNaN(hours) && !Number.isNaN(minutes)) {
|
|
225
220
|
result.time = hours * 60 + minutes;
|
|
226
221
|
}
|
|
227
|
-
const power = parseInt(states[7]);
|
|
228
|
-
if (!isNaN(power)) {
|
|
222
|
+
const power = Number.parseInt(states[7]);
|
|
223
|
+
if (!Number.isNaN(power)) {
|
|
229
224
|
result.power = power;
|
|
230
225
|
}
|
|
231
226
|
result.timestamp = Date.now();
|
|
@@ -234,7 +229,7 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
|
|
|
234
229
|
}
|
|
235
230
|
check() {
|
|
236
231
|
return __awaiter(this, void 0, void 0, function* () {
|
|
237
|
-
|
|
232
|
+
const info = {};
|
|
238
233
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
239
234
|
this.logEvent({ message: "checking device", port: this.getPort() });
|
|
240
235
|
let iv = undefined;
|
|
@@ -275,7 +270,7 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
|
|
|
275
270
|
return __awaiter(this, void 0, void 0, function* () {
|
|
276
271
|
const props = this.getStartProps(startProps);
|
|
277
272
|
this.logEvent({ message: 'start()' });
|
|
278
|
-
|
|
273
|
+
const info = {};
|
|
279
274
|
yield this.waitForOpened(true);
|
|
280
275
|
return (0, utils_1.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
|
|
281
276
|
try {
|
|
@@ -519,25 +514,20 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
|
|
|
519
514
|
}
|
|
520
515
|
waitForOpened() {
|
|
521
516
|
return __awaiter(this, arguments, void 0, function* (retries = false) {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
opened = yield this.comms.open();
|
|
531
|
-
if (opened)
|
|
532
|
-
return true;
|
|
533
|
-
}
|
|
534
|
-
catch (err) {
|
|
535
|
-
}
|
|
536
|
-
tries++;
|
|
537
|
-
yield (0, utils_1.sleep)(500);
|
|
517
|
+
const maxTries = retries ? 3 : 1;
|
|
518
|
+
let opened = false;
|
|
519
|
+
let tries = 0;
|
|
520
|
+
while (!opened && tries < maxTries) {
|
|
521
|
+
try {
|
|
522
|
+
opened = yield this.comms.open();
|
|
523
|
+
if (opened)
|
|
524
|
+
return true;
|
|
538
525
|
}
|
|
539
|
-
|
|
526
|
+
catch (_a) { }
|
|
527
|
+
tries++;
|
|
528
|
+
yield (0, utils_1.sleep)(500);
|
|
540
529
|
}
|
|
530
|
+
return false;
|
|
541
531
|
});
|
|
542
532
|
}
|
|
543
533
|
waitForClosed() {
|
|
@@ -554,7 +544,10 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
|
|
|
554
544
|
resolve(true);
|
|
555
545
|
cleanup();
|
|
556
546
|
};
|
|
557
|
-
const onError = (err) => {
|
|
547
|
+
const onError = (err) => {
|
|
548
|
+
reject(err);
|
|
549
|
+
cleanup();
|
|
550
|
+
};
|
|
558
551
|
const onOpen = () => { cleanup(); };
|
|
559
552
|
this.comms.on('closed', onClose);
|
|
560
553
|
this.comms.on('opened', onOpen);
|
package/lib/types/interface.d.ts
CHANGED
package/lib/utils/utils.js
CHANGED
|
@@ -73,16 +73,16 @@ function floatVal(d) {
|
|
|
73
73
|
return;
|
|
74
74
|
if (typeof d === 'number')
|
|
75
75
|
return d;
|
|
76
|
-
const res = parseFloat(d);
|
|
77
|
-
return isNaN(res) ? undefined : res;
|
|
76
|
+
const res = Number.parseFloat(d);
|
|
77
|
+
return Number.isNaN(res) ? undefined : res;
|
|
78
78
|
}
|
|
79
79
|
function intVal(d) {
|
|
80
80
|
if (d === undefined)
|
|
81
81
|
return;
|
|
82
82
|
if (typeof d === 'number')
|
|
83
83
|
return Math.floor(d);
|
|
84
|
-
const res = parseInt(d);
|
|
85
|
-
return isNaN(res) ? undefined : res;
|
|
84
|
+
const res = Number.parseInt(d);
|
|
85
|
+
return Number.isNaN(res) ? undefined : res;
|
|
86
86
|
}
|
|
87
87
|
function hexstr(arr, start, len) {
|
|
88
88
|
let str = "";
|
|
@@ -93,7 +93,7 @@ function hexstr(arr, start, len) {
|
|
|
93
93
|
endIdx = arr.length;
|
|
94
94
|
}
|
|
95
95
|
let added = 0;
|
|
96
|
-
for (
|
|
96
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
97
97
|
const hex = Math.abs(arr[i]).toString(16).toUpperCase();
|
|
98
98
|
if (added !== 0)
|
|
99
99
|
str += ' ';
|