incyclist-devices 1.4.23 → 1.4.26
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 +1 -0
- package/lib/Device.js +1 -0
- package/lib/DeviceProtocol.d.ts +1 -0
- package/lib/DeviceProtocol.js +2 -0
- package/lib/DeviceSupport.js +21 -8
- package/lib/ant/AntAdapter.js +1 -0
- package/lib/ant/AntScanner.js +30 -13
- package/lib/ant/antfe/AntFEAdapter.js +7 -26
- package/lib/ant/anthrm/AntHrmAdapter.js +1 -12
- 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 +248 -0
- package/lib/ant/utils.js +3 -1
- package/lib/calculations.js +3 -3
- package/lib/daum/DaumAdapter.d.ts +2 -2
- package/lib/daum/DaumAdapter.js +43 -27
- 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 +1 -0
- package/lib/daum/classic/DaumClassicAdapter.js +2 -2
- package/lib/daum/classic/DaumClassicProtocol.js +19 -7
- package/lib/daum/classic/bike.js +26 -26
- package/lib/daum/classic/utils.js +1 -0
- package/lib/daum/constants.js +1 -0
- 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 +19 -7
- package/lib/daum/premium/bike.js +18 -17
- package/lib/daum/premium/tcpserial.js +0 -1
- package/lib/daum/premium/utils.js +1 -0
- package/lib/kettler/comms.js +2 -1
- package/lib/kettler/ergo-racer/adapter.js +22 -10
- 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 +19 -7
- package/lib/modes/power-base.d.ts +20 -0
- package/lib/modes/power-base.js +70 -0
- package/lib/modes/power-meter.d.ts +20 -0
- package/lib/modes/power-meter.js +71 -0
- package/lib/modes/simulator.d.ts +27 -0
- package/lib/modes/simulator.js +118 -0
- package/lib/simulator/Simulator.js +23 -10
- package/lib/types/route.js +1 -0
- package/lib/types/user.js +1 -0
- package/lib/utils.js +3 -1
- package/package.json +2 -1
|
@@ -0,0 +1,248 @@
|
|
|
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 `${(0, 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
|
+
}));
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
exports.default = AntFEAdapter;
|
package/lib/ant/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getBrand =
|
|
3
|
+
exports.getBrand = void 0;
|
|
4
|
+
const getBrand = (manId) => {
|
|
4
5
|
if (manId === undefined)
|
|
5
6
|
return "ANT+";
|
|
6
7
|
switch (manId) {
|
|
@@ -19,3 +20,4 @@ exports.getBrand = (manId) => {
|
|
|
19
20
|
return "ANT+";
|
|
20
21
|
}
|
|
21
22
|
};
|
|
23
|
+
exports.getBrand = getBrand;
|
package/lib/calculations.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.solveCubic = exports.IllegalArgumentException = void 0;
|
|
3
4
|
const g = 9.80665;
|
|
4
5
|
const rho = 1.2041;
|
|
5
6
|
const cwABike = {
|
|
@@ -7,7 +8,6 @@ const cwABike = {
|
|
|
7
8
|
triathlon: 0.29,
|
|
8
9
|
mountain: 0.57
|
|
9
10
|
};
|
|
10
|
-
const k = 0.01090;
|
|
11
11
|
const cRR = 0.0036;
|
|
12
12
|
class IllegalArgumentException extends Error {
|
|
13
13
|
constructor(message) {
|
|
@@ -28,7 +28,7 @@ class C {
|
|
|
28
28
|
const _cRR = props.cRR || cRR;
|
|
29
29
|
const _cwA = props.cwA || cwABike[props.bikeType || 'race'] || cwABike.race;
|
|
30
30
|
let sl = Math.atan(slope / 100);
|
|
31
|
-
let c1 = 0.5 * _rho * _cwA
|
|
31
|
+
let c1 = 0.5 * _rho * _cwA;
|
|
32
32
|
let c2 = (sl + _cRR) * m * g;
|
|
33
33
|
let p = c2 / c1;
|
|
34
34
|
let q = -1.0 * power / c1;
|
|
@@ -70,7 +70,7 @@ class C {
|
|
|
70
70
|
let _cRR = props.cRR || cRR;
|
|
71
71
|
let _cwA = props.cwA || cwABike[props.bikeType || 'race'] || cwABike.race;
|
|
72
72
|
let sl = Math.sin(Math.atan(slope / 100));
|
|
73
|
-
let P = (0.5 * _rho * _cwA
|
|
73
|
+
let P = (0.5 * _rho * _cwA) * Math.pow(v, 3.0) + (sl + _cRR) * m * g * v;
|
|
74
74
|
return P;
|
|
75
75
|
}
|
|
76
76
|
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,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) {
|
|
@@ -8,13 +27,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
27
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
28
|
});
|
|
10
29
|
};
|
|
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
|
-
};
|
|
18
30
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
19
31
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
20
32
|
};
|
|
@@ -22,7 +34,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
22
34
|
const Device_1 = __importStar(require("../Device"));
|
|
23
35
|
const ERGCyclingMode_1 = __importDefault(require("./ERGCyclingMode"));
|
|
24
36
|
const SmartTrainerCyclingMode_1 = __importDefault(require("./SmartTrainerCyclingMode"));
|
|
25
|
-
const
|
|
37
|
+
const DaumPowerMeterCyclingMode_1 = __importDefault(require("./DaumPowerMeterCyclingMode"));
|
|
26
38
|
const utils_1 = require("../utils");
|
|
27
39
|
class DaumAdapterBase extends Device_1.default {
|
|
28
40
|
constructor(props, bike) {
|
|
@@ -34,7 +46,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
34
46
|
this.bike = bike;
|
|
35
47
|
this.stopped = false;
|
|
36
48
|
this.paused = false;
|
|
37
|
-
this.
|
|
49
|
+
this.cyclingData = {
|
|
38
50
|
isPedalling: false,
|
|
39
51
|
time: 0,
|
|
40
52
|
power: 0,
|
|
@@ -67,7 +79,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
67
79
|
this.cyclingMode.setSettings(settings);
|
|
68
80
|
}
|
|
69
81
|
getSupportedCyclingModes() {
|
|
70
|
-
return [ERGCyclingMode_1.default, SmartTrainerCyclingMode_1.default,
|
|
82
|
+
return [ERGCyclingMode_1.default, SmartTrainerCyclingMode_1.default, DaumPowerMeterCyclingMode_1.default];
|
|
71
83
|
}
|
|
72
84
|
getCyclingMode() {
|
|
73
85
|
if (!this.cyclingMode)
|
|
@@ -128,7 +140,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
128
140
|
this.distanceInternal = undefined;
|
|
129
141
|
this.paused = false;
|
|
130
142
|
this.stopped = false;
|
|
131
|
-
this.
|
|
143
|
+
this.cyclingData = {
|
|
132
144
|
isPedalling: false,
|
|
133
145
|
time: 0,
|
|
134
146
|
power: 0,
|
|
@@ -229,12 +241,15 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
229
241
|
this.updateBusy = true;
|
|
230
242
|
this.getCurrentBikeData()
|
|
231
243
|
.then(bikeData => {
|
|
232
|
-
this.updateData(this.
|
|
244
|
+
this.updateData(this.cyclingData, bikeData);
|
|
233
245
|
this.transformData();
|
|
234
246
|
this.updateBusy = false;
|
|
235
247
|
})
|
|
236
248
|
.catch(err => {
|
|
237
249
|
this.logEvent({ message: 'bike update error', error: err.message, stack: err.stack });
|
|
250
|
+
const { isPedalling, power, pedalRpm, speed, distanceInternal, heartrate, slope } = this.cyclingData;
|
|
251
|
+
this.updateData(this.cyclingData, { isPedalling, power, pedalRpm, speed, distanceInternal, heartrate, slope });
|
|
252
|
+
this.transformData();
|
|
238
253
|
this.updateBusy = false;
|
|
239
254
|
});
|
|
240
255
|
});
|
|
@@ -289,27 +304,28 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
289
304
|
data.time = bikeData.time;
|
|
290
305
|
if (bikeData.slope)
|
|
291
306
|
data.slope = bikeData.slope;
|
|
292
|
-
this.
|
|
307
|
+
this.cyclingData = this.getCyclingMode().updateData(data);
|
|
308
|
+
return this.cyclingData;
|
|
293
309
|
}
|
|
294
310
|
transformData() {
|
|
295
|
-
if (this.
|
|
311
|
+
if (this.cyclingData === undefined)
|
|
296
312
|
return;
|
|
297
313
|
let distance = 0;
|
|
298
|
-
if (this.distanceInternal !== undefined && this.
|
|
299
|
-
distance = utils_1.intVal(this.
|
|
314
|
+
if (this.distanceInternal !== undefined && this.cyclingData.distanceInternal !== undefined) {
|
|
315
|
+
distance = (0, utils_1.intVal)(this.cyclingData.distanceInternal - this.distanceInternal);
|
|
300
316
|
}
|
|
301
|
-
if (this.
|
|
302
|
-
this.distanceInternal = this.
|
|
317
|
+
if (this.cyclingData.distanceInternal !== undefined)
|
|
318
|
+
this.distanceInternal = this.cyclingData.distanceInternal;
|
|
303
319
|
let data = {
|
|
304
|
-
speed: utils_1.floatVal(this.
|
|
305
|
-
slope: utils_1.floatVal(this.
|
|
306
|
-
power: utils_1.intVal(this.
|
|
307
|
-
cadence: utils_1.intVal(this.
|
|
308
|
-
heartrate: utils_1.intVal(this.
|
|
320
|
+
speed: (0, utils_1.floatVal)(this.cyclingData.speed),
|
|
321
|
+
slope: (0, utils_1.floatVal)(this.cyclingData.slope),
|
|
322
|
+
power: (0, utils_1.intVal)(this.cyclingData.power),
|
|
323
|
+
cadence: (0, utils_1.intVal)(this.cyclingData.pedalRpm),
|
|
324
|
+
heartrate: (0, utils_1.intVal)(this.cyclingData.heartrate),
|
|
309
325
|
distance,
|
|
310
326
|
timestamp: Date.now(),
|
|
311
|
-
deviceTime: this.
|
|
312
|
-
deviceDistanceCounter: this.
|
|
327
|
+
deviceTime: this.cyclingData.time,
|
|
328
|
+
deviceDistanceCounter: this.cyclingData.distanceInternal
|
|
313
329
|
};
|
|
314
330
|
if (this.ignoreHrm)
|
|
315
331
|
delete data.heartrate;
|
|
@@ -350,7 +366,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
350
366
|
});
|
|
351
367
|
}
|
|
352
368
|
refreshRequests() {
|
|
353
|
-
if (!this.
|
|
369
|
+
if (!this.cyclingData.isPedalling || this.cyclingData.pedalRpm === 0)
|
|
354
370
|
return;
|
|
355
371
|
let bikeRequest = this.getCyclingMode().sendBikeUpdate({ refresh: true }) || {};
|
|
356
372
|
const prev = this.requests[this.requests.length - 1] || {};
|
|
@@ -361,7 +377,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
361
377
|
}
|
|
362
378
|
processClientRequest(request) {
|
|
363
379
|
if (request.slope !== undefined) {
|
|
364
|
-
this.
|
|
380
|
+
this.cyclingData.slope = request.slope;
|
|
365
381
|
}
|
|
366
382
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
367
383
|
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,6 +3,7 @@ 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;
|
|
6
7
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
8
|
const CyclingMode_1 = require("../CyclingMode");
|
|
8
9
|
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 utils_1.runWithRetries(() => __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
return (0, 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();
|