incyclist-devices 1.4.56 → 1.4.59
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/Device.d.ts +1 -1
- package/lib/ant/AntAdapter.d.ts +7 -0
- package/lib/ant/AntAdapter.js +16 -0
- package/lib/ble/ble-interface.d.ts +2 -0
- package/lib/ble/ble-interface.js +31 -15
- package/lib/ble/incyclist-protocol.js +9 -4
- package/lib/ble/pwr.d.ts +7 -0
- package/lib/ble/pwr.js +35 -1
- package/lib/daum/DaumAdapter.js +6 -6
- package/lib/daum/ERGCyclingMode.js +1 -1
- package/lib/daum/classic/DaumClassicAdapter.js +5 -1
- package/lib/daum/premium/DaumPremiumAdapter.js +4 -0
- package/lib/modes/simulator.d.ts +3 -2
- package/lib/modes/simulator.js +28 -16
- package/lib/simulator/Simulator.d.ts +7 -0
- package/lib/simulator/Simulator.js +25 -2
- package/package.json +1 -1
package/lib/Device.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export interface DeviceAdapter extends Device {
|
|
|
34
34
|
getName(): string;
|
|
35
35
|
getPort(): string;
|
|
36
36
|
getProtocol(): DeviceProtocol;
|
|
37
|
-
getProtocolName(): string;
|
|
37
|
+
getProtocolName(): string | undefined;
|
|
38
38
|
setIgnoreHrm(ignore: boolean): void;
|
|
39
39
|
setIgnorePower(ignore: boolean): void;
|
|
40
40
|
setIgnoreBike(ignore: boolean): void;
|
package/lib/ant/AntAdapter.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ export default class AntAdapter extends DeviceAdapter {
|
|
|
17
17
|
logger: EventLogger;
|
|
18
18
|
lastUpdate?: number;
|
|
19
19
|
updateFrequency: number;
|
|
20
|
+
userSettings: {
|
|
21
|
+
weight?: number;
|
|
22
|
+
};
|
|
23
|
+
bikeSettings: {
|
|
24
|
+
weight?: number;
|
|
25
|
+
};
|
|
20
26
|
constructor(protocol: any);
|
|
21
27
|
isSame(device: DeviceAdapter): boolean;
|
|
22
28
|
setSensor(sensor: any): void;
|
|
@@ -26,6 +32,7 @@ export default class AntAdapter extends DeviceAdapter {
|
|
|
26
32
|
setIgnorePower(ignore: any): void;
|
|
27
33
|
getProfile(): string;
|
|
28
34
|
getPort(): string;
|
|
35
|
+
getWeight(): number;
|
|
29
36
|
setChannel(channel: any): void;
|
|
30
37
|
setStick(stick: any): void;
|
|
31
38
|
isStopped(): boolean;
|
package/lib/ant/AntAdapter.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.DEFAULT_UPDATE_FREQUENCY = void 0;
|
|
7
7
|
const Device_1 = __importDefault(require("../Device"));
|
|
8
|
+
const Device_2 = require("../Device");
|
|
8
9
|
exports.DEFAULT_UPDATE_FREQUENCY = 1000;
|
|
9
10
|
class AntAdapter extends Device_1.default {
|
|
10
11
|
constructor(protocol) {
|
|
@@ -49,6 +50,17 @@ class AntAdapter extends Device_1.default {
|
|
|
49
50
|
getPort() {
|
|
50
51
|
return this.port;
|
|
51
52
|
}
|
|
53
|
+
getWeight() {
|
|
54
|
+
let userWeight = Device_2.DEFAULT_USER_WEIGHT;
|
|
55
|
+
let bikeWeight = Device_2.DEFAULT_BIKE_WEIGHT;
|
|
56
|
+
if (this.userSettings && this.userSettings.weight) {
|
|
57
|
+
userWeight = Number(this.userSettings.weight);
|
|
58
|
+
}
|
|
59
|
+
if (this.bikeSettings && this.bikeSettings.weight) {
|
|
60
|
+
bikeWeight = Number(this.bikeSettings.weight);
|
|
61
|
+
}
|
|
62
|
+
return bikeWeight + userWeight;
|
|
63
|
+
}
|
|
52
64
|
setChannel(channel) {
|
|
53
65
|
this.channel = channel;
|
|
54
66
|
}
|
|
@@ -78,6 +90,10 @@ class AntAdapter extends Device_1.default {
|
|
|
78
90
|
});
|
|
79
91
|
}
|
|
80
92
|
start(props) {
|
|
93
|
+
if (props && props.user)
|
|
94
|
+
this.userSettings = props.user;
|
|
95
|
+
if (props && props.bikeSettings)
|
|
96
|
+
this.bikeSettings = props.bikeSettings;
|
|
81
97
|
return new Promise(resolve => {
|
|
82
98
|
this.stopped = false;
|
|
83
99
|
resolve(true);
|
|
@@ -61,6 +61,8 @@ export default class BleInterface extends BleInterfaceClass {
|
|
|
61
61
|
disconnect(): Promise<boolean>;
|
|
62
62
|
isConnected(): boolean;
|
|
63
63
|
getDevicesFromServices(deviceTypes: (typeof BleDeviceClass)[], services: string | string[]): (typeof BleDeviceClass)[];
|
|
64
|
+
getAllSupportedServices(): any[];
|
|
65
|
+
getAllSupportedDeviceTypes(): (typeof BleDeviceClass)[];
|
|
64
66
|
getServicesFromDeviceTypes(deviceTypes: (typeof BleDeviceClass)[]): string[];
|
|
65
67
|
getServicesFromDevice(device: BleDeviceClass): string[];
|
|
66
68
|
waitForConnectFinished(timeout: any): Promise<unknown>;
|
package/lib/ble/ble-interface.js
CHANGED
|
@@ -18,8 +18,6 @@ const ble_1 = require("./ble");
|
|
|
18
18
|
const ble_peripheral_1 = __importDefault(require("./ble-peripheral"));
|
|
19
19
|
const CONNECT_TIMEOUT = 5000;
|
|
20
20
|
const DEFAULT_SCAN_TIMEOUT = 20000;
|
|
21
|
-
const BACKGROUND_SCAN_TIMEOUT = 30000;
|
|
22
|
-
const DEFAULT_SERVICES = ['1818', '180d', '1826'];
|
|
23
21
|
class BleInterface extends ble_1.BleInterfaceClass {
|
|
24
22
|
constructor(props = {}) {
|
|
25
23
|
super(props);
|
|
@@ -76,14 +74,6 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
76
74
|
const timeout = props.timeout || 2000;
|
|
77
75
|
const runBackgroundScan = () => {
|
|
78
76
|
return;
|
|
79
|
-
this.scanState.isBackgroundScan = true;
|
|
80
|
-
this.scan({ timeout: BACKGROUND_SCAN_TIMEOUT, isBackgroundScan: true })
|
|
81
|
-
.then(() => {
|
|
82
|
-
this.scanState.isBackgroundScan = false;
|
|
83
|
-
})
|
|
84
|
-
.catch(() => {
|
|
85
|
-
this.scanState.isBackgroundScan = false;
|
|
86
|
-
});
|
|
87
77
|
};
|
|
88
78
|
return new Promise((resolve, reject) => {
|
|
89
79
|
if (this.connectState.isConnected) {
|
|
@@ -223,6 +213,25 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
223
213
|
}
|
|
224
214
|
return [];
|
|
225
215
|
}
|
|
216
|
+
getAllSupportedServices() {
|
|
217
|
+
const supported = BleInterface.deviceClasses;
|
|
218
|
+
const res = [];
|
|
219
|
+
if (supported && supported.length > 0) {
|
|
220
|
+
supported.forEach(dc => {
|
|
221
|
+
if (dc && dc.services) {
|
|
222
|
+
dc.services.forEach(s => {
|
|
223
|
+
if (!res.includes(s))
|
|
224
|
+
res.push(s);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
return res;
|
|
230
|
+
}
|
|
231
|
+
getAllSupportedDeviceTypes() {
|
|
232
|
+
const supported = BleInterface.deviceClasses;
|
|
233
|
+
return supported.map(dc => dc.Class);
|
|
234
|
+
}
|
|
226
235
|
getServicesFromDeviceTypes(deviceTypes) {
|
|
227
236
|
let services = [];
|
|
228
237
|
try {
|
|
@@ -369,7 +378,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
369
378
|
this.scanState.isConnecting = true;
|
|
370
379
|
const existing = this.devices.find(i => (!profile || i.device.getProfile() === profile) && (i.device.address === requested.address || i.device.id === requested.id || i.device.name === requested.name));
|
|
371
380
|
if (existing) {
|
|
372
|
-
|
|
381
|
+
yield existing.device.connect();
|
|
373
382
|
this.scanState.isConnecting = false;
|
|
374
383
|
return existing.device;
|
|
375
384
|
}
|
|
@@ -461,7 +470,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
461
470
|
requested.profile;
|
|
462
471
|
const { id, address, name } = requested || {};
|
|
463
472
|
const scanForDevice = (requested !== null && requested !== undefined);
|
|
464
|
-
const services = (props.isBackgroundScan || !deviceTypes || deviceTypes.length === 0) ?
|
|
473
|
+
const services = (props.isBackgroundScan || !deviceTypes || deviceTypes.length === 0) ? this.getAllSupportedServices() : this.getServicesFromDeviceTypes(deviceTypes);
|
|
465
474
|
const bleBinding = this.getBinding();
|
|
466
475
|
if (!bleBinding)
|
|
467
476
|
return Promise.reject(new Error('no binding defined'));
|
|
@@ -485,7 +494,8 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
485
494
|
}
|
|
486
495
|
else {
|
|
487
496
|
opStr = 'scan';
|
|
488
|
-
|
|
497
|
+
const supported = BleInterface.deviceClasses.map(dc => ({ id: dc.id, type: dc.type, services: dc.services }));
|
|
498
|
+
this.logEvent({ message: 'scan start', services, supported });
|
|
489
499
|
}
|
|
490
500
|
if (this.scanState.isScanning) {
|
|
491
501
|
try {
|
|
@@ -506,6 +516,8 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
506
516
|
const knownDevices = this.devices.map(i => ({ name: i.device.name, address: i.device.address, isConnected: i.isConnected, connectState: i.device.getConnectState() }));
|
|
507
517
|
this.logEvent({ message: `${opStr}: check if already registered`, device: { name, address }, knownDevices });
|
|
508
518
|
const existing = this.devices.find(i => (i.device.address === address || i.device.name === name || i.device.id === id));
|
|
519
|
+
if (existing)
|
|
520
|
+
this.logEvent({ message: `${opStr}: device already registered`, device: { name, address } });
|
|
509
521
|
}
|
|
510
522
|
}
|
|
511
523
|
const onTimeout = () => {
|
|
@@ -527,14 +539,18 @@ class BleInterface extends ble_1.BleInterfaceClass {
|
|
|
527
539
|
const onPeripheralFound = (peripheral, fromCache = false) => __awaiter(this, void 0, void 0, function* () {
|
|
528
540
|
if (fromCache)
|
|
529
541
|
this.logEvent({ message: 'adding from Cache', peripheral: peripheral.address });
|
|
542
|
+
else {
|
|
543
|
+
const { id, name, address } = peripheral;
|
|
544
|
+
this.logEvent({ message: 'BLE scan: found device', peripheral: { id, name, address } });
|
|
545
|
+
}
|
|
530
546
|
if (!peripheral || !peripheral.advertisement || !peripheral.advertisement.serviceUuids || peripheral.advertisement.serviceUuids.length === 0)
|
|
531
547
|
return;
|
|
548
|
+
if (peripheral.address === undefined || peripheral.address === '')
|
|
549
|
+
peripheral.address = peripheral.id;
|
|
532
550
|
const isPeripheralProcessed = peripheralsProcessed.find(p => p === peripheral.address) !== undefined;
|
|
533
551
|
if (isPeripheralProcessed)
|
|
534
552
|
return;
|
|
535
553
|
peripheralsProcessed.push(peripheral.address);
|
|
536
|
-
let chachedPeripheralInfo = this.peripheralCache.find(i => i.address === peripheral.address);
|
|
537
|
-
const str = fromCache ? 'added' : 'detected';
|
|
538
554
|
const characteristics = yield this.getCharacteristics(peripheral);
|
|
539
555
|
const DeviceClasses = this.getDeviceClasses(peripheral, { profile });
|
|
540
556
|
let cntFound = 0;
|
|
@@ -39,7 +39,7 @@ const ble_interface_1 = __importDefault(require("./ble-interface"));
|
|
|
39
39
|
const fm_1 = __importStar(require("./fm"));
|
|
40
40
|
const hrm_1 = __importStar(require("./hrm"));
|
|
41
41
|
const pwr_1 = __importStar(require("./pwr"));
|
|
42
|
-
const
|
|
42
|
+
const wahoo_kickr_1 = __importDefault(require("./wahoo-kickr"));
|
|
43
43
|
class BleProtocol extends DeviceProtocol_1.default {
|
|
44
44
|
constructor(binding) {
|
|
45
45
|
super();
|
|
@@ -79,9 +79,13 @@ class BleProtocol extends DeviceProtocol_1.default {
|
|
|
79
79
|
if (fromDevice)
|
|
80
80
|
device = bleDevice;
|
|
81
81
|
else {
|
|
82
|
-
device = this.ble.findDeviceInCache(Object.assign(Object.assign({}, props()), { profile
|
|
83
|
-
if (!device)
|
|
84
|
-
|
|
82
|
+
device = this.ble.findDeviceInCache(Object.assign(Object.assign({}, props()), { profile }));
|
|
83
|
+
if (!device) {
|
|
84
|
+
if (profile.toLocaleLowerCase() === 'wahoo smart trainer')
|
|
85
|
+
device = new wahoo_kickr_1.default(props());
|
|
86
|
+
else
|
|
87
|
+
device = new fm_1.default(props());
|
|
88
|
+
}
|
|
85
89
|
}
|
|
86
90
|
return new fm_1.FmAdapter(device, this);
|
|
87
91
|
case 'cp':
|
|
@@ -109,6 +113,7 @@ class BleProtocol extends DeviceProtocol_1.default {
|
|
|
109
113
|
}
|
|
110
114
|
});
|
|
111
115
|
this.logger.logEvent({ message: 'scan started' });
|
|
116
|
+
const supportedDeviceTypes = this.ble.getAllSupportedDeviceTypes();
|
|
112
117
|
yield this.ble.scan({ deviceTypes: supportedDeviceTypes, timeout: 20000 });
|
|
113
118
|
if (props && props.onScanFinished) {
|
|
114
119
|
props.onScanFinished(props.id);
|
package/lib/ble/pwr.d.ts
CHANGED
|
@@ -54,6 +54,12 @@ export declare class PwrAdapter extends DeviceAdapter {
|
|
|
54
54
|
mode: CyclingMode;
|
|
55
55
|
distanceInternal: number;
|
|
56
56
|
prevDataTS: number;
|
|
57
|
+
userSettings: {
|
|
58
|
+
weight?: number;
|
|
59
|
+
};
|
|
60
|
+
bikeSettings: {
|
|
61
|
+
weight?: number;
|
|
62
|
+
};
|
|
57
63
|
constructor(device: BleDeviceClass, protocol: BleProtocol);
|
|
58
64
|
isBike(): boolean;
|
|
59
65
|
isHrm(): boolean;
|
|
@@ -65,6 +71,7 @@ export declare class PwrAdapter extends DeviceAdapter {
|
|
|
65
71
|
getCyclingMode(): CyclingMode;
|
|
66
72
|
getDefaultCyclingMode(): CyclingMode;
|
|
67
73
|
getPort(): string;
|
|
74
|
+
getWeight(): number;
|
|
68
75
|
setIgnoreBike(ignore: any): void;
|
|
69
76
|
setIgnorePower(ignore: any): void;
|
|
70
77
|
onDeviceData(deviceData: PowerData): void;
|
package/lib/ble/pwr.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
2
21
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
22
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
23
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -15,7 +34,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
34
|
exports.PwrAdapter = void 0;
|
|
16
35
|
const ble_device_1 = require("./ble-device");
|
|
17
36
|
const ble_interface_1 = __importDefault(require("./ble-interface"));
|
|
18
|
-
const Device_1 =
|
|
37
|
+
const Device_1 = __importStar(require("../Device"));
|
|
19
38
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
20
39
|
const power_meter_1 = __importDefault(require("../modes/power-meter"));
|
|
21
40
|
class BleCyclingPowerDevice extends ble_device_1.BleDevice {
|
|
@@ -172,6 +191,17 @@ class PwrAdapter extends Device_1.default {
|
|
|
172
191
|
getPort() {
|
|
173
192
|
return 'ble';
|
|
174
193
|
}
|
|
194
|
+
getWeight() {
|
|
195
|
+
let userWeight = Device_1.DEFAULT_USER_WEIGHT;
|
|
196
|
+
let bikeWeight = Device_1.DEFAULT_BIKE_WEIGHT;
|
|
197
|
+
if (this.userSettings && this.userSettings.weight) {
|
|
198
|
+
userWeight = Number(this.userSettings.weight);
|
|
199
|
+
}
|
|
200
|
+
if (this.bikeSettings && this.bikeSettings.weight) {
|
|
201
|
+
bikeWeight = Number(this.bikeSettings.weight);
|
|
202
|
+
}
|
|
203
|
+
return bikeWeight + userWeight;
|
|
204
|
+
}
|
|
175
205
|
setIgnoreBike(ignore) {
|
|
176
206
|
this.ignore = ignore;
|
|
177
207
|
}
|
|
@@ -230,6 +260,10 @@ class PwrAdapter extends Device_1.default {
|
|
|
230
260
|
}
|
|
231
261
|
start(props) {
|
|
232
262
|
return __awaiter(this, void 0, void 0, function* () {
|
|
263
|
+
if (props && props.user)
|
|
264
|
+
this.userSettings = props.user;
|
|
265
|
+
if (props && props.bikeSettings)
|
|
266
|
+
this.bikeSettings = props.bikeSettings;
|
|
233
267
|
this.logger.logEvent({ message: 'start requested', profile: this.getProfile(), props });
|
|
234
268
|
try {
|
|
235
269
|
const bleDevice = yield this.ble.connectDevice(this.device);
|
package/lib/daum/DaumAdapter.js
CHANGED
|
@@ -108,8 +108,8 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
getWeight() {
|
|
111
|
-
const userWeight = this.userSettings.weight || Device_1.DEFAULT_USER_WEIGHT;
|
|
112
|
-
const bikeWeight = this.bikeSettings.weight || Device_1.DEFAULT_BIKE_WEIGHT;
|
|
111
|
+
const userWeight = Number(this.userSettings.weight || Device_1.DEFAULT_USER_WEIGHT);
|
|
112
|
+
const bikeWeight = Number(this.bikeSettings.weight || Device_1.DEFAULT_BIKE_WEIGHT);
|
|
113
113
|
return bikeWeight + userWeight;
|
|
114
114
|
}
|
|
115
115
|
getCurrentBikeData() {
|
|
@@ -318,13 +318,13 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
318
318
|
return;
|
|
319
319
|
let distance = 0;
|
|
320
320
|
if (this.distanceInternal !== undefined && this.cyclingData.distanceInternal !== undefined) {
|
|
321
|
-
distance =
|
|
321
|
+
distance = this.cyclingData.distanceInternal - this.distanceInternal;
|
|
322
322
|
}
|
|
323
323
|
if (this.cyclingData.distanceInternal !== undefined)
|
|
324
324
|
this.distanceInternal = this.cyclingData.distanceInternal;
|
|
325
325
|
let data = {
|
|
326
|
-
speed:
|
|
327
|
-
slope:
|
|
326
|
+
speed: this.cyclingData.speed,
|
|
327
|
+
slope: this.cyclingData.slope,
|
|
328
328
|
power: (0, utils_1.intVal)(this.cyclingData.power),
|
|
329
329
|
cadence: (0, utils_1.intVal)(this.cyclingData.pedalRpm),
|
|
330
330
|
heartrate: (0, utils_1.intVal)(this.cyclingData.heartrate),
|
|
@@ -366,7 +366,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
366
366
|
}
|
|
367
367
|
catch (err) {
|
|
368
368
|
this.requestBusy = false;
|
|
369
|
-
this.logEvent({ message: 'error',
|
|
369
|
+
this.logEvent({ message: 'sendRequest error', error: err.message || err });
|
|
370
370
|
return;
|
|
371
371
|
}
|
|
372
372
|
});
|
|
@@ -147,7 +147,7 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
147
147
|
const m = this.getWeight();
|
|
148
148
|
const t = this.getTimeSinceLastUpdate();
|
|
149
149
|
const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
150
|
-
data.speed =
|
|
150
|
+
data.speed = speed;
|
|
151
151
|
data.power = Math.round(power);
|
|
152
152
|
data.distanceInternal = distanceInternal + distance;
|
|
153
153
|
data.slope = slope;
|
|
@@ -83,7 +83,11 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
83
83
|
return __awaiter(this, void 0, void 0, function* () {
|
|
84
84
|
this.logger.logEvent({ message: 'start()', props });
|
|
85
85
|
const opts = props || {};
|
|
86
|
-
const { user } =
|
|
86
|
+
const { user, bikeSettings } = opts;
|
|
87
|
+
if (user && user.weight)
|
|
88
|
+
this.userSettings.weight = user.weight;
|
|
89
|
+
if (bikeSettings && bikeSettings.weight)
|
|
90
|
+
this.bikeSettings.weight = bikeSettings.weight;
|
|
87
91
|
this.initData();
|
|
88
92
|
let startState = {};
|
|
89
93
|
return (0, utils_1.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -68,6 +68,10 @@ class DaumPremiumDevice extends DaumAdapter_1.default {
|
|
|
68
68
|
console.log('~~~setPersonSupport:', this.getCyclingMode().getModeProperty('setPersonSupport'));
|
|
69
69
|
console.log('~~~eppSupport:', this.getCyclingMode().getModeProperty('eppSupport'));
|
|
70
70
|
const opts = props || {};
|
|
71
|
+
if (opts.user && opts.user.weight)
|
|
72
|
+
this.userSettings.weight = opts.user.weight;
|
|
73
|
+
if (opts.bikeSettings && opts.bikeSettings.weight)
|
|
74
|
+
this.bikeSettings.weight = opts.bikeSettings.weight;
|
|
71
75
|
const user = opts.user || this.userSettings;
|
|
72
76
|
const route = opts.route;
|
|
73
77
|
var info = {};
|
package/lib/modes/simulator.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { EventLogger } from "gd-eventlog";
|
|
2
|
-
import
|
|
2
|
+
import { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
|
|
3
3
|
import { Simulator } from "../simulator/Simulator";
|
|
4
|
+
import PowerBasedCyclingModeBase from "./power-base";
|
|
4
5
|
export declare type ERGEvent = {
|
|
5
6
|
rpmUpdated?: boolean;
|
|
6
7
|
gearUpdated?: boolean;
|
|
7
8
|
starting?: boolean;
|
|
8
9
|
tsStart?: number;
|
|
9
10
|
};
|
|
10
|
-
export default class SimulatorCyclingMode extends
|
|
11
|
+
export default class SimulatorCyclingMode extends PowerBasedCyclingModeBase {
|
|
11
12
|
logger: EventLogger;
|
|
12
13
|
data: IncyclistBikeData;
|
|
13
14
|
prevRequest: UpdateRequest;
|
package/lib/modes/simulator.js
CHANGED
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
7
|
const CyclingMode_1 = require("../CyclingMode");
|
|
8
|
-
const
|
|
8
|
+
const power_base_1 = __importDefault(require("./power-base"));
|
|
9
9
|
const config = {
|
|
10
10
|
name: "Simulator",
|
|
11
11
|
description: "Simulates a ride with constant speed or power output",
|
|
@@ -14,9 +14,10 @@ const config = {
|
|
|
14
14
|
{ key: 'delay', name: 'Start Delay', description: 'Delay (in s) at start of training', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 2, min: 0, max: 30 },
|
|
15
15
|
{ key: 'power', name: 'Power', description: 'Power (in W) at start of training', condition: (s) => !s.mode || s.mode === 'Power', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 150, min: 25, max: 800 },
|
|
16
16
|
{ key: 'speed', name: 'Speed', description: 'Speed (in km/h) at start of training', condition: (s) => s.mode === 'Speed', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 30, min: 5, max: 50 },
|
|
17
|
+
{ key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' }
|
|
17
18
|
]
|
|
18
19
|
};
|
|
19
|
-
class SimulatorCyclingMode extends
|
|
20
|
+
class SimulatorCyclingMode extends power_base_1.default {
|
|
20
21
|
constructor(adapter, props) {
|
|
21
22
|
super(adapter, props);
|
|
22
23
|
this.prevUpdateTS = 0;
|
|
@@ -62,41 +63,52 @@ class SimulatorCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
62
63
|
const prevSpeed = prevData.speed;
|
|
63
64
|
const prevRequest = this.prevRequest || {};
|
|
64
65
|
const data = this.data || {};
|
|
66
|
+
const bikeType = (this.getSetting('bikeType') || 'Race').toLowerCase();
|
|
65
67
|
const mode = this.getSetting('mode');
|
|
66
68
|
delete this.event.gearUpdated;
|
|
67
69
|
delete this.event.rpmUpdated;
|
|
68
70
|
try {
|
|
69
71
|
let rpm = 90;
|
|
70
|
-
let power = (mode === '
|
|
72
|
+
let power = (!mode || mode.toLowerCase() === 'power') ? Number(this.getSetting('power')) : bikeData.power || 0;
|
|
71
73
|
let slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
|
|
72
|
-
let speed = mode === '
|
|
73
|
-
let m =
|
|
74
|
+
let speed = mode.toLowerCase() === 'speed' ? Number(this.getSetting('speed')) : bikeData.speed || 0;
|
|
75
|
+
let m = this.getWeight();
|
|
74
76
|
let distanceInternal = prevData.distanceInternal || 0;
|
|
75
77
|
let ts = Date.now();
|
|
76
78
|
let duration = this.prevUpdateTS === 0 ? 0 : ((ts - this.prevUpdateTS) / 1000);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
const t = this.getTimeSinceLastUpdate();
|
|
80
|
+
let distance = 0;
|
|
81
|
+
if (!mode || mode.toLowerCase() === 'power') {
|
|
82
|
+
const res = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
83
|
+
speed = res.speed;
|
|
84
|
+
distance = res.distance;
|
|
79
85
|
}
|
|
80
|
-
else if (mode === '
|
|
81
|
-
|
|
86
|
+
else if (mode.toLowerCase() === 'speed') {
|
|
87
|
+
const res = this.calculatePowerAndDistance(speed, slope, m, t, { bikeType });
|
|
88
|
+
power = res.power;
|
|
89
|
+
distance = res.distance;
|
|
82
90
|
}
|
|
83
91
|
if (prevRequest.targetPower) {
|
|
84
92
|
power = prevRequest.targetPower;
|
|
85
|
-
|
|
93
|
+
const res = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
94
|
+
speed = res.speed;
|
|
95
|
+
distance = res.distance;
|
|
86
96
|
}
|
|
87
97
|
if (prevRequest.maxPower && power > prevRequest.maxPower) {
|
|
88
98
|
power = prevRequest.maxPower;
|
|
89
|
-
|
|
99
|
+
const res = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
100
|
+
speed = res.speed;
|
|
101
|
+
distance = res.distance;
|
|
90
102
|
}
|
|
91
103
|
else if (prevRequest.minPower && power < prevRequest.minPower) {
|
|
92
104
|
power = prevRequest.minPower;
|
|
93
|
-
|
|
105
|
+
const res = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
106
|
+
speed = res.speed;
|
|
107
|
+
distance = res.distance;
|
|
94
108
|
}
|
|
95
|
-
|
|
96
|
-
distanceInternal += (v * duration);
|
|
97
|
-
data.speed = parseFloat(speed.toFixed(1));
|
|
109
|
+
data.speed = speed;
|
|
98
110
|
data.power = Math.round(power);
|
|
99
|
-
data.distanceInternal = distanceInternal;
|
|
111
|
+
data.distanceInternal = distanceInternal + distance;
|
|
100
112
|
data.slope = slope;
|
|
101
113
|
data.pedalRpm = rpm;
|
|
102
114
|
if (data.time !== undefined)
|
|
@@ -24,6 +24,12 @@ export declare class Simulator extends DeviceAdapter {
|
|
|
24
24
|
data: IncyclistBikeData;
|
|
25
25
|
isBot: boolean;
|
|
26
26
|
ignoreHrm: boolean;
|
|
27
|
+
userSettings: {
|
|
28
|
+
weight?: number;
|
|
29
|
+
};
|
|
30
|
+
bikeSettings: {
|
|
31
|
+
weight?: number;
|
|
32
|
+
};
|
|
27
33
|
constructor(protocol?: DeviceProtocol, props?: SimulatorSettings);
|
|
28
34
|
isBike(): boolean;
|
|
29
35
|
isHrm(): boolean;
|
|
@@ -32,6 +38,7 @@ export declare class Simulator extends DeviceAdapter {
|
|
|
32
38
|
getID(): string;
|
|
33
39
|
getName(): string;
|
|
34
40
|
getPort(): string;
|
|
41
|
+
getWeight(): number;
|
|
35
42
|
setIgnoreHrm(ignore: any): void;
|
|
36
43
|
getSupportedCyclingModes(): Array<any>;
|
|
37
44
|
getDefaultCyclingMode(): CyclingMode;
|
|
@@ -37,6 +37,7 @@ const DeviceRegistry_1 = __importDefault(require("../DeviceRegistry"));
|
|
|
37
37
|
const Device_1 = __importDefault(require("../Device"));
|
|
38
38
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
39
39
|
const simulator_1 = __importDefault(require("../modes/simulator"));
|
|
40
|
+
const Device_2 = require("../Device");
|
|
40
41
|
const DEFAULT_SETTINGS = { name: 'Simulator', port: '', isBot: false };
|
|
41
42
|
class Simulator extends Device_1.default {
|
|
42
43
|
constructor(protocol, props = DEFAULT_SETTINGS) {
|
|
@@ -72,6 +73,17 @@ class Simulator extends Device_1.default {
|
|
|
72
73
|
getID() { return Simulator.NAME; }
|
|
73
74
|
getName() { return Simulator.NAME; }
|
|
74
75
|
getPort() { return 'local'; }
|
|
76
|
+
getWeight() {
|
|
77
|
+
let userWeight = Device_2.DEFAULT_USER_WEIGHT;
|
|
78
|
+
let bikeWeight = Device_2.DEFAULT_BIKE_WEIGHT;
|
|
79
|
+
if (this.userSettings && this.userSettings.weight) {
|
|
80
|
+
userWeight = Number(this.userSettings.weight);
|
|
81
|
+
}
|
|
82
|
+
if (this.bikeSettings && this.bikeSettings.weight) {
|
|
83
|
+
bikeWeight = Number(this.bikeSettings.weight);
|
|
84
|
+
}
|
|
85
|
+
return bikeWeight + userWeight;
|
|
86
|
+
}
|
|
75
87
|
setIgnoreHrm(ignore) {
|
|
76
88
|
this.ignoreHrm = ignore;
|
|
77
89
|
}
|
|
@@ -108,6 +120,10 @@ class Simulator extends Device_1.default {
|
|
|
108
120
|
start(props) {
|
|
109
121
|
return __awaiter(this, void 0, void 0, function* () {
|
|
110
122
|
this.startProps = props;
|
|
123
|
+
if (props && props.user)
|
|
124
|
+
this.userSettings = props.user;
|
|
125
|
+
if (props && props.bikeSettings)
|
|
126
|
+
this.bikeSettings = props.bikeSettings;
|
|
111
127
|
return new Promise((resolve) => {
|
|
112
128
|
if (!this.isBot)
|
|
113
129
|
this.logger.logEvent({ message: 'start', iv: this.iv });
|
|
@@ -117,6 +133,12 @@ class Simulator extends Device_1.default {
|
|
|
117
133
|
this.started = true;
|
|
118
134
|
this.time = Date.now();
|
|
119
135
|
this.startTS = this.time;
|
|
136
|
+
if (this.isBot) {
|
|
137
|
+
this.startTS = props.activity ? Date.parse(props.activity.startTime) : this.startTS - 1500;
|
|
138
|
+
const sm = this.getCyclingMode();
|
|
139
|
+
sm.prevUpdateTS = this.startTS;
|
|
140
|
+
this.update();
|
|
141
|
+
}
|
|
120
142
|
if (this.iv !== undefined) {
|
|
121
143
|
clearInterval(this.iv);
|
|
122
144
|
this.iv = undefined;
|
|
@@ -192,8 +214,9 @@ class Simulator extends Device_1.default {
|
|
|
192
214
|
update() {
|
|
193
215
|
const startDelay = this.getCyclingMode().getSetting('delay');
|
|
194
216
|
const timeSinceStart = Date.now() - this.startTS;
|
|
195
|
-
if (startDelay && timeSinceStart < startDelay * 1000)
|
|
217
|
+
if (!this.isBot && startDelay && timeSinceStart < startDelay * 1000) {
|
|
196
218
|
return;
|
|
219
|
+
}
|
|
197
220
|
const prevDist = this.data.distanceInternal;
|
|
198
221
|
this.data = this.getCyclingMode().updateData(this.data);
|
|
199
222
|
let data = {
|
|
@@ -204,7 +227,7 @@ class Simulator extends Device_1.default {
|
|
|
204
227
|
distance: this.data.distanceInternal - prevDist,
|
|
205
228
|
heartrate: Math.round(this.data.power - 10 + Math.random() * 20),
|
|
206
229
|
timestamp: Date.now(),
|
|
207
|
-
deviceTime:
|
|
230
|
+
deviceTime: (Date.now() - this.startTS) / 1000,
|
|
208
231
|
deviceDistanceCounter: this.data.distanceInternal
|
|
209
232
|
};
|
|
210
233
|
this.paused = (this.data.speed === 0);
|