incyclist-devices 1.4.76 → 1.4.78
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.js +1 -1
- package/lib/ble/ble-interface.js +5 -4
- package/lib/ble/ble-peripheral.js +8 -10
- package/lib/ble/ble.js +1 -1
- package/lib/ble/tacx.d.ts +14 -0
- package/lib/ble/tacx.js +62 -15
- package/package.json +1 -1
package/lib/ble/ble-device.js
CHANGED
|
@@ -316,7 +316,7 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
318
318
|
if (withoutResponse) {
|
|
319
|
-
this.logEvent({ message: 'writing' });
|
|
319
|
+
this.logEvent({ message: 'writing', data: data.toString('hex'), withoutResponse });
|
|
320
320
|
characteristic.write(data, withoutResponse);
|
|
321
321
|
resolve(new ArrayBuffer(0));
|
|
322
322
|
return;
|
package/lib/ble/ble-interface.js
CHANGED
|
@@ -55,9 +55,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
55
55
|
if (this.logger) {
|
|
56
56
|
this.logger.logEvent(event);
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
console.log('~~BLE:', event);
|
|
60
|
-
}
|
|
58
|
+
console.log('~~BLE:', event);
|
|
61
59
|
}
|
|
62
60
|
onStateChange(state) {
|
|
63
61
|
if (state !== ble_1.BleState.POWERED_ON) {
|
|
@@ -583,9 +581,12 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
583
581
|
if (scanForDevice && cntFound > 0)
|
|
584
582
|
return;
|
|
585
583
|
const d = this.createDevice(DeviceClass, peripheral, characteristics);
|
|
586
|
-
if (!d)
|
|
584
|
+
if (!d) {
|
|
585
|
+
this.logEvent({ message: `${opStr}: could not create device `, DeviceClass });
|
|
587
586
|
return;
|
|
587
|
+
}
|
|
588
588
|
try {
|
|
589
|
+
this.logEvent({ message: `${opStr}: connecting `, device: d.name, profile: d.getProfile(), address: d.address });
|
|
589
590
|
yield d.connect();
|
|
590
591
|
}
|
|
591
592
|
catch (err) {
|
|
@@ -31,9 +31,7 @@ class BlePeripheralConnector {
|
|
|
31
31
|
if (this.logger) {
|
|
32
32
|
this.logger.logEvent(event);
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
console.log('~~~BLE:', event);
|
|
36
|
-
}
|
|
34
|
+
console.log('~~~BLE:', event);
|
|
37
35
|
}
|
|
38
36
|
connect() {
|
|
39
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -132,15 +130,15 @@ class BlePeripheralConnector {
|
|
|
132
130
|
this.logEvent({ message: 'subscribe', characteristic: characteristicUuid, characteristics: this.characteristics.map(c => ({ characteristic: c.uuid, uuid: (0, ble_1.uuid)(c.uuid) })) });
|
|
133
131
|
return new Promise((resolve, reject) => {
|
|
134
132
|
try {
|
|
135
|
-
const characteristic = this.characteristics.find(c => c.uuid === characteristicUuid || (0, ble_1.uuid)(c.uuid) === characteristicUuid);
|
|
136
|
-
this.logEvent({ message: 'subscribe', peripheral: this.peripheral.address, characteristic: characteristic.uuid, uuid: (0, ble_1.uuid)(characteristic.uuid) });
|
|
133
|
+
const characteristic = this.characteristics.find(c => (0, ble_1.uuid)(c.uuid) === (0, ble_1.uuid)(characteristicUuid) || (0, ble_1.uuid)(c.uuid) === (0, ble_1.uuid)(characteristicUuid));
|
|
137
134
|
if (!characteristic) {
|
|
138
135
|
reject(new Error('Characteristic not found'));
|
|
139
136
|
return;
|
|
140
137
|
}
|
|
138
|
+
this.logEvent({ message: 'subscribe', peripheral: this.peripheral.address, characteristic: characteristic.uuid, uuid: (0, ble_1.uuid)(characteristic.uuid) });
|
|
141
139
|
characteristic.removeAllListeners('data');
|
|
142
140
|
characteristic.on('data', (data, _isNotification) => {
|
|
143
|
-
this.onData(characteristicUuid, data);
|
|
141
|
+
this.onData((0, ble_1.uuid)(characteristicUuid), data);
|
|
144
142
|
});
|
|
145
143
|
const to = setTimeout(() => {
|
|
146
144
|
this.logEvent({ message: 'subscribe result', characteristic: characteristicUuid, error: 'timeout' });
|
|
@@ -163,18 +161,18 @@ class BlePeripheralConnector {
|
|
|
163
161
|
});
|
|
164
162
|
}
|
|
165
163
|
onData(characteristicUuid, data) {
|
|
166
|
-
this.emitter.emit(characteristicUuid, characteristicUuid, data);
|
|
164
|
+
this.emitter.emit((0, ble_1.uuid)(characteristicUuid), characteristicUuid, data);
|
|
167
165
|
}
|
|
168
166
|
on(characteristicUuid, callback) {
|
|
169
167
|
if (callback)
|
|
170
|
-
this.emitter.on(characteristicUuid, callback);
|
|
168
|
+
this.emitter.on((0, ble_1.uuid)(characteristicUuid), callback);
|
|
171
169
|
}
|
|
172
170
|
off(characteristicUuid, callback) {
|
|
173
171
|
if (callback)
|
|
174
|
-
this.emitter.off(characteristicUuid, callback);
|
|
172
|
+
this.emitter.off((0, ble_1.uuid)(characteristicUuid), callback);
|
|
175
173
|
}
|
|
176
174
|
removeAllListeners(characteristicUuid) {
|
|
177
|
-
this.emitter.removeAllListeners(characteristicUuid);
|
|
175
|
+
this.emitter.removeAllListeners((0, ble_1.uuid)(characteristicUuid));
|
|
178
176
|
}
|
|
179
177
|
getState() {
|
|
180
178
|
return this.peripheral.state;
|
package/lib/ble/ble.js
CHANGED
package/lib/ble/tacx.d.ts
CHANGED
|
@@ -24,6 +24,14 @@ declare type CrankData = {
|
|
|
24
24
|
time?: number;
|
|
25
25
|
cntUpdateMissing?: number;
|
|
26
26
|
};
|
|
27
|
+
declare type MessageInfo = {
|
|
28
|
+
message: string;
|
|
29
|
+
ts: number;
|
|
30
|
+
uuid: string;
|
|
31
|
+
};
|
|
32
|
+
declare type MessageLog = {
|
|
33
|
+
[uuid: string]: MessageInfo;
|
|
34
|
+
};
|
|
27
35
|
export default class TacxAdvancedFitnessMachineDevice extends BleFitnessMachineDevice {
|
|
28
36
|
static services: string[];
|
|
29
37
|
static characteristics: string[];
|
|
@@ -34,6 +42,8 @@ export default class TacxAdvancedFitnessMachineDevice extends BleFitnessMachineD
|
|
|
34
42
|
tsPrevWrite: any;
|
|
35
43
|
data: BleFeBikeData;
|
|
36
44
|
hasFECData: boolean;
|
|
45
|
+
prevMessages: MessageLog;
|
|
46
|
+
messageCnt: number;
|
|
37
47
|
constructor(props?: any);
|
|
38
48
|
isMatching(characteristics: string[]): boolean;
|
|
39
49
|
init(): Promise<boolean>;
|
|
@@ -44,9 +54,13 @@ export default class TacxAdvancedFitnessMachineDevice extends BleFitnessMachineD
|
|
|
44
54
|
isHrm(): boolean;
|
|
45
55
|
requestControl(): Promise<boolean>;
|
|
46
56
|
parseCrankData(crankData: any): {
|
|
57
|
+
rpm?: undefined;
|
|
58
|
+
time?: undefined;
|
|
59
|
+
} | {
|
|
47
60
|
rpm: number;
|
|
48
61
|
time: any;
|
|
49
62
|
};
|
|
63
|
+
parseCSC(_data: Buffer): IndoorBikeData;
|
|
50
64
|
parsePower(_data: Buffer): IndoorBikeData;
|
|
51
65
|
resetState(): void;
|
|
52
66
|
parseFEState(capStateBF: number): void;
|
package/lib/ble/tacx.js
CHANGED
|
@@ -76,6 +76,8 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
76
76
|
this.tsPrevWrite = undefined;
|
|
77
77
|
this.data = {};
|
|
78
78
|
this.hasFECData = false;
|
|
79
|
+
this.messageCnt = 0;
|
|
80
|
+
this.prevMessages = {};
|
|
79
81
|
}
|
|
80
82
|
isMatching(characteristics) {
|
|
81
83
|
if (!characteristics)
|
|
@@ -120,8 +122,10 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
120
122
|
});
|
|
121
123
|
}
|
|
122
124
|
parseCrankData(crankData) {
|
|
123
|
-
if (!this.prevCrankData)
|
|
124
|
-
this.prevCrankData = {
|
|
125
|
+
if (!this.prevCrankData) {
|
|
126
|
+
this.prevCrankData = Object.assign(Object.assign({}, crankData), { cntUpdateMissing: -1 });
|
|
127
|
+
return {};
|
|
128
|
+
}
|
|
125
129
|
const c = this.currentCrankData = crankData;
|
|
126
130
|
const p = this.prevCrankData;
|
|
127
131
|
let rpm = this.data.cadence;
|
|
@@ -150,7 +154,29 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
150
154
|
this.prevCrankData.cntUpdateMissing = cntUpdateMissing + 1;
|
|
151
155
|
return { rpm, time: this.timeOffset + c.time };
|
|
152
156
|
}
|
|
157
|
+
parseCSC(_data) {
|
|
158
|
+
this.logEvent({ message: 'BLE CSC message', data: _data.toString('hex') });
|
|
159
|
+
const data = Buffer.from(_data);
|
|
160
|
+
let offset = 0;
|
|
161
|
+
const flags = data.readUInt8(offset);
|
|
162
|
+
offset++;
|
|
163
|
+
if (flags & 0x01) {
|
|
164
|
+
offset += 6;
|
|
165
|
+
}
|
|
166
|
+
if (flags & 0x02) {
|
|
167
|
+
const crankData = {
|
|
168
|
+
revolutions: data.readUInt16LE(offset),
|
|
169
|
+
time: data.readUInt16LE(offset + 2)
|
|
170
|
+
};
|
|
171
|
+
const { rpm, time } = this.parseCrankData(crankData);
|
|
172
|
+
this.data.cadence = rpm;
|
|
173
|
+
this.data.time = time;
|
|
174
|
+
offset += 4;
|
|
175
|
+
}
|
|
176
|
+
return this.data;
|
|
177
|
+
}
|
|
153
178
|
parsePower(_data) {
|
|
179
|
+
this.logEvent({ message: 'BLE CSP message', data: _data.toString('hex') });
|
|
154
180
|
const data = Buffer.from(_data);
|
|
155
181
|
try {
|
|
156
182
|
let offset = 4;
|
|
@@ -174,6 +200,7 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
174
200
|
}
|
|
175
201
|
}
|
|
176
202
|
catch (err) {
|
|
203
|
+
this.logEvent({ message: 'error', fn: 'parsePower()', error: err.message || err, stack: err.stack });
|
|
177
204
|
}
|
|
178
205
|
const { instantaneousPower, cadence, time } = this.data;
|
|
179
206
|
return { instantaneousPower, cadence, time, raw: data.toString('hex') };
|
|
@@ -349,6 +376,8 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
349
376
|
break;
|
|
350
377
|
}
|
|
351
378
|
this.parseFEState(flagStateBF);
|
|
379
|
+
if (power !== undefined && cadence !== undefined)
|
|
380
|
+
this.hasFECData = true;
|
|
352
381
|
return this.data;
|
|
353
382
|
}
|
|
354
383
|
parseProductInformation(data) {
|
|
@@ -374,26 +403,40 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
374
403
|
}
|
|
375
404
|
const len = data.readUInt8(1);
|
|
376
405
|
const messageId = data.readUInt8(4);
|
|
377
|
-
this.hasFECData = true;
|
|
378
406
|
let res;
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
407
|
+
try {
|
|
408
|
+
switch (messageId) {
|
|
409
|
+
case ANTMessages.generalFE:
|
|
410
|
+
res = this.parseGeneralFE(data.slice(4, len + 3));
|
|
411
|
+
break;
|
|
412
|
+
case ANTMessages.trainerData:
|
|
413
|
+
res = this.parseTrainerData(data.slice(4, len + 3));
|
|
414
|
+
break;
|
|
415
|
+
case ANTMessages.productInformation:
|
|
416
|
+
res = this.parseProductInformation(data.slice(4, len + 3));
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
if (res)
|
|
420
|
+
res.raw = data.toString('hex');
|
|
421
|
+
}
|
|
422
|
+
catch (err) {
|
|
423
|
+
this.logEvent({ message: 'error', fn: 'parseFECMessage()', error: err.message || err, stack: err.stack });
|
|
389
424
|
}
|
|
390
|
-
res.raw = data.toString('hex');
|
|
391
425
|
return res;
|
|
392
426
|
}
|
|
393
427
|
onData(characteristic, data) {
|
|
394
428
|
try {
|
|
395
|
-
super.onData(characteristic, data);
|
|
396
429
|
const uuid = characteristic.toLocaleLowerCase();
|
|
430
|
+
const message = data.toString('hex');
|
|
431
|
+
const ts = Date.now();
|
|
432
|
+
if (this.prevMessages[uuid]) {
|
|
433
|
+
const prev = this.prevMessages[uuid];
|
|
434
|
+
if (prev.message === message && prev.ts > ts - 500) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
this.prevMessages[uuid] = { uuid, ts, message };
|
|
439
|
+
this.messageCnt++;
|
|
397
440
|
let res = undefined;
|
|
398
441
|
if (uuid && uuid.startsWith(TACX_FE_C_RX)) {
|
|
399
442
|
res = this.parseFECMessage(data);
|
|
@@ -411,6 +454,10 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
|
|
|
411
454
|
case '2a37':
|
|
412
455
|
res = this.parseHrm(data);
|
|
413
456
|
break;
|
|
457
|
+
case '2a5b':
|
|
458
|
+
if (!this.hasFECData)
|
|
459
|
+
res = this.parseCSC(data);
|
|
460
|
+
break;
|
|
414
461
|
case '2ada':
|
|
415
462
|
if (!this.hasFECData)
|
|
416
463
|
res = this.parseFitnessMachineStatus(data);
|