incyclist-devices 1.4.66 → 1.4.69
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/ble/ble-device.d.ts +7 -0
- package/lib/ble/ble-device.js +47 -5
- package/lib/ble/ble-interface.d.ts +1 -0
- package/lib/ble/ble-interface.js +34 -17
- package/lib/ble/fm.d.ts +2 -0
- package/lib/ble/fm.js +44 -26
- package/lib/ble/pwr.d.ts +1 -0
- package/lib/ble/pwr.js +11 -2
- package/lib/ble/tacx.js +6 -6
- package/lib/ble/wahoo-kickr.d.ts +1 -0
- package/lib/ble/wahoo-kickr.js +14 -24
- package/lib/daum/classic/utils.d.ts +1 -1
- package/lib/daum/classic/utils.js +2 -0
- package/package.json +1 -1
package/lib/ble/ble-device.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ interface BleDeviceConstructProps extends BleDeviceProps {
|
|
|
9
9
|
declare type CommandQueueItem = {
|
|
10
10
|
uuid: string;
|
|
11
11
|
data: Buffer;
|
|
12
|
+
timeout: number;
|
|
12
13
|
resolve: any;
|
|
13
14
|
reject: any;
|
|
14
15
|
};
|
|
@@ -26,21 +27,27 @@ export declare abstract class BleDevice extends BleDeviceClass {
|
|
|
26
27
|
isInitialized: boolean;
|
|
27
28
|
subscribedCharacteristics: string[];
|
|
28
29
|
writeQueue: CommandQueueItem[];
|
|
30
|
+
workerIv: NodeJS.Timeout;
|
|
29
31
|
constructor(props?: BleDeviceConstructProps);
|
|
30
32
|
logEvent(event: any): void;
|
|
31
33
|
setLogger(logger: EventLogger): void;
|
|
32
34
|
setInterface(ble: BleInterfaceClass): void;
|
|
35
|
+
isMatching(characteristics: string[]): boolean;
|
|
33
36
|
cleanupListeners(): void;
|
|
34
37
|
onDisconnect(): void;
|
|
35
38
|
waitForConnectFinished(timeout: any): Promise<unknown>;
|
|
36
39
|
hasService(serviceUuid: any): boolean;
|
|
37
40
|
init(): Promise<boolean>;
|
|
41
|
+
initDevice(): Promise<boolean>;
|
|
38
42
|
connectPeripheral(peripheral: BlePeripheral): Promise<void>;
|
|
39
43
|
subscribeAll(conn?: BlePeripheralConnector): Promise<void>;
|
|
40
44
|
connect(props?: ConnectProps): Promise<boolean>;
|
|
41
45
|
disconnect(): Promise<boolean>;
|
|
42
46
|
abstract getProfile(): string;
|
|
43
47
|
onData(characteristic: string, data: Buffer): void;
|
|
48
|
+
timeoutCheck(): void;
|
|
49
|
+
startWorker(): void;
|
|
50
|
+
stopWorker(): void;
|
|
44
51
|
write(characteristicUuid: string, data: Buffer, withoutResponse?: boolean): Promise<ArrayBuffer>;
|
|
45
52
|
read(characteristicUuid: string): Promise<Uint8Array>;
|
|
46
53
|
getDeviceInfo(): Promise<BleDeviceInfo>;
|
package/lib/ble/ble-device.js
CHANGED
|
@@ -27,6 +27,7 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
27
27
|
this.subscribedCharacteristics = [];
|
|
28
28
|
this.isInitialized = false;
|
|
29
29
|
this.writeQueue = [];
|
|
30
|
+
this.workerIv = null;
|
|
30
31
|
if (props.peripheral) {
|
|
31
32
|
const { id, address, advertisement, state } = props.peripheral;
|
|
32
33
|
this.peripheral = props.peripheral;
|
|
@@ -57,6 +58,9 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
57
58
|
setInterface(ble) {
|
|
58
59
|
this.ble = ble;
|
|
59
60
|
}
|
|
61
|
+
isMatching(characteristics) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
60
64
|
cleanupListeners() {
|
|
61
65
|
if (this.characteristics === undefined) {
|
|
62
66
|
this.characteristics = [];
|
|
@@ -103,11 +107,15 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
103
107
|
return this.services && this.services.find(s => s === serviceUuid || (0, ble_1.uuid)(serviceUuid)) !== undefined;
|
|
104
108
|
}
|
|
105
109
|
init() {
|
|
106
|
-
|
|
107
|
-
return
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
return yield this.initDevice();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
initDevice() {
|
|
115
|
+
this.logEvent({ message: 'get device info' });
|
|
108
116
|
return this.getDeviceInfo().then(() => {
|
|
109
117
|
this.emit('deviceInfo', this.deviceInfo);
|
|
110
|
-
this.logEvent(Object.assign({ message: '
|
|
118
|
+
this.logEvent(Object.assign({ message: 'device init done' }, this.deviceInfo));
|
|
111
119
|
this.isInitialized = true;
|
|
112
120
|
return true;
|
|
113
121
|
});
|
|
@@ -220,6 +228,9 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
220
228
|
const { id, name, address } = this;
|
|
221
229
|
this.logEvent({ message: 'disconnect requested', device: { id, name, address } });
|
|
222
230
|
this.connectState.isDisconnecting = true;
|
|
231
|
+
if (this.workerIv) {
|
|
232
|
+
this.stopWorker();
|
|
233
|
+
}
|
|
223
234
|
if (!this.connectState.isConnecting && !this.connectState.isConnected) {
|
|
224
235
|
this.connectState.isDisconnecting = false;
|
|
225
236
|
this.logEvent({ message: 'disconnect result: success', device: { id, name, address } });
|
|
@@ -251,11 +262,43 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
251
262
|
}
|
|
252
263
|
}
|
|
253
264
|
}
|
|
265
|
+
timeoutCheck() {
|
|
266
|
+
const now = Date.now();
|
|
267
|
+
const updatedQueue = [];
|
|
268
|
+
let hasTimeout = false;
|
|
269
|
+
this.writeQueue.forEach(writeItem => {
|
|
270
|
+
if (writeItem.timeout && writeItem.timeout < now) {
|
|
271
|
+
if (writeItem.reject) {
|
|
272
|
+
hasTimeout = true;
|
|
273
|
+
writeItem.reject(new Error('timeout'));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
updatedQueue.push(writeItem);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
if (hasTimeout)
|
|
281
|
+
this.writeQueue = updatedQueue;
|
|
282
|
+
}
|
|
283
|
+
startWorker() {
|
|
284
|
+
if (this.workerIv)
|
|
285
|
+
return;
|
|
286
|
+
this.workerIv = setInterval(() => { this.timeoutCheck(); }, 100);
|
|
287
|
+
}
|
|
288
|
+
stopWorker() {
|
|
289
|
+
if (!this.workerIv)
|
|
290
|
+
return;
|
|
291
|
+
clearInterval(this.workerIv);
|
|
292
|
+
this.workerIv = null;
|
|
293
|
+
}
|
|
254
294
|
write(characteristicUuid, data, withoutResponse = false) {
|
|
255
295
|
return __awaiter(this, void 0, void 0, function* () {
|
|
256
296
|
try {
|
|
257
297
|
const connector = this.ble.getConnector(this.peripheral);
|
|
258
298
|
const isAlreadySubscribed = connector.isSubscribed(characteristicUuid);
|
|
299
|
+
if (!withoutResponse && !this.workerIv) {
|
|
300
|
+
this.startWorker();
|
|
301
|
+
}
|
|
259
302
|
if (!withoutResponse && !isAlreadySubscribed) {
|
|
260
303
|
const connector = this.ble.getConnector(this.peripheral);
|
|
261
304
|
connector.removeAllListeners(characteristicUuid);
|
|
@@ -281,9 +324,8 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
281
324
|
else {
|
|
282
325
|
const writeId = this.writeQueue.length;
|
|
283
326
|
let messageDeleted = false;
|
|
284
|
-
this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, resolve, reject });
|
|
327
|
+
this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, timeout: Date.now() + 2500, resolve, reject });
|
|
285
328
|
const to = setTimeout(() => {
|
|
286
|
-
console.log('~~~ write timeout');
|
|
287
329
|
if (this.writeQueue.length > writeId && !messageDeleted)
|
|
288
330
|
this.writeQueue.splice(writeId, 1);
|
|
289
331
|
this.logEvent({ message: 'writing response', err: 'timeout' });
|
|
@@ -77,6 +77,7 @@ export default class BleInterface extends BleInterfaceClass {
|
|
|
77
77
|
getDeviceClasses(peripheral: any, props?: {
|
|
78
78
|
deviceTypes?: (typeof BleDeviceClass)[];
|
|
79
79
|
profile?: string;
|
|
80
|
+
services?: string[];
|
|
80
81
|
}): (typeof BleDeviceClass)[];
|
|
81
82
|
createDevice(DeviceClass: (typeof BleDeviceClass), peripheral: BlePeripheral, characteristics?: BleCharacteristic[]): any;
|
|
82
83
|
connectDevice(requested: BleDeviceClass | BleDeviceDescription, timeout?: number): Promise<BleDeviceClass>;
|
package/lib/ble/ble-interface.js
CHANGED
|
@@ -55,7 +55,9 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
55
55
|
if (this.logger) {
|
|
56
56
|
this.logger.logEvent(event);
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
if (process.env.BLE_DEBUG) {
|
|
59
|
+
console.log('~~BLE:', event);
|
|
60
|
+
}
|
|
59
61
|
}
|
|
60
62
|
onStateChange(state) {
|
|
61
63
|
if (state !== ble_1.BleState.POWERED_ON) {
|
|
@@ -334,13 +336,13 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
334
336
|
}
|
|
335
337
|
getDeviceClasses(peripheral, props = {}) {
|
|
336
338
|
let DeviceClasses;
|
|
337
|
-
const { deviceTypes, profile } = props;
|
|
339
|
+
const { deviceTypes, profile, services = peripheral.advertisement.serviceUuids } = props;
|
|
338
340
|
if ((!deviceTypes || deviceTypes.length === 0)) {
|
|
339
341
|
const classes = BleInterface.deviceClasses.map(c => c.Class);
|
|
340
|
-
DeviceClasses = this.getDevicesFromServices(classes,
|
|
342
|
+
DeviceClasses = this.getDevicesFromServices(classes, services);
|
|
341
343
|
}
|
|
342
344
|
else {
|
|
343
|
-
DeviceClasses = this.getDevicesFromServices(deviceTypes,
|
|
345
|
+
DeviceClasses = this.getDevicesFromServices(deviceTypes, services);
|
|
344
346
|
}
|
|
345
347
|
if (profile && DeviceClasses && DeviceClasses.length > 0) {
|
|
346
348
|
DeviceClasses = DeviceClasses.filter(C => {
|
|
@@ -353,15 +355,26 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
353
355
|
return DeviceClasses;
|
|
354
356
|
}
|
|
355
357
|
createDevice(DeviceClass, peripheral, characteristics) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
358
|
+
try {
|
|
359
|
+
const C = DeviceClass;
|
|
360
|
+
const device = new C({ peripheral });
|
|
361
|
+
const cids = characteristics ? characteristics.map(c => (0, ble_1.uuid)(c.uuid)) : [];
|
|
362
|
+
this.logEvent({ message: 'trying to create device', peripheral: peripheral.address, characteristics: cids, profile: device.getProfile() });
|
|
363
|
+
const existingDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
|
|
364
|
+
if (existingDevice)
|
|
365
|
+
return existingDevice;
|
|
366
|
+
device.setInterface(this);
|
|
367
|
+
if (characteristics && device.isMatching(cids)) {
|
|
368
|
+
device.characteristics = characteristics;
|
|
369
|
+
return device;
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
this.logEvent({ message: 'failed to create device', peripheral: peripheral.address, profile: device.getProfile() });
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
this.logEvent({ message: 'error', fn: '', error: err.message || err, stack: err.stack });
|
|
377
|
+
}
|
|
365
378
|
}
|
|
366
379
|
connectDevice(requested, timeout = DEFAULT_SCAN_TIMEOUT + CONNECT_TIMEOUT) {
|
|
367
380
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -551,10 +564,12 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
551
564
|
peripheralsProcessed.push(peripheral.address);
|
|
552
565
|
const characteristics = yield this.getCharacteristics(peripheral);
|
|
553
566
|
const connector = this.getConnector(peripheral);
|
|
567
|
+
const connectedServices = connector.getServices();
|
|
568
|
+
const services = connectedServices ? connectedServices.map(cs => cs.uuid) : undefined;
|
|
554
569
|
const connectedPeripheral = connector.getPeripheral();
|
|
555
570
|
const { id, name, address, advertisement = {} } = connectedPeripheral;
|
|
556
|
-
const DeviceClasses = this.getDeviceClasses(connectedPeripheral, { profile });
|
|
557
|
-
this.logEvent({ message: 'BLE scan: device connected', peripheral: { id, name, address, services: advertisement.serviceUuids, classes: DeviceClasses.map(c => c.prototype.constructor.name) }
|
|
571
|
+
const DeviceClasses = this.getDeviceClasses(connectedPeripheral, { profile, services });
|
|
572
|
+
this.logEvent({ message: 'BLE scan: device connected', peripheral: { id, name, address, services: advertisement.serviceUuids }, services, classes: DeviceClasses.map(c => c.prototype.constructor.name) });
|
|
558
573
|
let cntFound = 0;
|
|
559
574
|
DeviceClasses.forEach((DeviceClass) => __awaiter(this, void 0, void 0, function* () {
|
|
560
575
|
if (!DeviceClass)
|
|
@@ -562,6 +577,8 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
562
577
|
if (scanForDevice && cntFound > 0)
|
|
563
578
|
return;
|
|
564
579
|
const d = this.createDevice(DeviceClass, peripheral, characteristics);
|
|
580
|
+
if (!d)
|
|
581
|
+
return;
|
|
565
582
|
yield d.connect();
|
|
566
583
|
if (scanForDevice) {
|
|
567
584
|
if ((id && id !== '' && d.id === id) ||
|
|
@@ -573,14 +590,14 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
573
590
|
cntFound++;
|
|
574
591
|
const existing = devicesProcessed.find(device => device.id === d.id && device.getProfile() === d.getProfile());
|
|
575
592
|
if (!scanForDevice && cntFound > 0 && !existing) {
|
|
576
|
-
this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
|
|
593
|
+
this.logEvent({ message: `${opStr}: device found`, device: d.name, profile: d.getProfile(), address: d.address, services: d.services.join(',') });
|
|
577
594
|
this.addDeviceToCache(d, peripheral.state === 'connected');
|
|
578
595
|
devicesProcessed.push(d);
|
|
579
596
|
this.emit('device', d);
|
|
580
597
|
return;
|
|
581
598
|
}
|
|
582
599
|
if (scanForDevice && cntFound > 0) {
|
|
583
|
-
this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
|
|
600
|
+
this.logEvent({ message: `${opStr}: device found`, device: d.name, profile: d.getProfile(), address: d.address, services: d.services.join(',') });
|
|
584
601
|
this.addDeviceToCache(d, peripheral.state === 'connected');
|
|
585
602
|
devicesProcessed.push(d);
|
|
586
603
|
this.emit('device', d);
|
package/lib/ble/fm.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export default class BleFitnessMachineDevice extends BleDevice {
|
|
|
52
52
|
windSpeed: number;
|
|
53
53
|
wheelSize: number;
|
|
54
54
|
constructor(props?: any);
|
|
55
|
+
isMatching(characteristics: string[]): boolean;
|
|
56
|
+
subscribeWriteResponse(cuuid: string): Promise<void>;
|
|
55
57
|
init(): Promise<boolean>;
|
|
56
58
|
onDisconnect(): void;
|
|
57
59
|
getProfile(): string;
|
package/lib/ble/fm.js
CHANGED
|
@@ -21,6 +21,8 @@ const power_meter_1 = __importDefault(require("../modes/power-meter"));
|
|
|
21
21
|
const ble_st_mode_1 = __importDefault(require("./ble-st-mode"));
|
|
22
22
|
const ble_erg_mode_1 = __importDefault(require("./ble-erg-mode"));
|
|
23
23
|
const FTMS_CP = '2ad9';
|
|
24
|
+
const FTMS_STATUS = '2ada';
|
|
25
|
+
const INDOOR_BIKE_DATA = '2ad2';
|
|
24
26
|
const cwABike = {
|
|
25
27
|
race: 0.35,
|
|
26
28
|
triathlon: 0.29,
|
|
@@ -94,35 +96,48 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
94
96
|
this.wheelSize = 2100;
|
|
95
97
|
this.data = {};
|
|
96
98
|
}
|
|
99
|
+
isMatching(characteristics) {
|
|
100
|
+
if (!characteristics)
|
|
101
|
+
return false;
|
|
102
|
+
const hasStatus = characteristics.find(c => c === FTMS_STATUS) !== undefined;
|
|
103
|
+
const hasCP = characteristics.find(c => c === FTMS_CP) !== undefined;
|
|
104
|
+
const hasIndoorBike = characteristics.find(c => c === INDOOR_BIKE_DATA) !== undefined;
|
|
105
|
+
return hasStatus && hasCP && hasIndoorBike;
|
|
106
|
+
}
|
|
107
|
+
subscribeWriteResponse(cuuid) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
const connector = this.ble.getConnector(this.peripheral);
|
|
110
|
+
const isAlreadySubscribed = connector.isSubscribed(cuuid);
|
|
111
|
+
if (!isAlreadySubscribed) {
|
|
112
|
+
connector.removeAllListeners(cuuid);
|
|
113
|
+
let prev = undefined;
|
|
114
|
+
let prevTS = undefined;
|
|
115
|
+
connector.on(cuuid, (uuid, data) => {
|
|
116
|
+
const message = data.toString('hex');
|
|
117
|
+
if (prevTS && prev && message === prev && Date.now() - prevTS < 500) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
prevTS = Date.now();
|
|
121
|
+
prev = message;
|
|
122
|
+
this.onData(uuid, data);
|
|
123
|
+
});
|
|
124
|
+
yield connector.subscribe(cuuid);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
97
128
|
init() {
|
|
98
129
|
const _super = Object.create(null, {
|
|
99
|
-
|
|
130
|
+
initDevice: { get: () => super.initDevice }
|
|
100
131
|
});
|
|
101
132
|
return __awaiter(this, void 0, void 0, function* () {
|
|
102
133
|
try {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (!isAlreadySubscribed) {
|
|
106
|
-
connector.removeAllListeners(FTMS_CP);
|
|
107
|
-
let prev = undefined;
|
|
108
|
-
let prevTS = undefined;
|
|
109
|
-
connector.on(FTMS_CP, (uuid, data) => {
|
|
110
|
-
const message = data.toString('hex');
|
|
111
|
-
if (prevTS && prev && message === prev && Date.now() - prevTS < 500) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
prevTS = Date.now();
|
|
115
|
-
prev = message;
|
|
116
|
-
this.onData(uuid, data);
|
|
117
|
-
});
|
|
118
|
-
yield connector.subscribe(FTMS_CP);
|
|
119
|
-
}
|
|
120
|
-
this.logEvent({ message: 'get device info' });
|
|
121
|
-
yield _super.init.call(this);
|
|
134
|
+
yield this.subscribeWriteResponse(FTMS_CP);
|
|
135
|
+
yield _super.initDevice.call(this);
|
|
122
136
|
yield this.getFitnessMachineFeatures();
|
|
123
137
|
this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
|
|
124
138
|
}
|
|
125
139
|
catch (err) {
|
|
140
|
+
this.logEvent({ message: 'error', fn: 'BleFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
|
|
126
141
|
return Promise.resolve(false);
|
|
127
142
|
}
|
|
128
143
|
});
|
|
@@ -295,13 +310,13 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
295
310
|
const uuid = characteristic.toLocaleLowerCase();
|
|
296
311
|
let res = undefined;
|
|
297
312
|
switch (uuid) {
|
|
298
|
-
case
|
|
313
|
+
case INDOOR_BIKE_DATA:
|
|
299
314
|
res = this.parseIndoorBikeData(data);
|
|
300
315
|
break;
|
|
301
316
|
case '2a37':
|
|
302
317
|
res = this.parseHrm(data);
|
|
303
318
|
break;
|
|
304
|
-
case
|
|
319
|
+
case FTMS_STATUS:
|
|
305
320
|
res = this.parseFitnessMachineStatus(data);
|
|
306
321
|
break;
|
|
307
322
|
case '2a63':
|
|
@@ -409,9 +424,11 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
409
424
|
}
|
|
410
425
|
setIndoorBikeSimulation(windSpeed, gradient, crr, cw) {
|
|
411
426
|
return __awaiter(this, void 0, void 0, function* () {
|
|
412
|
-
if (!this.hasControl)
|
|
413
|
-
return;
|
|
414
427
|
const hasControl = yield this.requestControl();
|
|
428
|
+
if (!hasControl) {
|
|
429
|
+
this.logEvent({ message: 'setTargetInclination failed', reason: 'control is disabled' });
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
415
432
|
const data = Buffer.alloc(7);
|
|
416
433
|
data.writeUInt8(17, 0);
|
|
417
434
|
data.writeInt16LE(Math.round(windSpeed * 1000), 1);
|
|
@@ -469,7 +486,7 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
469
486
|
}
|
|
470
487
|
exports.default = BleFitnessMachineDevice;
|
|
471
488
|
BleFitnessMachineDevice.services = ['1826'];
|
|
472
|
-
BleFitnessMachineDevice.characteristics = ['2acc',
|
|
489
|
+
BleFitnessMachineDevice.characteristics = ['2acc', INDOOR_BIKE_DATA, '2ad6', '2ad8', FTMS_CP, FTMS_STATUS];
|
|
473
490
|
ble_interface_1.default.register('BleFitnessMachineDevice', 'fm', BleFitnessMachineDevice, BleFitnessMachineDevice.services);
|
|
474
491
|
class FmAdapter extends Device_1.default {
|
|
475
492
|
constructor(device, protocol) {
|
|
@@ -494,7 +511,8 @@ class FmAdapter extends Device_1.default {
|
|
|
494
511
|
return (adapter.getName() === this.getName() && adapter.getProfile() === this.getProfile());
|
|
495
512
|
}
|
|
496
513
|
getProfile() {
|
|
497
|
-
|
|
514
|
+
const profile = this.device ? this.device.getProfile() : undefined;
|
|
515
|
+
return profile || 'Smart Trainer';
|
|
498
516
|
}
|
|
499
517
|
getName() {
|
|
500
518
|
return `${this.device.name}`;
|
package/lib/ble/pwr.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export default class BleCyclingPowerDevice extends BleDevice {
|
|
|
33
33
|
currentCrankData: CrankData;
|
|
34
34
|
prevCrankData: CrankData;
|
|
35
35
|
constructor(props?: any);
|
|
36
|
+
isMatching(characteristics: string[]): boolean;
|
|
36
37
|
init(): Promise<boolean>;
|
|
37
38
|
getProfile(): string;
|
|
38
39
|
getServiceUUids(): string[];
|
package/lib/ble/pwr.js
CHANGED
|
@@ -37,6 +37,8 @@ const ble_interface_1 = __importDefault(require("./ble-interface"));
|
|
|
37
37
|
const Device_1 = __importStar(require("../Device"));
|
|
38
38
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
39
39
|
const power_meter_1 = __importDefault(require("../modes/power-meter"));
|
|
40
|
+
const CP_MEASUREMENT = '2a63';
|
|
41
|
+
const CP_FEATURE = '2a65';
|
|
40
42
|
class BleCyclingPowerDevice extends ble_device_1.BleDevice {
|
|
41
43
|
constructor(props) {
|
|
42
44
|
super(props);
|
|
@@ -49,6 +51,13 @@ class BleCyclingPowerDevice extends ble_device_1.BleDevice {
|
|
|
49
51
|
this.currentCrankData = undefined;
|
|
50
52
|
this.prevCrankData = undefined;
|
|
51
53
|
}
|
|
54
|
+
isMatching(characteristics) {
|
|
55
|
+
if (!characteristics)
|
|
56
|
+
return false;
|
|
57
|
+
const hasCPMeasurement = characteristics.find(c => c === CP_MEASUREMENT) !== undefined;
|
|
58
|
+
const hasCPFeature = characteristics.find(c => c === CP_FEATURE) !== undefined;
|
|
59
|
+
return hasCPMeasurement && hasCPFeature;
|
|
60
|
+
}
|
|
52
61
|
init() {
|
|
53
62
|
const _super = Object.create(null, {
|
|
54
63
|
init: { get: () => super.init }
|
|
@@ -131,7 +140,7 @@ class BleCyclingPowerDevice extends ble_device_1.BleDevice {
|
|
|
131
140
|
}
|
|
132
141
|
onData(characteristic, data) {
|
|
133
142
|
super.onData(characteristic, data);
|
|
134
|
-
if (characteristic.toLocaleLowerCase() ===
|
|
143
|
+
if (characteristic.toLocaleLowerCase() === CP_MEASUREMENT) {
|
|
135
144
|
const res = this.parsePower(data);
|
|
136
145
|
this.emit('data', res);
|
|
137
146
|
}
|
|
@@ -149,7 +158,7 @@ class BleCyclingPowerDevice extends ble_device_1.BleDevice {
|
|
|
149
158
|
}
|
|
150
159
|
exports.default = BleCyclingPowerDevice;
|
|
151
160
|
BleCyclingPowerDevice.services = ['1818'];
|
|
152
|
-
BleCyclingPowerDevice.characteristics = [
|
|
161
|
+
BleCyclingPowerDevice.characteristics = [CP_MEASUREMENT, CP_FEATURE, '2a5d', '2a3c'];
|
|
153
162
|
ble_interface_1.default.register('BleCyclingPowerDevice', 'cp', BleCyclingPowerDevice, BleCyclingPowerDevice.services);
|
|
154
163
|
class PwrAdapter extends Device_1.default {
|
|
155
164
|
constructor(device, protocol) {
|
package/lib/ble/tacx.js
CHANGED
|
@@ -42,7 +42,7 @@ const TACX_FE_C_TX = '6e40fec3';
|
|
|
42
42
|
const SYNC_BYTE = 0xA4;
|
|
43
43
|
const DEFAULT_CHANNEL = 5;
|
|
44
44
|
const ACKNOWLEDGED_DATA = 0x4F;
|
|
45
|
-
const PROFILE_ID = 'Tacx
|
|
45
|
+
const PROFILE_ID = 'Tacx SmartTrainer';
|
|
46
46
|
const cwABike = {
|
|
47
47
|
race: 0.35,
|
|
48
48
|
triathlon: 0.29,
|
|
@@ -79,16 +79,16 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
79
79
|
}
|
|
80
80
|
init() {
|
|
81
81
|
const _super = Object.create(null, {
|
|
82
|
-
|
|
82
|
+
initDevice: { get: () => super.initDevice }
|
|
83
83
|
});
|
|
84
84
|
return __awaiter(this, void 0, void 0, function* () {
|
|
85
85
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
|
|
86
|
+
yield _super.initDevice.call(this);
|
|
87
|
+
return true;
|
|
89
88
|
}
|
|
90
89
|
catch (err) {
|
|
91
|
-
|
|
90
|
+
this.logEvent({ message: 'error', fn: 'TacxAdvancedFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
|
|
91
|
+
return false;
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
94
|
}
|
package/lib/ble/wahoo-kickr.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export default class WahooAdvancedFitnessMachineDevice extends BleFitnessMachine
|
|
|
35
35
|
timeOffset: number;
|
|
36
36
|
tsPrevWrite: any;
|
|
37
37
|
constructor(props?: any);
|
|
38
|
+
isMatching(characteristics: string[]): boolean;
|
|
38
39
|
init(): Promise<boolean>;
|
|
39
40
|
getProfile(): string;
|
|
40
41
|
getServiceUUids(): string[];
|
package/lib/ble/wahoo-kickr.js
CHANGED
|
@@ -54,35 +54,25 @@ class WahooAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
54
54
|
this.tsPrevWrite = undefined;
|
|
55
55
|
this.data = {};
|
|
56
56
|
}
|
|
57
|
+
isMatching(characteristics) {
|
|
58
|
+
if (!characteristics)
|
|
59
|
+
return false;
|
|
60
|
+
const hasWahooCP = characteristics.find(c => c === WAHOO_ADVANCED_TRAINER_CP) !== undefined;
|
|
61
|
+
return hasWahooCP;
|
|
62
|
+
}
|
|
57
63
|
init() {
|
|
58
64
|
const _super = Object.create(null, {
|
|
59
|
-
|
|
65
|
+
initDevice: { get: () => super.initDevice }
|
|
60
66
|
});
|
|
61
67
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
68
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
connector.removeAllListeners(WAHOO_ADVANCED_TRAINER_CP);
|
|
67
|
-
let prev = undefined;
|
|
68
|
-
let prevTS = undefined;
|
|
69
|
-
connector.on(WAHOO_ADVANCED_TRAINER_CP, (uuid, data) => {
|
|
70
|
-
const message = data.toString('hex');
|
|
71
|
-
if (prevTS && prev && message === prev && Date.now() - prevTS < 500) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
prevTS = Date.now();
|
|
75
|
-
prev = message;
|
|
76
|
-
this.onData(uuid, data);
|
|
77
|
-
});
|
|
78
|
-
yield connector.subscribe(WAHOO_ADVANCED_TRAINER_CP);
|
|
79
|
-
}
|
|
80
|
-
this.logEvent({ message: 'get device info' });
|
|
81
|
-
yield _super.init.call(this);
|
|
82
|
-
this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
|
|
69
|
+
yield this.subscribeWriteResponse(WAHOO_ADVANCED_TRAINER_CP);
|
|
70
|
+
yield _super.initDevice.call(this);
|
|
71
|
+
return true;
|
|
83
72
|
}
|
|
84
73
|
catch (err) {
|
|
85
|
-
|
|
74
|
+
this.logEvent({ message: 'error', fn: 'WahooAdvancedFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
|
|
75
|
+
return false;
|
|
86
76
|
}
|
|
87
77
|
});
|
|
88
78
|
}
|
|
@@ -189,7 +179,7 @@ class WahooAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
189
179
|
const opcode = Buffer.alloc(1);
|
|
190
180
|
opcode.writeUInt8(requestedOpCode, 0);
|
|
191
181
|
const message = Buffer.concat([opcode, data]);
|
|
192
|
-
const res = yield this.write(
|
|
182
|
+
const res = yield this.write(WAHOO_ADVANCED_TRAINER_CP, message);
|
|
193
183
|
const responseData = Buffer.from(res);
|
|
194
184
|
const result = responseData.readUInt8(0);
|
|
195
185
|
this.logEvent({ message: 'response', opCode: requestedOpCode, response: responseData.toString('hex') });
|
|
@@ -315,7 +305,7 @@ class WahooAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
315
305
|
}
|
|
316
306
|
exports.default = WahooAdvancedFitnessMachineDevice;
|
|
317
307
|
WahooAdvancedFitnessMachineDevice.services = ['a026ee0b'];
|
|
318
|
-
WahooAdvancedFitnessMachineDevice.characteristics = ['2acc', '2ad2', '2ad6', '2ad8', '2ad9', '2ada',
|
|
308
|
+
WahooAdvancedFitnessMachineDevice.characteristics = ['2acc', '2ad2', '2ad6', '2ad8', '2ad9', '2ada', WAHOO_ADVANCED_TRAINER_CP];
|
|
319
309
|
ble_interface_1.default.register('WahooAdvancedFitnessMachineDevice', 'wahoo-fm', WahooAdvancedFitnessMachineDevice, WahooAdvancedFitnessMachineDevice.services);
|
|
320
310
|
class WahooAdvancedFmAdapter extends fm_1.FmAdapter {
|
|
321
311
|
constructor(device, protocol) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const DEFAULT_AGE = 30;
|
|
2
2
|
export declare const DEFAULT_USER_WEIGHT = 75;
|
|
3
3
|
export declare const DEFAULT_BIKE_WEIGHT = 10;
|
|
4
|
-
export declare function getCockpit(c: any): "Cardio" | "Fitness" | "Vita De Luxe" | "8008" | "8008 TRS" | "8080" | "Therapie" | "8008 TRS Pro" | "8008 TRS3" | "Unknown";
|
|
4
|
+
export declare function getCockpit(c: any): "Cardio" | "Fitness" | "Vita De Luxe" | "8008" | "8008 TRS" | "8080" | "Therapie" | "8008 TRS Pro" | "8008 TRS3" | "ergo_lyps Cardio Pro" | "Unknown";
|
|
5
5
|
export declare function getBikeType(type: any): 1 | 0;
|
|
6
6
|
export declare function getGender(sex: any): 1 | 2;
|
|
7
7
|
export declare function getLength(length: any): number;
|