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.
Files changed (50) hide show
  1. package/lib/CyclingMode.js +0 -1
  2. package/lib/Device.js +0 -1
  3. package/lib/DeviceProtocol.d.ts +1 -0
  4. package/lib/DeviceProtocol.js +1 -1
  5. package/lib/DeviceSupport.js +8 -21
  6. package/lib/ant/AntAdapter.js +0 -1
  7. package/lib/ant/AntScanner.js +10 -21
  8. package/lib/ant/antfe/AntFEAdapter.js +7 -7
  9. package/lib/ant/anthrm/AntHrmAdapter.js +1 -1
  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 +259 -0
  14. package/lib/ant/utils.js +1 -3
  15. package/lib/calculations.js +2 -4
  16. package/lib/daum/DaumAdapter.d.ts +2 -2
  17. package/lib/daum/DaumAdapter.js +31 -39
  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 +0 -1
  23. package/lib/daum/classic/DaumClassicAdapter.js +2 -2
  24. package/lib/daum/classic/DaumClassicProtocol.js +7 -19
  25. package/lib/daum/classic/bike.js +26 -26
  26. package/lib/daum/classic/utils.js +0 -1
  27. package/lib/daum/constants.js +0 -1
  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 +7 -19
  32. package/lib/daum/premium/bike.js +17 -18
  33. package/lib/daum/premium/utils.js +0 -1
  34. package/lib/kettler/comms.js +1 -2
  35. package/lib/kettler/ergo-racer/adapter.js +10 -22
  36. package/lib/kettler/ergo-racer/modes/power-meter.d.ts +2 -2
  37. package/lib/kettler/ergo-racer/modes/power-meter.js +12 -4
  38. package/lib/kettler/ergo-racer/protocol.js +7 -19
  39. package/lib/modes/power-base.d.ts +20 -0
  40. package/lib/modes/power-base.js +60 -0
  41. package/lib/modes/power-meter.d.ts +20 -0
  42. package/lib/modes/power-meter.js +70 -0
  43. package/lib/modes/simulator.d.ts +27 -0
  44. package/lib/modes/simulator.js +118 -0
  45. package/lib/simulator/Simulator.js +10 -23
  46. package/lib/simulator/simulator-mode.js +4 -4
  47. package/lib/types/route.js +0 -1
  48. package/lib/types/user.js +0 -1
  49. package/lib/utils.js +1 -3
  50. 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 = void 0;
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;
@@ -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 + 2 * k;
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 + 2 * k) * Math.pow(v, 3.0) + (sl + _cRR) * m * g * v;
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
- 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,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 PowerMeterCyclingMode_1 = __importDefault(require("./PowerMeterCyclingMode"));
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.daumRunData = {
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, PowerMeterCyclingMode_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.daumRunData = {
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.daumRunData, bikeData);
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.daumRunData = this.getCyclingMode().updateData(data);
295
+ this.cyclingData = this.getCyclingMode().updateData(data);
296
+ return this.cyclingData;
305
297
  }
306
298
  transformData() {
307
- if (this.daumRunData === undefined)
299
+ if (this.cyclingData === undefined)
308
300
  return;
309
301
  let distance = 0;
310
- if (this.distanceInternal !== undefined && this.daumRunData.distanceInternal !== undefined) {
311
- distance = (0, utils_1.intVal)(this.daumRunData.distanceInternal - this.distanceInternal);
302
+ if (this.distanceInternal !== undefined && this.cyclingData.distanceInternal !== undefined) {
303
+ distance = utils_1.intVal(this.cyclingData.distanceInternal - this.distanceInternal);
312
304
  }
313
- if (this.daumRunData.distanceInternal !== undefined)
314
- this.distanceInternal = this.daumRunData.distanceInternal;
305
+ if (this.cyclingData.distanceInternal !== undefined)
306
+ this.distanceInternal = this.cyclingData.distanceInternal;
315
307
  let data = {
316
- speed: (0, utils_1.floatVal)(this.daumRunData.speed),
317
- slope: (0, utils_1.floatVal)(this.daumRunData.slope),
318
- power: (0, utils_1.intVal)(this.daumRunData.power),
319
- cadence: (0, utils_1.intVal)(this.daumRunData.pedalRpm),
320
- heartrate: (0, utils_1.intVal)(this.daumRunData.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.daumRunData.time,
324
- deviceDistanceCounter: this.daumRunData.distanceInternal
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.daumRunData.isPedalling || this.daumRunData.pedalRpm === 0)
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.daumRunData.slope = request.slope;
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 { 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,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 (0, utils_1.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
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.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();