incyclist-devices 1.4.63 → 1.4.64
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 +0 -1
- package/lib/ble/ble-device.js +50 -27
- package/lib/ble/ble-peripheral.d.ts +1 -0
- package/lib/ble/ble-peripheral.js +30 -16
- package/lib/ble/fm.d.ts +1 -0
- package/lib/ble/fm.js +19 -3
- package/lib/daum/ERGCyclingMode.js +9 -2
- package/lib/modes/power-meter.js +2 -2
- package/lib/modes/simulator.js +9 -0
- package/lib/simulator/Simulator.js +5 -0
- package/package.json +1 -1
package/lib/ble/ble-device.d.ts
CHANGED
package/lib/ble/ble-device.js
CHANGED
|
@@ -47,9 +47,7 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
47
47
|
if (this.logger) {
|
|
48
48
|
this.logger.logEvent(event);
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
console.log('~~~BLE:', event);
|
|
52
|
-
}
|
|
50
|
+
console.log('~~~BLE:', event);
|
|
53
51
|
}
|
|
54
52
|
setLogger(logger) {
|
|
55
53
|
this.logger = logger;
|
|
@@ -246,6 +244,7 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
246
244
|
if (writeIdx !== -1) {
|
|
247
245
|
const writeItem = this.writeQueue[writeIdx];
|
|
248
246
|
this.writeQueue.splice(writeIdx, 1);
|
|
247
|
+
console.log('~~~ write queue', this.writeQueue);
|
|
249
248
|
if (writeItem.resolve)
|
|
250
249
|
writeItem.resolve(data);
|
|
251
250
|
}
|
|
@@ -253,34 +252,58 @@ class BleDevice extends ble_1.BleDeviceClass {
|
|
|
253
252
|
}
|
|
254
253
|
write(characteristicUuid, data, withoutResponse = false) {
|
|
255
254
|
return __awaiter(this, void 0, void 0, function* () {
|
|
256
|
-
|
|
255
|
+
try {
|
|
257
256
|
const connector = this.ble.getConnector(this.peripheral);
|
|
258
|
-
connector.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (withoutResponse) {
|
|
271
|
-
characteristic.write(data, withoutResponse);
|
|
272
|
-
resolve(new ArrayBuffer(0));
|
|
273
|
-
return;
|
|
257
|
+
const isAlreadySubscribed = connector.isSubscribed(characteristicUuid);
|
|
258
|
+
console.log('~~~ write ', characteristicUuid, data.toString('hex'), isAlreadySubscribed, this.subscribedCharacteristics);
|
|
259
|
+
if (!withoutResponse && !isAlreadySubscribed) {
|
|
260
|
+
const connector = this.ble.getConnector(this.peripheral);
|
|
261
|
+
connector.on(characteristicUuid, (uuid, data) => {
|
|
262
|
+
this.onData(uuid, data);
|
|
263
|
+
});
|
|
264
|
+
this.logEvent({ message: 'write:subscribing ', characteristic: characteristicUuid });
|
|
265
|
+
yield connector.subscribe(characteristicUuid);
|
|
266
|
+
this.subscribedCharacteristics.push(characteristicUuid);
|
|
274
267
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
268
|
+
return new Promise((resolve, reject) => {
|
|
269
|
+
const characteristic = this.characteristics.find(c => c.uuid === characteristicUuid || (0, ble_1.uuid)(c.uuid) === characteristicUuid);
|
|
270
|
+
if (!characteristic) {
|
|
271
|
+
reject(new Error('Characteristic not found'));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (withoutResponse) {
|
|
275
|
+
this.logEvent({ message: 'writing' });
|
|
276
|
+
characteristic.write(data, withoutResponse);
|
|
277
|
+
resolve(new ArrayBuffer(0));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const writeId = this.writeQueue.length;
|
|
282
|
+
let messageDeleted = false;
|
|
283
|
+
this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, resolve, reject });
|
|
284
|
+
const to = setTimeout(() => {
|
|
285
|
+
console.log('~~~ write timeout');
|
|
286
|
+
if (this.writeQueue.length > writeId && !messageDeleted)
|
|
287
|
+
this.writeQueue.splice(writeId, 1);
|
|
288
|
+
this.logEvent({ message: 'writing response', err: 'timeout' });
|
|
289
|
+
reject(new Error('timeout'));
|
|
290
|
+
}, 1000);
|
|
291
|
+
this.logEvent({ message: 'writing' });
|
|
292
|
+
characteristic.write(data, withoutResponse, (err) => {
|
|
293
|
+
clearTimeout(to);
|
|
294
|
+
this.logEvent({ message: 'writing response', err });
|
|
295
|
+
if (err) {
|
|
296
|
+
this.writeQueue.splice(writeId, 1);
|
|
297
|
+
messageDeleted = true;
|
|
298
|
+
reject(err);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
281
301
|
}
|
|
282
302
|
});
|
|
283
|
-
}
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
this.logEvent({ message: 'error', fn: '', error: err.message || err, stack: err.stack });
|
|
306
|
+
}
|
|
284
307
|
});
|
|
285
308
|
}
|
|
286
309
|
read(characteristicUuid) {
|
|
@@ -22,6 +22,7 @@ export default class BlePeripheralConnector {
|
|
|
22
22
|
reconnect(): Promise<void>;
|
|
23
23
|
onDisconnect(): void;
|
|
24
24
|
initialize(enforce?: boolean): Promise<void>;
|
|
25
|
+
isSubscribed(characteristicUuid: string): boolean;
|
|
25
26
|
subscribeAll(callback: (characteristicUuid: string, data: any) => void): Promise<string[]>;
|
|
26
27
|
subscribe(characteristicUuid: string): Promise<boolean>;
|
|
27
28
|
onData(characteristicUuid: string, data: any): void;
|
|
@@ -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* () {
|
|
@@ -86,6 +84,9 @@ class BlePeripheralConnector {
|
|
|
86
84
|
this.state.isInitialized = this.characteristics !== undefined && this.services !== undefined;
|
|
87
85
|
});
|
|
88
86
|
}
|
|
87
|
+
isSubscribed(characteristicUuid) {
|
|
88
|
+
return this.state.subscribed.find(c => c === characteristicUuid || (0, ble_1.uuid)(c) === characteristicUuid || c === (0, ble_1.uuid)(characteristicUuid)) !== undefined;
|
|
89
|
+
}
|
|
89
90
|
subscribeAll(callback) {
|
|
90
91
|
return __awaiter(this, void 0, void 0, function* () {
|
|
91
92
|
const cnt = this.characteristics.length;
|
|
@@ -127,21 +128,34 @@ class BlePeripheralConnector {
|
|
|
127
128
|
});
|
|
128
129
|
}
|
|
129
130
|
subscribe(characteristicUuid) {
|
|
131
|
+
this.logEvent({ message: 'subscribe', characteristic: characteristicUuid, characteristics: this.characteristics.map(c => ({ characteristic: c.uuid, uuid: (0, ble_1.uuid)(c.uuid) })) });
|
|
130
132
|
return new Promise((resolve, reject) => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
try {
|
|
134
|
+
const characteristic = this.characteristics.find(c => c.uuid === characteristicUuid || (0, ble_1.uuid)(c.uuid) === characteristicUuid);
|
|
135
|
+
this.logEvent({ message: 'subscribe', peripheral: this.peripheral.address, characteristic: characteristic.uuid, uuid: (0, ble_1.uuid)(characteristic.uuid) });
|
|
136
|
+
if (!characteristic) {
|
|
137
|
+
reject(new Error('Characteristic not found'));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
characteristic.on('data', (data, _isNotification) => {
|
|
141
|
+
this.onData(characteristicUuid, data);
|
|
142
|
+
});
|
|
143
|
+
const to = setTimeout(() => {
|
|
144
|
+
this.logEvent({ message: 'subscribe result', characteristic: characteristicUuid, error: 'timeout' });
|
|
145
|
+
reject(new Error('timeout'));
|
|
146
|
+
}, 3000);
|
|
147
|
+
characteristic.subscribe((err) => {
|
|
148
|
+
clearTimeout(to);
|
|
149
|
+
this.logEvent({ message: 'subscribe result', characteristic: characteristicUuid, error: err });
|
|
150
|
+
if (err)
|
|
151
|
+
reject(err);
|
|
152
|
+
else
|
|
153
|
+
resolve(true);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
this.logEvent({ message: 'error', error: err.message || err, stack: err.stack });
|
|
135
158
|
}
|
|
136
|
-
characteristic.on('data', (data, _isNotification) => {
|
|
137
|
-
this.onData(characteristicUuid, data);
|
|
138
|
-
});
|
|
139
|
-
characteristic.subscribe((err) => {
|
|
140
|
-
if (err)
|
|
141
|
-
reject(err);
|
|
142
|
-
else
|
|
143
|
-
resolve(true);
|
|
144
|
-
});
|
|
145
159
|
});
|
|
146
160
|
}
|
|
147
161
|
onData(characteristicUuid, data) {
|
package/lib/ble/fm.d.ts
CHANGED
package/lib/ble/fm.js
CHANGED
|
@@ -86,6 +86,7 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
86
86
|
super(props);
|
|
87
87
|
this.features = undefined;
|
|
88
88
|
this.hasControl = false;
|
|
89
|
+
this.isCheckingControl = false;
|
|
89
90
|
this.isCPSubscribed = false;
|
|
90
91
|
this.crr = 0.0033;
|
|
91
92
|
this.cw = 0.6;
|
|
@@ -300,6 +301,7 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
300
301
|
writeFtmsMessage(requestedOpCode, data) {
|
|
301
302
|
return __awaiter(this, void 0, void 0, function* () {
|
|
302
303
|
try {
|
|
304
|
+
this.logEvent({ message: 'fmts:write', data: data.toString('hex') });
|
|
303
305
|
const res = yield this.write(FTMS_CP, data);
|
|
304
306
|
const responseData = Buffer.from(res);
|
|
305
307
|
const opCode = responseData.readUInt8(0);
|
|
@@ -307,19 +309,25 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
307
309
|
const result = responseData.readUInt8(2);
|
|
308
310
|
if (opCode !== 128 || request !== requestedOpCode)
|
|
309
311
|
throw new Error('Illegal response ');
|
|
312
|
+
this.logEvent({ message: 'fmts:write result', res, result });
|
|
310
313
|
return result;
|
|
311
314
|
}
|
|
312
315
|
catch (err) {
|
|
313
|
-
this.logEvent({ message: '
|
|
316
|
+
this.logEvent({ message: 'fmts:write failed', opCode: requestedOpCode, reason: err.message });
|
|
314
317
|
return 4;
|
|
315
318
|
}
|
|
316
319
|
});
|
|
317
320
|
}
|
|
318
321
|
requestControl() {
|
|
319
322
|
return __awaiter(this, void 0, void 0, function* () {
|
|
323
|
+
let to = undefined;
|
|
324
|
+
if (this.isCheckingControl) {
|
|
325
|
+
to = setTimeout(() => { }, 3500);
|
|
326
|
+
}
|
|
320
327
|
if (this.hasControl)
|
|
321
328
|
return true;
|
|
322
329
|
this.logEvent({ message: 'requestControl' });
|
|
330
|
+
this.isCheckingControl = true;
|
|
323
331
|
const data = Buffer.alloc(1);
|
|
324
332
|
data.writeUInt8(0, 0);
|
|
325
333
|
const res = yield this.writeFtmsMessage(0, data);
|
|
@@ -329,6 +337,9 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
329
337
|
else {
|
|
330
338
|
this.logEvent({ message: 'requestControl failed' });
|
|
331
339
|
}
|
|
340
|
+
this.isCheckingControl = false;
|
|
341
|
+
if (to)
|
|
342
|
+
clearTimeout(to);
|
|
332
343
|
return this.hasControl;
|
|
333
344
|
});
|
|
334
345
|
}
|
|
@@ -340,6 +351,10 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
340
351
|
if (!this.hasControl)
|
|
341
352
|
return;
|
|
342
353
|
const hasControl = yield this.requestControl();
|
|
354
|
+
if (!hasControl) {
|
|
355
|
+
this.logEvent({ message: 'setTargetPower failed', reason: 'control is disabled' });
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
343
358
|
const data = Buffer.alloc(3);
|
|
344
359
|
data.writeUInt8(5, 0);
|
|
345
360
|
data.writeInt16LE(Math.round(power), 1);
|
|
@@ -350,7 +365,8 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
|
|
|
350
365
|
setSlope(slope) {
|
|
351
366
|
return __awaiter(this, void 0, void 0, function* () {
|
|
352
367
|
this.logEvent({ message: 'setSlope', slope });
|
|
353
|
-
|
|
368
|
+
const hasControl = yield this.requestControl();
|
|
369
|
+
if (!hasControl)
|
|
354
370
|
return;
|
|
355
371
|
const { windSpeed, crr, cw } = this;
|
|
356
372
|
return yield this.setIndoorBikeSimulation(windSpeed, slope, crr, cw);
|
|
@@ -582,7 +598,7 @@ class FmAdapter extends Device_1.default {
|
|
|
582
598
|
break;
|
|
583
599
|
}
|
|
584
600
|
}
|
|
585
|
-
this.device.requestControl();
|
|
601
|
+
yield this.device.requestControl();
|
|
586
602
|
const startRequest = this.getCyclingMode().getBikeInitRequest();
|
|
587
603
|
yield this.sendUpdate(startRequest);
|
|
588
604
|
bleDevice.on('data', (data) => {
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const CyclingMode_1 = require("../CyclingMode");
|
|
7
7
|
const calculations_1 = __importDefault(require("../calculations"));
|
|
8
8
|
const power_base_1 = __importDefault(require("../modes/power-base"));
|
|
9
|
+
const MIN_SPEED = 10;
|
|
9
10
|
const config = {
|
|
10
11
|
name: "ERG",
|
|
11
12
|
description: "Calculates speed based on power and slope. Power is either set by workout or calculated based on gear and cadence",
|
|
@@ -147,9 +148,15 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
147
148
|
const m = this.getWeight();
|
|
148
149
|
const t = this.getTimeSinceLastUpdate();
|
|
149
150
|
const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
150
|
-
|
|
151
|
+
if (power === 0 && speed < MIN_SPEED) {
|
|
152
|
+
data.speed = Math.round(prevData.speed - 1) < 0 ? 0 : Math.round(prevData.speed - 1);
|
|
153
|
+
data.distanceInternal = distanceInternal + data.speed / 3.6 * t;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
data.speed = speed;
|
|
157
|
+
data.distanceInternal = distanceInternal + distance;
|
|
158
|
+
}
|
|
151
159
|
data.power = Math.round(power);
|
|
152
|
-
data.distanceInternal = distanceInternal + distance;
|
|
153
160
|
data.slope = slope;
|
|
154
161
|
data.pedalRpm = rpm;
|
|
155
162
|
data.gear = gear;
|
package/lib/modes/power-meter.js
CHANGED
|
@@ -62,8 +62,8 @@ class PowerMeterCyclingMode extends power_base_1.default {
|
|
|
62
62
|
data.distanceInternal = distanceInternal + data.speed / 3.6 * t;
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
|
-
data.speed =
|
|
66
|
-
data.distanceInternal =
|
|
65
|
+
data.speed = speed;
|
|
66
|
+
data.distanceInternal = distanceInternal + distance;
|
|
67
67
|
}
|
|
68
68
|
if (props.log)
|
|
69
69
|
this.logger.logEvent({ message: "updateData result", data, bikeData, prevSpeed: prevData.speed, stopped: speed < MIN_SPEED });
|
package/lib/modes/simulator.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
7
|
const CyclingMode_1 = require("../CyclingMode");
|
|
8
8
|
const power_base_1 = __importDefault(require("./power-base"));
|
|
9
|
+
const MIN_SPEED = 10;
|
|
9
10
|
const config = {
|
|
10
11
|
name: "Simulator",
|
|
11
12
|
description: "Simulates a ride with constant speed or power output",
|
|
@@ -106,6 +107,14 @@ class SimulatorCyclingMode extends power_base_1.default {
|
|
|
106
107
|
speed = res.speed;
|
|
107
108
|
distance = res.distance;
|
|
108
109
|
}
|
|
110
|
+
if (power === 0 && speed < MIN_SPEED) {
|
|
111
|
+
data.speed = Math.round(prevData.speed - 1) < 0 ? 0 : Math.round(prevData.speed - 1);
|
|
112
|
+
data.distanceInternal = distanceInternal + data.speed / 3.6 * t;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
data.speed = speed;
|
|
116
|
+
data.distanceInternal = distanceInternal + distance;
|
|
117
|
+
}
|
|
109
118
|
data.speed = speed;
|
|
110
119
|
data.power = Math.round(power);
|
|
111
120
|
data.distanceInternal = distanceInternal + distance;
|
|
@@ -218,6 +218,8 @@ class Simulator extends Device_1.default {
|
|
|
218
218
|
return;
|
|
219
219
|
}
|
|
220
220
|
const prevDist = this.data.distanceInternal;
|
|
221
|
+
const d = this.data;
|
|
222
|
+
const prevTime = d.deviceTime;
|
|
221
223
|
this.data = this.getCyclingMode().updateData(this.data);
|
|
222
224
|
let data = {
|
|
223
225
|
speed: this.data.speed,
|
|
@@ -230,6 +232,9 @@ class Simulator extends Device_1.default {
|
|
|
230
232
|
deviceTime: (Date.now() - this.startTS) / 1000,
|
|
231
233
|
deviceDistanceCounter: this.data.distanceInternal
|
|
232
234
|
};
|
|
235
|
+
if (this.isBot) {
|
|
236
|
+
this.logger.logEvent(Object.assign({ message: 'Coach update', prevDist, prevTime }, data));
|
|
237
|
+
}
|
|
233
238
|
this.paused = (this.data.speed === 0);
|
|
234
239
|
if (this.ignoreHrm)
|
|
235
240
|
delete data.heartrate;
|