incyclist-devices 1.4.65 → 1.4.68
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 +54 -9
- package/lib/ble/ble-interface.d.ts +1 -0
- package/lib/ble/ble-interface.js +34 -17
- package/lib/ble/ble-peripheral.js +7 -3
- package/lib/ble/fm.d.ts +2 -0
- package/lib/ble/fm.js +40 -7
- 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 +15 -8
- 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;
|
|
@@ -47,7 +48,9 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
47
48
|
if (this.logger) {
|
|
48
49
|
this.logger.logEvent(event);
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
if (process.env.BLE_DEBUG) {
|
|
52
|
+
console.log('~~~BLE:', event);
|
|
53
|
+
}
|
|
51
54
|
}
|
|
52
55
|
setLogger(logger) {
|
|
53
56
|
this.logger = logger;
|
|
@@ -55,6 +58,9 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
55
58
|
setInterface(ble) {
|
|
56
59
|
this.ble = ble;
|
|
57
60
|
}
|
|
61
|
+
isMatching(characteristics) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
58
64
|
cleanupListeners() {
|
|
59
65
|
if (this.characteristics === undefined) {
|
|
60
66
|
this.characteristics = [];
|
|
@@ -101,11 +107,17 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
101
107
|
return this.services && this.services.find(s => s === serviceUuid || (0, ble_1.uuid)(serviceUuid)) !== undefined;
|
|
102
108
|
}
|
|
103
109
|
init() {
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
if (this.isInitialized)
|
|
112
|
+
return Promise.resolve(true);
|
|
113
|
+
return yield this.initDevice();
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
initDevice() {
|
|
117
|
+
this.logEvent({ message: 'get device info' });
|
|
106
118
|
return this.getDeviceInfo().then(() => {
|
|
107
119
|
this.emit('deviceInfo', this.deviceInfo);
|
|
108
|
-
this.logEvent(Object.assign({ message: '
|
|
120
|
+
this.logEvent(Object.assign({ message: 'device init done' }, this.deviceInfo));
|
|
109
121
|
this.isInitialized = true;
|
|
110
122
|
return true;
|
|
111
123
|
});
|
|
@@ -218,6 +230,9 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
218
230
|
const { id, name, address } = this;
|
|
219
231
|
this.logEvent({ message: 'disconnect requested', device: { id, name, address } });
|
|
220
232
|
this.connectState.isDisconnecting = true;
|
|
233
|
+
if (this.workerIv) {
|
|
234
|
+
this.stopWorker();
|
|
235
|
+
}
|
|
221
236
|
if (!this.connectState.isConnecting && !this.connectState.isConnected) {
|
|
222
237
|
this.connectState.isDisconnecting = false;
|
|
223
238
|
this.logEvent({ message: 'disconnect result: success', device: { id, name, address } });
|
|
@@ -244,20 +259,51 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
244
259
|
if (writeIdx !== -1) {
|
|
245
260
|
const writeItem = this.writeQueue[writeIdx];
|
|
246
261
|
this.writeQueue.splice(writeIdx, 1);
|
|
247
|
-
console.log('~~~ write queue', this.writeQueue);
|
|
248
262
|
if (writeItem.resolve)
|
|
249
263
|
writeItem.resolve(data);
|
|
250
264
|
}
|
|
251
265
|
}
|
|
252
266
|
}
|
|
267
|
+
timeoutCheck() {
|
|
268
|
+
const now = Date.now();
|
|
269
|
+
const updatedQueue = [];
|
|
270
|
+
let hasTimeout = false;
|
|
271
|
+
this.writeQueue.forEach(writeItem => {
|
|
272
|
+
if (writeItem.timeout && writeItem.timeout > now) {
|
|
273
|
+
if (writeItem.reject) {
|
|
274
|
+
hasTimeout = true;
|
|
275
|
+
writeItem.reject(new Error('timeout'));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
updatedQueue.push(writeItem);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
if (hasTimeout)
|
|
283
|
+
this.writeQueue = updatedQueue;
|
|
284
|
+
}
|
|
285
|
+
startWorker() {
|
|
286
|
+
if (this.workerIv)
|
|
287
|
+
return;
|
|
288
|
+
this.workerIv = setInterval(() => { this.timeoutCheck(); }, 100);
|
|
289
|
+
}
|
|
290
|
+
stopWorker() {
|
|
291
|
+
if (!this.workerIv)
|
|
292
|
+
return;
|
|
293
|
+
clearInterval(this.workerIv);
|
|
294
|
+
this.workerIv = null;
|
|
295
|
+
}
|
|
253
296
|
write(characteristicUuid, data, withoutResponse = false) {
|
|
254
297
|
return __awaiter(this, void 0, void 0, function* () {
|
|
255
298
|
try {
|
|
256
299
|
const connector = this.ble.getConnector(this.peripheral);
|
|
257
300
|
const isAlreadySubscribed = connector.isSubscribed(characteristicUuid);
|
|
258
|
-
|
|
301
|
+
if (!withoutResponse && !this.workerIv) {
|
|
302
|
+
this.startWorker();
|
|
303
|
+
}
|
|
259
304
|
if (!withoutResponse && !isAlreadySubscribed) {
|
|
260
305
|
const connector = this.ble.getConnector(this.peripheral);
|
|
306
|
+
connector.removeAllListeners(characteristicUuid);
|
|
261
307
|
connector.on(characteristicUuid, (uuid, data) => {
|
|
262
308
|
this.onData(uuid, data);
|
|
263
309
|
});
|
|
@@ -280,14 +326,13 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
280
326
|
else {
|
|
281
327
|
const writeId = this.writeQueue.length;
|
|
282
328
|
let messageDeleted = false;
|
|
283
|
-
this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, resolve, reject });
|
|
329
|
+
this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, timeout: Date.now() + 1000, resolve, reject });
|
|
284
330
|
const to = setTimeout(() => {
|
|
285
|
-
console.log('~~~ write timeout');
|
|
286
331
|
if (this.writeQueue.length > writeId && !messageDeleted)
|
|
287
332
|
this.writeQueue.splice(writeId, 1);
|
|
288
333
|
this.logEvent({ message: 'writing response', err: 'timeout' });
|
|
289
334
|
reject(new Error('timeout'));
|
|
290
|
-
},
|
|
335
|
+
}, 5000);
|
|
291
336
|
this.logEvent({ message: 'writing' });
|
|
292
337
|
characteristic.write(data, withoutResponse, (err) => {
|
|
293
338
|
clearTimeout(to);
|
|
@@ -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);
|
|
@@ -31,7 +31,9 @@ class BlePeripheralConnector {
|
|
|
31
31
|
if (this.logger) {
|
|
32
32
|
this.logger.logEvent(event);
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
if (process.env.BLE_DEBUG) {
|
|
35
|
+
console.log('~~~BLE:', event);
|
|
36
|
+
}
|
|
35
37
|
}
|
|
36
38
|
connect() {
|
|
37
39
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -110,7 +112,6 @@ class BlePeripheralConnector {
|
|
|
110
112
|
try {
|
|
111
113
|
yield this.subscribe(c.uuid);
|
|
112
114
|
subscribed.push(c.uuid);
|
|
113
|
-
this.state.subscribed.push(c.uuid);
|
|
114
115
|
}
|
|
115
116
|
catch (err) {
|
|
116
117
|
this.logEvent({ message: 'cannot subscribe', peripheral: this.peripheral.address, characteristic: c.uuid, error: err.message || err });
|
|
@@ -137,6 +138,7 @@ class BlePeripheralConnector {
|
|
|
137
138
|
reject(new Error('Characteristic not found'));
|
|
138
139
|
return;
|
|
139
140
|
}
|
|
141
|
+
characteristic.removeAllListeners('data');
|
|
140
142
|
characteristic.on('data', (data, _isNotification) => {
|
|
141
143
|
this.onData(characteristicUuid, data);
|
|
142
144
|
});
|
|
@@ -149,8 +151,10 @@ class BlePeripheralConnector {
|
|
|
149
151
|
this.logEvent({ message: 'subscribe result', characteristic: characteristicUuid, error: err });
|
|
150
152
|
if (err)
|
|
151
153
|
reject(err);
|
|
152
|
-
else
|
|
154
|
+
else {
|
|
155
|
+
this.state.subscribed.push(characteristicUuid);
|
|
153
156
|
resolve(true);
|
|
157
|
+
}
|
|
154
158
|
});
|
|
155
159
|
}
|
|
156
160
|
catch (err) {
|
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,18 +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
|
-
this.
|
|
104
|
-
yield _super.
|
|
134
|
+
yield this.subscribeWriteResponse(FTMS_CP);
|
|
135
|
+
yield _super.initDevice.call(this);
|
|
105
136
|
yield this.getFitnessMachineFeatures();
|
|
106
137
|
this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
|
|
107
138
|
}
|
|
108
139
|
catch (err) {
|
|
140
|
+
this.logEvent({ message: 'error', fn: 'BleFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
|
|
109
141
|
return Promise.resolve(false);
|
|
110
142
|
}
|
|
111
143
|
});
|
|
@@ -278,13 +310,13 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
278
310
|
const uuid = characteristic.toLocaleLowerCase();
|
|
279
311
|
let res = undefined;
|
|
280
312
|
switch (uuid) {
|
|
281
|
-
case
|
|
313
|
+
case INDOOR_BIKE_DATA:
|
|
282
314
|
res = this.parseIndoorBikeData(data);
|
|
283
315
|
break;
|
|
284
316
|
case '2a37':
|
|
285
317
|
res = this.parseHrm(data);
|
|
286
318
|
break;
|
|
287
|
-
case
|
|
319
|
+
case FTMS_STATUS:
|
|
288
320
|
res = this.parseFitnessMachineStatus(data);
|
|
289
321
|
break;
|
|
290
322
|
case '2a63':
|
|
@@ -452,7 +484,7 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
452
484
|
}
|
|
453
485
|
exports.default = BleFitnessMachineDevice;
|
|
454
486
|
BleFitnessMachineDevice.services = ['1826'];
|
|
455
|
-
BleFitnessMachineDevice.characteristics = ['2acc',
|
|
487
|
+
BleFitnessMachineDevice.characteristics = ['2acc', INDOOR_BIKE_DATA, '2ad6', '2ad8', FTMS_CP, FTMS_STATUS];
|
|
456
488
|
ble_interface_1.default.register('BleFitnessMachineDevice', 'fm', BleFitnessMachineDevice, BleFitnessMachineDevice.services);
|
|
457
489
|
class FmAdapter extends Device_1.default {
|
|
458
490
|
constructor(device, protocol) {
|
|
@@ -477,7 +509,8 @@ class FmAdapter extends Device_1.default {
|
|
|
477
509
|
return (adapter.getName() === this.getName() && adapter.getProfile() === this.getProfile());
|
|
478
510
|
}
|
|
479
511
|
getProfile() {
|
|
480
|
-
|
|
512
|
+
const profile = this.device ? this.device.getProfile() : undefined;
|
|
513
|
+
return profile || 'Smart Trainer';
|
|
481
514
|
}
|
|
482
515
|
getName() {
|
|
483
516
|
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
|
@@ -36,7 +36,7 @@ const ble_interface_1 = __importDefault(require("./ble-interface"));
|
|
|
36
36
|
const Device_1 = require("../Device");
|
|
37
37
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
38
38
|
const fm_1 = __importStar(require("./fm"));
|
|
39
|
-
const WAHOO_ADVANCED_FTMS = '
|
|
39
|
+
const WAHOO_ADVANCED_FTMS = 'a026e00b';
|
|
40
40
|
const WAHOO_ADVANCED_TRAINER_CP = 'a026e037';
|
|
41
41
|
const cwABike = {
|
|
42
42
|
race: 0.35,
|
|
@@ -54,18 +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
|
-
this.
|
|
64
|
-
yield _super.
|
|
65
|
-
|
|
69
|
+
yield this.subscribeWriteResponse(WAHOO_ADVANCED_TRAINER_CP);
|
|
70
|
+
yield _super.initDevice.call(this);
|
|
71
|
+
return true;
|
|
66
72
|
}
|
|
67
73
|
catch (err) {
|
|
68
|
-
|
|
74
|
+
this.logEvent({ message: 'error', fn: 'WahooAdvancedFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
|
|
75
|
+
return false;
|
|
69
76
|
}
|
|
70
77
|
});
|
|
71
78
|
}
|
|
@@ -172,7 +179,7 @@ class WahooAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
172
179
|
const opcode = Buffer.alloc(1);
|
|
173
180
|
opcode.writeUInt8(requestedOpCode, 0);
|
|
174
181
|
const message = Buffer.concat([opcode, data]);
|
|
175
|
-
const res = yield this.write(
|
|
182
|
+
const res = yield this.write(WAHOO_ADVANCED_TRAINER_CP, message);
|
|
176
183
|
const responseData = Buffer.from(res);
|
|
177
184
|
const result = responseData.readUInt8(0);
|
|
178
185
|
this.logEvent({ message: 'response', opCode: requestedOpCode, response: responseData.toString('hex') });
|
|
@@ -298,7 +305,7 @@ class WahooAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
298
305
|
}
|
|
299
306
|
exports.default = WahooAdvancedFitnessMachineDevice;
|
|
300
307
|
WahooAdvancedFitnessMachineDevice.services = ['a026ee0b'];
|
|
301
|
-
WahooAdvancedFitnessMachineDevice.characteristics = ['2acc', '2ad2', '2ad6', '2ad8', '2ad9', '2ada',
|
|
308
|
+
WahooAdvancedFitnessMachineDevice.characteristics = ['2acc', '2ad2', '2ad6', '2ad8', '2ad9', '2ada', WAHOO_ADVANCED_TRAINER_CP];
|
|
302
309
|
ble_interface_1.default.register('WahooAdvancedFitnessMachineDevice', 'wahoo-fm', WahooAdvancedFitnessMachineDevice, WahooAdvancedFitnessMachineDevice.services);
|
|
303
310
|
class WahooAdvancedFmAdapter extends fm_1.FmAdapter {
|
|
304
311
|
constructor(device, protocol) {
|