incyclist-devices 1.4.22 → 1.4.25
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/CyclingMode.js +0 -1
- package/lib/Device.js +0 -1
- package/lib/DeviceProtocol.d.ts +1 -0
- package/lib/DeviceProtocol.js +1 -1
- package/lib/DeviceSupport.js +8 -21
- package/lib/ant/AntAdapter.js +0 -1
- package/lib/ant/AntScanner.js +10 -21
- package/lib/ant/antfe/AntFEAdapter.js +7 -7
- package/lib/ant/anthrm/AntHrmAdapter.js +1 -1
- package/lib/ant/antpwr/AntPWRAdapter.d.ts +24 -0
- package/lib/ant/antpwr/AntPWRAdapter.js +252 -0
- package/lib/ant/antpwr/pwr-adapter.d.ts +48 -0
- package/lib/ant/antpwr/pwr-adapter.js +259 -0
- package/lib/ant/utils.js +1 -3
- package/lib/calculations.js +2 -4
- package/lib/daum/DaumAdapter.d.ts +2 -2
- package/lib/daum/DaumAdapter.js +31 -39
- package/lib/daum/DaumPowerMeterCyclingMode.d.ts +8 -0
- package/lib/daum/DaumPowerMeterCyclingMode.js +21 -0
- package/lib/daum/ERGCyclingMode.d.ts +3 -6
- package/lib/daum/ERGCyclingMode.js +15 -27
- package/lib/daum/SmartTrainerCyclingMode.js +0 -1
- package/lib/daum/classic/DaumClassicAdapter.js +2 -2
- package/lib/daum/classic/DaumClassicProtocol.js +7 -19
- package/lib/daum/classic/bike.js +26 -26
- package/lib/daum/classic/utils.js +0 -1
- package/lib/daum/constants.js +0 -1
- package/lib/daum/premium/DaumClassicCyclingMode.d.ts +2 -2
- package/lib/daum/premium/DaumClassicCyclingMode.js +2 -2
- package/lib/daum/premium/DaumPremiumAdapter.js +2 -2
- package/lib/daum/premium/DaumPremiumProtocol.js +7 -19
- package/lib/daum/premium/bike.js +17 -18
- package/lib/daum/premium/utils.js +0 -1
- package/lib/kettler/comms.js +1 -2
- package/lib/kettler/ergo-racer/adapter.js +10 -22
- package/lib/kettler/ergo-racer/modes/power-meter.d.ts +2 -2
- package/lib/kettler/ergo-racer/modes/power-meter.js +12 -4
- package/lib/kettler/ergo-racer/protocol.js +7 -19
- package/lib/modes/power-base.d.ts +20 -0
- package/lib/modes/power-base.js +60 -0
- package/lib/modes/power-meter.d.ts +20 -0
- package/lib/modes/power-meter.js +70 -0
- package/lib/modes/simulator.d.ts +27 -0
- package/lib/modes/simulator.js +118 -0
- package/lib/simulator/Simulator.js +10 -23
- package/lib/simulator/simulator-mode.js +4 -4
- package/lib/types/route.js +0 -1
- package/lib/types/user.js +0 -1
- package/lib/utils.js +1 -3
- package/package.json +1 -1
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const gd_eventlog_1 = require("gd-eventlog");
|
|
16
|
+
const AntAdapter_1 = __importDefault(require("../AntAdapter"));
|
|
17
|
+
const utils_1 = require("../utils");
|
|
18
|
+
const power_meter_1 = __importDefault(require("../../modes/power-meter"));
|
|
19
|
+
const floatVal = (d) => d ? parseFloat(d) : d;
|
|
20
|
+
const intVal = (d) => d ? parseInt(d) : d;
|
|
21
|
+
const hex = (v) => Math.abs(v).toString(16).toUpperCase();
|
|
22
|
+
const DEFAULT_START_TIMEOUT = 5000;
|
|
23
|
+
class AntFEAdapter extends AntAdapter_1.default {
|
|
24
|
+
constructor(DeviceID, port, stick, protocol) {
|
|
25
|
+
super(protocol);
|
|
26
|
+
this.logger = new gd_eventlog_1.EventLogger('Ant+PWR');
|
|
27
|
+
this.logger.logEvent({ message: 'Ant+PWR Adapter created', DeviceID, port });
|
|
28
|
+
this.deviceID = DeviceID;
|
|
29
|
+
this.port = port;
|
|
30
|
+
this.stick = stick;
|
|
31
|
+
this.deviceData = {
|
|
32
|
+
DeviceID
|
|
33
|
+
};
|
|
34
|
+
this.data = {};
|
|
35
|
+
this.started = false;
|
|
36
|
+
this.starting = false;
|
|
37
|
+
this.connected = false;
|
|
38
|
+
this.mode = this.getDefaultCyclingMode();
|
|
39
|
+
}
|
|
40
|
+
isBike() { return true; }
|
|
41
|
+
isHrm() { return false; }
|
|
42
|
+
isPower() { return true; }
|
|
43
|
+
getProfile() {
|
|
44
|
+
return 'Power Meter';
|
|
45
|
+
}
|
|
46
|
+
getName() {
|
|
47
|
+
return `Ant+PWR ${this.deviceID}`;
|
|
48
|
+
}
|
|
49
|
+
getDisplayName() {
|
|
50
|
+
const { DeviceID, ManId } = this.deviceData;
|
|
51
|
+
return `${utils_1.getBrand(ManId)} PWR ${DeviceID}`;
|
|
52
|
+
}
|
|
53
|
+
getCyclingMode() {
|
|
54
|
+
if (!this.mode)
|
|
55
|
+
this.mode = this.getDefaultCyclingMode();
|
|
56
|
+
return this.mode;
|
|
57
|
+
}
|
|
58
|
+
getDefaultCyclingMode() {
|
|
59
|
+
return new power_meter_1.default(this);
|
|
60
|
+
}
|
|
61
|
+
onAttached() {
|
|
62
|
+
this.logger.logEvent({ message: 'Device connected' });
|
|
63
|
+
this.connected = true;
|
|
64
|
+
}
|
|
65
|
+
getLogData(data, excludeList) {
|
|
66
|
+
const logData = JSON.parse(JSON.stringify(data));
|
|
67
|
+
excludeList.forEach((key) => {
|
|
68
|
+
delete logData[key];
|
|
69
|
+
});
|
|
70
|
+
return logData;
|
|
71
|
+
}
|
|
72
|
+
onDeviceData(deviceData) {
|
|
73
|
+
if (!this.started || this.isStopped())
|
|
74
|
+
return;
|
|
75
|
+
this.deviceData = deviceData;
|
|
76
|
+
try {
|
|
77
|
+
if (this.onDataFn && !(this.ignoreBike && this.ignorePower) && !this.paused) {
|
|
78
|
+
if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
|
|
79
|
+
const logData = this.getLogData(deviceData, ['PairedDevices', 'RawData']);
|
|
80
|
+
this.logger.logEvent({ message: 'onDeviceData', data: logData });
|
|
81
|
+
let incyclistData = this.mapData(deviceData);
|
|
82
|
+
incyclistData = this.getCyclingMode().updateData(incyclistData);
|
|
83
|
+
const data = this.transformData(incyclistData);
|
|
84
|
+
this.onDataFn(data);
|
|
85
|
+
this.lastUpdate = Date.now();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
onDeviceEvent(data) {
|
|
93
|
+
try {
|
|
94
|
+
const cmdInfo = this.currentCmd;
|
|
95
|
+
if (!cmdInfo)
|
|
96
|
+
return;
|
|
97
|
+
const msg = cmdInfo.msg.readUInt8(2);
|
|
98
|
+
const Constants = this.getProtocol().getAnt().Constants;
|
|
99
|
+
const { expectedResponse } = cmdInfo;
|
|
100
|
+
if (data.message === msg) {
|
|
101
|
+
if (expectedResponse === undefined && data.code === Constants.EVENT_TRANSFER_TX_COMPLETED) {
|
|
102
|
+
this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (expectedResponse === undefined && data.code !== Constants.EVENT_TRANSFER_TX_COMPLETED) {
|
|
106
|
+
this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (data.message === 1) {
|
|
111
|
+
if (expectedResponse !== undefined && data.code === expectedResponse) {
|
|
112
|
+
this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (expectedResponse === undefined && (data.code === Constants.EVENT_TRANSFER_TX_COMPLETED || data.code === 3)) {
|
|
116
|
+
this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (data.code === Constants.EVENT_TRANSFER_TX_FAILED || data.code === Constants.EVENT_CHANNEL_COLLISION) {
|
|
120
|
+
this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (this.currentCmd !== undefined && data.message === Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA && data.code === 31) {
|
|
125
|
+
this.logger.log("could not send (TRANSFER_IN_PROGRESS)");
|
|
126
|
+
this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.logger.logEvent({ message: "Incoming Event ", event: { message: hex(data.message), code: hex(data.code) } });
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
this.logger.logEvent({ message: 'Error', fn: 'parseEvent', event: { message: hex(data.message), code: hex(data.code) }, error: err.message || err });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
sendUpdate(request) {
|
|
136
|
+
if (this.paused)
|
|
137
|
+
return;
|
|
138
|
+
this.getCyclingMode().sendBikeUpdate(request);
|
|
139
|
+
}
|
|
140
|
+
mapData(deviceData) {
|
|
141
|
+
const data = {
|
|
142
|
+
isPedalling: false,
|
|
143
|
+
power: 0,
|
|
144
|
+
pedalRpm: 0,
|
|
145
|
+
speed: 0,
|
|
146
|
+
heartrate: 0,
|
|
147
|
+
distanceInternal: 0,
|
|
148
|
+
slope: undefined,
|
|
149
|
+
time: undefined
|
|
150
|
+
};
|
|
151
|
+
data.slope = (deviceData.Slope !== undefined ? deviceData.Slope : data.slope);
|
|
152
|
+
data.power = (deviceData.Power !== undefined ? deviceData.Power : data.power);
|
|
153
|
+
data.pedalRpm = (deviceData.Cadence !== undefined ? deviceData.Cadence : data.pedalRpm);
|
|
154
|
+
data.time = (deviceData.TimeStamp !== undefined ? deviceData.TimeStamp : data.time);
|
|
155
|
+
data.isPedalling = data.pedalRpm > 0;
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
transformData(bikeData) {
|
|
159
|
+
if (bikeData === undefined)
|
|
160
|
+
return;
|
|
161
|
+
let distance = 0;
|
|
162
|
+
if (this.distanceInternal !== undefined && bikeData.distanceInternal !== undefined) {
|
|
163
|
+
distance = intVal(bikeData.distanceInternal - this.distanceInternal);
|
|
164
|
+
}
|
|
165
|
+
if (bikeData.distanceInternal !== undefined)
|
|
166
|
+
this.distanceInternal = bikeData.distanceInternal;
|
|
167
|
+
let data = {
|
|
168
|
+
speed: floatVal(bikeData.speed),
|
|
169
|
+
slope: floatVal(bikeData.slope),
|
|
170
|
+
power: intVal(bikeData.power),
|
|
171
|
+
cadence: intVal(bikeData.pedalRpm),
|
|
172
|
+
distance,
|
|
173
|
+
timestamp: Date.now()
|
|
174
|
+
};
|
|
175
|
+
if (this.ignorePower) {
|
|
176
|
+
delete data.power;
|
|
177
|
+
delete data.cadence;
|
|
178
|
+
}
|
|
179
|
+
if (this.ignoreBike) {
|
|
180
|
+
data = {};
|
|
181
|
+
}
|
|
182
|
+
return data;
|
|
183
|
+
}
|
|
184
|
+
start(props) {
|
|
185
|
+
const _super = Object.create(null, {
|
|
186
|
+
start: { get: () => super.start }
|
|
187
|
+
});
|
|
188
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
+
yield _super.start.call(this, props);
|
|
190
|
+
this.logger.logEvent({ message: 'start()', props });
|
|
191
|
+
const opts = props || {};
|
|
192
|
+
const { args = {} } = opts;
|
|
193
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
194
|
+
if (this.ignoreBike && this.ignorePower) {
|
|
195
|
+
this.logger.logEvent({ message: 'start() not done: bike disabled' });
|
|
196
|
+
return resolve(false);
|
|
197
|
+
}
|
|
198
|
+
if (this.starting) {
|
|
199
|
+
this.logger.logEvent({ message: 'start() not done: bike starting' });
|
|
200
|
+
return resolve(false);
|
|
201
|
+
}
|
|
202
|
+
if (this.started) {
|
|
203
|
+
this.logger.logEvent({ message: 'start() done: bike was already started' });
|
|
204
|
+
return resolve(true);
|
|
205
|
+
}
|
|
206
|
+
this.starting = true;
|
|
207
|
+
const Ant = this.getProtocol().getAnt();
|
|
208
|
+
const protocol = this.getProtocol();
|
|
209
|
+
let start = Date.now();
|
|
210
|
+
let timeout = start + (args.timeout || DEFAULT_START_TIMEOUT);
|
|
211
|
+
const iv = setInterval(() => {
|
|
212
|
+
if (Date.now() > timeout) {
|
|
213
|
+
clearInterval(iv);
|
|
214
|
+
this.starting = false;
|
|
215
|
+
reject(new Error('timeout'));
|
|
216
|
+
}
|
|
217
|
+
if (this.isStopped()) {
|
|
218
|
+
clearInterval(iv);
|
|
219
|
+
this.starting = false;
|
|
220
|
+
reject(new Error('stopped'));
|
|
221
|
+
}
|
|
222
|
+
}, 100);
|
|
223
|
+
protocol.attachSensors(this, Ant.BicyclePowerSensor, 'powerData')
|
|
224
|
+
.then(() => {
|
|
225
|
+
this.starting = false;
|
|
226
|
+
this.started = true;
|
|
227
|
+
clearInterval(iv);
|
|
228
|
+
resolve(true);
|
|
229
|
+
})
|
|
230
|
+
.catch(err => reject(err));
|
|
231
|
+
}));
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
stop() {
|
|
235
|
+
const _super = Object.create(null, {
|
|
236
|
+
stop: { get: () => super.stop }
|
|
237
|
+
});
|
|
238
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
239
|
+
yield _super.stop.call(this);
|
|
240
|
+
this.logger.logEvent({ message: 'stop()' });
|
|
241
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
242
|
+
this.starting = false;
|
|
243
|
+
return resolve(true);
|
|
244
|
+
this.started = false;
|
|
245
|
+
if (this.ignoreHrm)
|
|
246
|
+
return resolve(false);
|
|
247
|
+
try {
|
|
248
|
+
const protocol = this.getProtocol();
|
|
249
|
+
yield protocol.detachSensor(this);
|
|
250
|
+
resolve(true);
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
reject(err);
|
|
254
|
+
}
|
|
255
|
+
}));
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
exports.default = AntFEAdapter;
|
package/lib/ant/utils.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getBrand =
|
|
4
|
-
const getBrand = (manId) => {
|
|
3
|
+
exports.getBrand = (manId) => {
|
|
5
4
|
if (manId === undefined)
|
|
6
5
|
return "ANT+";
|
|
7
6
|
switch (manId) {
|
|
@@ -20,4 +19,3 @@ const getBrand = (manId) => {
|
|
|
20
19
|
return "ANT+";
|
|
21
20
|
}
|
|
22
21
|
};
|
|
23
|
-
exports.getBrand = getBrand;
|
package/lib/calculations.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.solveCubic = exports.IllegalArgumentException = void 0;
|
|
4
3
|
const g = 9.80665;
|
|
5
4
|
const rho = 1.2041;
|
|
6
5
|
const cwABike = {
|
|
@@ -8,7 +7,6 @@ const cwABike = {
|
|
|
8
7
|
triathlon: 0.29,
|
|
9
8
|
mountain: 0.57
|
|
10
9
|
};
|
|
11
|
-
const k = 0.01090;
|
|
12
10
|
const cRR = 0.0036;
|
|
13
11
|
class IllegalArgumentException extends Error {
|
|
14
12
|
constructor(message) {
|
|
@@ -29,7 +27,7 @@ class C {
|
|
|
29
27
|
const _cRR = props.cRR || cRR;
|
|
30
28
|
const _cwA = props.cwA || cwABike[props.bikeType || 'race'] || cwABike.race;
|
|
31
29
|
let sl = Math.atan(slope / 100);
|
|
32
|
-
let c1 = 0.5 * _rho * _cwA
|
|
30
|
+
let c1 = 0.5 * _rho * _cwA;
|
|
33
31
|
let c2 = (sl + _cRR) * m * g;
|
|
34
32
|
let p = c2 / c1;
|
|
35
33
|
let q = -1.0 * power / c1;
|
|
@@ -71,7 +69,7 @@ class C {
|
|
|
71
69
|
let _cRR = props.cRR || cRR;
|
|
72
70
|
let _cwA = props.cwA || cwABike[props.bikeType || 'race'] || cwABike.race;
|
|
73
71
|
let sl = Math.sin(Math.atan(slope / 100));
|
|
74
|
-
let P = (0.5 * _rho * _cwA
|
|
72
|
+
let P = (0.5 * _rho * _cwA) * Math.pow(v, 3.0) + (sl + _cRR) * m * g * v;
|
|
75
73
|
return P;
|
|
76
74
|
}
|
|
77
75
|
static calculateSpeedDaum(gear, rpm, bikeType) {
|
|
@@ -13,7 +13,7 @@ export default class DaumAdapterBase extends DeviceAdapterBase implements Device
|
|
|
13
13
|
distanceInternal: number;
|
|
14
14
|
paused: boolean;
|
|
15
15
|
stopped: boolean;
|
|
16
|
-
|
|
16
|
+
cyclingData: IncyclistBikeData;
|
|
17
17
|
deviceData: DeviceData;
|
|
18
18
|
currentRequest: any;
|
|
19
19
|
requests: Array<any>;
|
|
@@ -56,7 +56,7 @@ export default class DaumAdapterBase extends DeviceAdapterBase implements Device
|
|
|
56
56
|
update(): Promise<void>;
|
|
57
57
|
sendRequests(): Promise<void>;
|
|
58
58
|
bikeSync(): Promise<void>;
|
|
59
|
-
updateData(prev: any, bikeData: any):
|
|
59
|
+
updateData(prev: any, bikeData: any): IncyclistBikeData;
|
|
60
60
|
transformData(): DeviceData;
|
|
61
61
|
sendRequest(request: any): Promise<any>;
|
|
62
62
|
refreshRequests(): void;
|
package/lib/daum/DaumAdapter.js
CHANGED
|
@@ -1,23 +1,4 @@
|
|
|
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
|
-
};
|
|
21
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
22
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
23
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -27,6 +8,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
27
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
28
9
|
});
|
|
29
10
|
};
|
|
11
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
12
|
+
if (mod && mod.__esModule) return mod;
|
|
13
|
+
var result = {};
|
|
14
|
+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
15
|
+
result["default"] = mod;
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
30
18
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
31
19
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
32
20
|
};
|
|
@@ -34,7 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
34
22
|
const Device_1 = __importStar(require("../Device"));
|
|
35
23
|
const ERGCyclingMode_1 = __importDefault(require("./ERGCyclingMode"));
|
|
36
24
|
const SmartTrainerCyclingMode_1 = __importDefault(require("./SmartTrainerCyclingMode"));
|
|
37
|
-
const
|
|
25
|
+
const DaumPowerMeterCyclingMode_1 = __importDefault(require("./DaumPowerMeterCyclingMode"));
|
|
38
26
|
const utils_1 = require("../utils");
|
|
39
27
|
class DaumAdapterBase extends Device_1.default {
|
|
40
28
|
constructor(props, bike) {
|
|
@@ -46,7 +34,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
46
34
|
this.bike = bike;
|
|
47
35
|
this.stopped = false;
|
|
48
36
|
this.paused = false;
|
|
49
|
-
this.
|
|
37
|
+
this.cyclingData = {
|
|
50
38
|
isPedalling: false,
|
|
51
39
|
time: 0,
|
|
52
40
|
power: 0,
|
|
@@ -79,7 +67,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
79
67
|
this.cyclingMode.setSettings(settings);
|
|
80
68
|
}
|
|
81
69
|
getSupportedCyclingModes() {
|
|
82
|
-
return [ERGCyclingMode_1.default, SmartTrainerCyclingMode_1.default,
|
|
70
|
+
return [ERGCyclingMode_1.default, SmartTrainerCyclingMode_1.default, DaumPowerMeterCyclingMode_1.default];
|
|
83
71
|
}
|
|
84
72
|
getCyclingMode() {
|
|
85
73
|
if (!this.cyclingMode)
|
|
@@ -140,7 +128,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
140
128
|
this.distanceInternal = undefined;
|
|
141
129
|
this.paused = false;
|
|
142
130
|
this.stopped = false;
|
|
143
|
-
this.
|
|
131
|
+
this.cyclingData = {
|
|
144
132
|
isPedalling: false,
|
|
145
133
|
time: 0,
|
|
146
134
|
power: 0,
|
|
@@ -241,12 +229,15 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
241
229
|
this.updateBusy = true;
|
|
242
230
|
this.getCurrentBikeData()
|
|
243
231
|
.then(bikeData => {
|
|
244
|
-
this.updateData(this.
|
|
232
|
+
this.updateData(this.cyclingData, bikeData);
|
|
245
233
|
this.transformData();
|
|
246
234
|
this.updateBusy = false;
|
|
247
235
|
})
|
|
248
236
|
.catch(err => {
|
|
249
237
|
this.logEvent({ message: 'bike update error', error: err.message, stack: err.stack });
|
|
238
|
+
const { isPedalling, power, pedalRpm, speed, distanceInternal, heartrate, slope } = this.cyclingData;
|
|
239
|
+
this.updateData(this.cyclingData, { isPedalling, power, pedalRpm, speed, distanceInternal, heartrate, slope });
|
|
240
|
+
this.transformData();
|
|
250
241
|
this.updateBusy = false;
|
|
251
242
|
});
|
|
252
243
|
});
|
|
@@ -301,27 +292,28 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
301
292
|
data.time = bikeData.time;
|
|
302
293
|
if (bikeData.slope)
|
|
303
294
|
data.slope = bikeData.slope;
|
|
304
|
-
this.
|
|
295
|
+
this.cyclingData = this.getCyclingMode().updateData(data);
|
|
296
|
+
return this.cyclingData;
|
|
305
297
|
}
|
|
306
298
|
transformData() {
|
|
307
|
-
if (this.
|
|
299
|
+
if (this.cyclingData === undefined)
|
|
308
300
|
return;
|
|
309
301
|
let distance = 0;
|
|
310
|
-
if (this.distanceInternal !== undefined && this.
|
|
311
|
-
distance =
|
|
302
|
+
if (this.distanceInternal !== undefined && this.cyclingData.distanceInternal !== undefined) {
|
|
303
|
+
distance = utils_1.intVal(this.cyclingData.distanceInternal - this.distanceInternal);
|
|
312
304
|
}
|
|
313
|
-
if (this.
|
|
314
|
-
this.distanceInternal = this.
|
|
305
|
+
if (this.cyclingData.distanceInternal !== undefined)
|
|
306
|
+
this.distanceInternal = this.cyclingData.distanceInternal;
|
|
315
307
|
let data = {
|
|
316
|
-
speed:
|
|
317
|
-
slope:
|
|
318
|
-
power:
|
|
319
|
-
cadence:
|
|
320
|
-
heartrate:
|
|
308
|
+
speed: utils_1.floatVal(this.cyclingData.speed),
|
|
309
|
+
slope: utils_1.floatVal(this.cyclingData.slope),
|
|
310
|
+
power: utils_1.intVal(this.cyclingData.power),
|
|
311
|
+
cadence: utils_1.intVal(this.cyclingData.pedalRpm),
|
|
312
|
+
heartrate: utils_1.intVal(this.cyclingData.heartrate),
|
|
321
313
|
distance,
|
|
322
314
|
timestamp: Date.now(),
|
|
323
|
-
deviceTime: this.
|
|
324
|
-
deviceDistanceCounter: this.
|
|
315
|
+
deviceTime: this.cyclingData.time,
|
|
316
|
+
deviceDistanceCounter: this.cyclingData.distanceInternal
|
|
325
317
|
};
|
|
326
318
|
if (this.ignoreHrm)
|
|
327
319
|
delete data.heartrate;
|
|
@@ -362,7 +354,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
362
354
|
});
|
|
363
355
|
}
|
|
364
356
|
refreshRequests() {
|
|
365
|
-
if (!this.
|
|
357
|
+
if (!this.cyclingData.isPedalling || this.cyclingData.pedalRpm === 0)
|
|
366
358
|
return;
|
|
367
359
|
let bikeRequest = this.getCyclingMode().sendBikeUpdate({ refresh: true }) || {};
|
|
368
360
|
const prev = this.requests[this.requests.length - 1] || {};
|
|
@@ -373,7 +365,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
373
365
|
}
|
|
374
366
|
processClientRequest(request) {
|
|
375
367
|
if (request.slope !== undefined) {
|
|
376
|
-
this.
|
|
368
|
+
this.cyclingData.slope = request.slope;
|
|
377
369
|
}
|
|
378
370
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
379
371
|
let bikeRequest = this.getCyclingMode().sendBikeUpdate(request);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import CyclingMode, { UpdateRequest } from "../CyclingMode";
|
|
2
|
+
import PowerMeterCyclingMode from "../modes/power-meter";
|
|
3
|
+
export default class DaumPowerMeterCyclingMode extends PowerMeterCyclingMode implements CyclingMode {
|
|
4
|
+
prevRequest: UpdateRequest;
|
|
5
|
+
hasBikeUpdate: boolean;
|
|
6
|
+
getBikeInitRequest(): UpdateRequest;
|
|
7
|
+
sendBikeUpdate(request: UpdateRequest): UpdateRequest;
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const power_meter_1 = __importDefault(require("../modes/power-meter"));
|
|
7
|
+
class DaumPowerMeterCyclingMode extends power_meter_1.default {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.hasBikeUpdate = false;
|
|
11
|
+
}
|
|
12
|
+
getBikeInitRequest() {
|
|
13
|
+
return { slope: 0 };
|
|
14
|
+
}
|
|
15
|
+
sendBikeUpdate(request) {
|
|
16
|
+
super.sendBikeUpdate(request);
|
|
17
|
+
this.prevRequest = {};
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.default = DaumPowerMeterCyclingMode;
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import CyclingMode, { CyclingModeBase, CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
|
|
1
|
+
import CyclingMode, { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
|
|
3
2
|
import DaumAdapter from "./DaumAdapter";
|
|
3
|
+
import PowerBasedCyclingModeBase from "../modes/power-base";
|
|
4
4
|
export declare type ERGEvent = {
|
|
5
5
|
rpmUpdated?: boolean;
|
|
6
6
|
gearUpdated?: boolean;
|
|
7
7
|
starting?: boolean;
|
|
8
8
|
tsStart?: number;
|
|
9
9
|
};
|
|
10
|
-
export default class ERGCyclingMode extends
|
|
11
|
-
logger: EventLogger;
|
|
12
|
-
data: IncyclistBikeData;
|
|
10
|
+
export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
|
|
13
11
|
prevRequest: UpdateRequest;
|
|
14
|
-
prevUpdateTS: number;
|
|
15
12
|
hasBikeUpdate: boolean;
|
|
16
13
|
chain: number[];
|
|
17
14
|
cassette: number[];
|
|
@@ -3,9 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
6
|
const CyclingMode_1 = require("../CyclingMode");
|
|
8
7
|
const calculations_1 = __importDefault(require("../calculations"));
|
|
8
|
+
const power_base_1 = __importDefault(require("../modes/power-base"));
|
|
9
9
|
const config = {
|
|
10
10
|
name: "ERG",
|
|
11
11
|
description: "Calculates speed based on power and slope. Power is either set by workout or calculated based on gear and cadence",
|
|
@@ -14,15 +14,12 @@ const config = {
|
|
|
14
14
|
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
|
|
15
15
|
]
|
|
16
16
|
};
|
|
17
|
-
class ERGCyclingMode extends
|
|
17
|
+
class ERGCyclingMode extends power_base_1.default {
|
|
18
18
|
constructor(adapter, props) {
|
|
19
19
|
super(adapter, props);
|
|
20
|
-
this.prevUpdateTS = 0;
|
|
21
20
|
this.hasBikeUpdate = false;
|
|
22
21
|
this.event = {};
|
|
23
|
-
this.
|
|
24
|
-
this.data = {};
|
|
25
|
-
this.logger.logEvent({ message: 'constructor', props });
|
|
22
|
+
this.initLogger('ERGMode');
|
|
26
23
|
}
|
|
27
24
|
getName() {
|
|
28
25
|
return config.name;
|
|
@@ -132,7 +129,6 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
132
129
|
const prevRequest = this.prevRequest || {};
|
|
133
130
|
const data = this.data || {};
|
|
134
131
|
const bikeType = this.getSetting('bikeType').toLowerCase();
|
|
135
|
-
console.log('~~~ bikeType', bikeType);
|
|
136
132
|
delete this.event.gearUpdated;
|
|
137
133
|
delete this.event.rpmUpdated;
|
|
138
134
|
if (prevData === {} || prevData.speed === undefined || prevData.speed === 0) {
|
|
@@ -140,32 +136,25 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
140
136
|
this.event.tsStart = Date.now();
|
|
141
137
|
}
|
|
142
138
|
try {
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
const rpm = bikeData.pedalRpm || 0;
|
|
140
|
+
const gear = bikeData.gear || 0;
|
|
145
141
|
let power = bikeData.power || 0;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let distanceInternal = prevData.distanceInternal || 0;
|
|
150
|
-
let ts = Date.now();
|
|
151
|
-
let duration = this.prevUpdateTS === 0 ? 0 : ((ts - this.prevUpdateTS) / 1000);
|
|
152
|
-
if (rpm === 0 || bikeData.isPedalling === false) {
|
|
153
|
-
speed = 0;
|
|
142
|
+
const slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
|
|
143
|
+
const distanceInternal = prevData.distanceInternal || 0;
|
|
144
|
+
if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
|
|
154
145
|
power = 0;
|
|
155
146
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
distanceInternal += Math.round(v * duration);
|
|
160
|
-
}
|
|
147
|
+
const m = this.getWeight();
|
|
148
|
+
const t = this.getTimeSinceLastUpdate();
|
|
149
|
+
const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
161
150
|
data.speed = parseFloat(speed.toFixed(1));
|
|
162
151
|
data.power = Math.round(power);
|
|
163
|
-
data.distanceInternal = distanceInternal;
|
|
152
|
+
data.distanceInternal = Math.round(distanceInternal + distance);
|
|
164
153
|
data.slope = slope;
|
|
165
154
|
data.pedalRpm = rpm;
|
|
166
155
|
data.gear = gear;
|
|
167
|
-
if (data.time !== undefined)
|
|
168
|
-
data.time +=
|
|
156
|
+
if (data.time !== undefined && !(this.event.starting && !bikeData.pedalRpm))
|
|
157
|
+
data.time += t;
|
|
169
158
|
else
|
|
170
159
|
data.time = 0;
|
|
171
160
|
data.heartrate = bikeData.heartrate;
|
|
@@ -176,7 +165,6 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
176
165
|
if (rpm && rpm !== prevData.pedalRpm) {
|
|
177
166
|
this.event.rpmUpdated = true;
|
|
178
167
|
}
|
|
179
|
-
this.prevUpdateTS = ts;
|
|
180
168
|
}
|
|
181
169
|
catch (err) {
|
|
182
170
|
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
|
|
@@ -188,7 +176,7 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
188
176
|
calculateTargetPower(request, updateMode = true) {
|
|
189
177
|
const bikeType = this.getSetting('bikeType').toLowerCase();
|
|
190
178
|
const defaultPower = this.getSetting('startPower');
|
|
191
|
-
let m = this.
|
|
179
|
+
let m = this.getWeight();
|
|
192
180
|
const prevData = this.data || {};
|
|
193
181
|
let target;
|
|
194
182
|
if (prevData.pedalRpm && prevData.gear && (!updateMode || prevData.pedalRpm !== 0)) {
|
|
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.direction = void 0;
|
|
7
6
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
8
7
|
const CyclingMode_1 = require("../CyclingMode");
|
|
9
8
|
const calculations_1 = __importDefault(require("../calculations"));
|
|
@@ -86,7 +86,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
86
86
|
const { user } = props;
|
|
87
87
|
this.initData();
|
|
88
88
|
let startState = {};
|
|
89
|
-
return
|
|
89
|
+
return utils_1.runWithRetries(() => __awaiter(this, void 0, void 0, function* () {
|
|
90
90
|
try {
|
|
91
91
|
if (!this.bike.isConnected())
|
|
92
92
|
yield this.bike.saveConnect();
|
|
@@ -109,7 +109,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
109
109
|
startState.startProg = true;
|
|
110
110
|
}
|
|
111
111
|
if (!startState.setGear) {
|
|
112
|
-
yield this.bike.setGear(this.
|
|
112
|
+
yield this.bike.setGear(this.cyclingData.gear || (opts.gear || 10));
|
|
113
113
|
startState.setGear = true;
|
|
114
114
|
}
|
|
115
115
|
const startRequest = this.getCyclingMode().getBikeInitRequest();
|