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.
Files changed (50) hide show
  1. package/lib/CyclingMode.js +1 -0
  2. package/lib/Device.js +1 -0
  3. package/lib/DeviceProtocol.d.ts +1 -0
  4. package/lib/DeviceProtocol.js +2 -0
  5. package/lib/DeviceSupport.js +21 -8
  6. package/lib/ant/AntAdapter.js +1 -0
  7. package/lib/ant/AntScanner.js +30 -13
  8. package/lib/ant/antfe/AntFEAdapter.js +7 -26
  9. package/lib/ant/anthrm/AntHrmAdapter.js +1 -12
  10. package/lib/ant/antpwr/AntPWRAdapter.d.ts +24 -0
  11. package/lib/ant/antpwr/AntPWRAdapter.js +252 -0
  12. package/lib/ant/antpwr/pwr-adapter.d.ts +48 -0
  13. package/lib/ant/antpwr/pwr-adapter.js +248 -0
  14. package/lib/ant/utils.js +3 -1
  15. package/lib/calculations.js +3 -3
  16. package/lib/daum/DaumAdapter.d.ts +2 -2
  17. package/lib/daum/DaumAdapter.js +43 -27
  18. package/lib/daum/DaumPowerMeterCyclingMode.d.ts +8 -0
  19. package/lib/daum/DaumPowerMeterCyclingMode.js +21 -0
  20. package/lib/daum/ERGCyclingMode.d.ts +3 -6
  21. package/lib/daum/ERGCyclingMode.js +15 -27
  22. package/lib/daum/SmartTrainerCyclingMode.js +1 -0
  23. package/lib/daum/classic/DaumClassicAdapter.js +2 -2
  24. package/lib/daum/classic/DaumClassicProtocol.js +19 -7
  25. package/lib/daum/classic/bike.js +26 -26
  26. package/lib/daum/classic/utils.js +1 -0
  27. package/lib/daum/constants.js +1 -0
  28. package/lib/daum/premium/DaumClassicCyclingMode.d.ts +2 -2
  29. package/lib/daum/premium/DaumClassicCyclingMode.js +2 -2
  30. package/lib/daum/premium/DaumPremiumAdapter.js +2 -2
  31. package/lib/daum/premium/DaumPremiumProtocol.js +19 -7
  32. package/lib/daum/premium/bike.js +18 -17
  33. package/lib/daum/premium/tcpserial.js +0 -1
  34. package/lib/daum/premium/utils.js +1 -0
  35. package/lib/kettler/comms.js +2 -1
  36. package/lib/kettler/ergo-racer/adapter.js +22 -10
  37. package/lib/kettler/ergo-racer/modes/power-meter.d.ts +2 -2
  38. package/lib/kettler/ergo-racer/modes/power-meter.js +12 -4
  39. package/lib/kettler/ergo-racer/protocol.js +19 -7
  40. package/lib/modes/power-base.d.ts +20 -0
  41. package/lib/modes/power-base.js +70 -0
  42. package/lib/modes/power-meter.d.ts +20 -0
  43. package/lib/modes/power-meter.js +71 -0
  44. package/lib/modes/simulator.d.ts +27 -0
  45. package/lib/modes/simulator.js +118 -0
  46. package/lib/simulator/Simulator.js +23 -10
  47. package/lib/types/route.js +1 -0
  48. package/lib/types/user.js +1 -0
  49. package/lib/utils.js +3 -1
  50. 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 = (manId) => {
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;
@@ -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 + 2 * k;
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 + 2 * k) * Math.pow(v, 3.0) + (sl + _cRR) * m * g * v;
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
- daumRunData: IncyclistBikeData;
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): void;
59
+ updateData(prev: any, bikeData: any): IncyclistBikeData;
60
60
  transformData(): DeviceData;
61
61
  sendRequest(request: any): Promise<any>;
62
62
  refreshRequests(): void;
@@ -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 PowerMeterCyclingMode_1 = __importDefault(require("./PowerMeterCyclingMode"));
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.daumRunData = {
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, PowerMeterCyclingMode_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.daumRunData = {
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.daumRunData, bikeData);
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.daumRunData = this.getCyclingMode().updateData(data);
307
+ this.cyclingData = this.getCyclingMode().updateData(data);
308
+ return this.cyclingData;
293
309
  }
294
310
  transformData() {
295
- if (this.daumRunData === undefined)
311
+ if (this.cyclingData === undefined)
296
312
  return;
297
313
  let distance = 0;
298
- if (this.distanceInternal !== undefined && this.daumRunData.distanceInternal !== undefined) {
299
- distance = utils_1.intVal(this.daumRunData.distanceInternal - this.distanceInternal);
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.daumRunData.distanceInternal !== undefined)
302
- this.distanceInternal = this.daumRunData.distanceInternal;
317
+ if (this.cyclingData.distanceInternal !== undefined)
318
+ this.distanceInternal = this.cyclingData.distanceInternal;
303
319
  let data = {
304
- speed: utils_1.floatVal(this.daumRunData.speed),
305
- slope: utils_1.floatVal(this.daumRunData.slope),
306
- power: utils_1.intVal(this.daumRunData.power),
307
- cadence: utils_1.intVal(this.daumRunData.pedalRpm),
308
- heartrate: utils_1.intVal(this.daumRunData.heartrate),
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.daumRunData.time,
312
- deviceDistanceCounter: this.daumRunData.distanceInternal
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.daumRunData.isPedalling || this.daumRunData.pedalRpm === 0)
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.daumRunData.slope = request.slope;
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 { EventLogger } from "gd-eventlog";
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 CyclingModeBase implements CyclingMode {
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 CyclingMode_1.CyclingModeBase {
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.logger = adapter.logger || new gd_eventlog_1.EventLogger('ERGMode');
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
- let rpm = bikeData.pedalRpm || 0;
144
- let gear = bikeData.gear || 0;
139
+ const rpm = bikeData.pedalRpm || 0;
140
+ const gear = bikeData.gear || 0;
145
141
  let power = bikeData.power || 0;
146
- let slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
147
- let speed;
148
- let m = this.adapter.getWeight();
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
- else {
157
- speed = calculations_1.default.calculateSpeed(m, power, slope, { bikeType });
158
- let v = speed / 3.6;
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 += duration;
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.adapter.getWeight();
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.daumRunData.gear || (opts.gear || 10));
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();