incyclist-devices 2.0.37 → 2.1.0
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/antv2/adapter-factory.d.ts +4 -2
- package/lib/antv2/adapter.d.ts +3 -20
- package/lib/antv2/adapter.js +7 -93
- package/lib/antv2/fe/adapter.d.ts +9 -5
- package/lib/antv2/fe/adapter.js +25 -14
- package/lib/antv2/hr/adapter.d.ts +2 -1
- package/lib/antv2/pwr/adapter.d.ts +9 -5
- package/lib/antv2/pwr/adapter.js +19 -8
- package/lib/antv2/types.d.ts +2 -1
- package/lib/base/adpater.d.ts +31 -13
- package/lib/base/adpater.js +84 -28
- package/lib/ble/adapter-factory.d.ts +10 -9
- package/lib/ble/base/adapter.d.ts +9 -20
- package/lib/ble/base/adapter.js +15 -72
- package/lib/ble/ble-interface.d.ts +5 -4
- package/lib/ble/cp/adapter.d.ts +5 -8
- package/lib/ble/cp/adapter.js +26 -10
- package/lib/ble/elite/adapter.d.ts +6 -5
- package/lib/ble/elite/adapter.js +26 -2
- package/lib/ble/fm/adapter.d.ts +10 -9
- package/lib/ble/fm/adapter.js +38 -11
- package/lib/ble/hr/adapter.d.ts +5 -3
- package/lib/ble/peripheral-cache.d.ts +3 -2
- package/lib/ble/tacx/adapter.d.ts +2 -2
- package/lib/ble/wahoo/adapter.d.ts +2 -2
- package/lib/index.d.ts +5 -5
- package/lib/index.js +4 -2
- package/lib/interfaces.d.ts +1 -1
- package/lib/modes/ant-fe-adv-st-mode.d.ts +12 -0
- package/lib/modes/ant-fe-adv-st-mode.js +83 -0
- package/lib/modes/antble-erg.d.ts +31 -0
- package/lib/modes/antble-erg.js +28 -0
- package/lib/modes/antble-smarttrainer.d.ts +23 -0
- package/lib/modes/antble-smarttrainer.js +65 -0
- package/lib/modes/base.d.ts +29 -0
- package/lib/modes/{cycling-mode.js → base.js} +23 -26
- package/lib/modes/daum-classic-standard.d.ts +16 -0
- package/lib/modes/daum-classic-standard.js +54 -0
- package/lib/modes/daum-erg.d.ts +49 -0
- package/lib/{serial/daum/ERGCyclingMode.js → modes/daum-erg.js} +45 -73
- package/lib/modes/daum-power.d.ts +5 -0
- package/lib/{serial/daum/DaumPowerMeterCyclingMode.js → modes/daum-power.js} +1 -10
- package/lib/modes/daum-premium-standard.d.ts +23 -0
- package/lib/{serial/daum/premium/modes/daum-classic.js → modes/daum-premium-standard.js} +26 -38
- package/lib/modes/daum-smarttrainer.d.ts +82 -0
- package/lib/{serial/daum/SmartTrainerCyclingMode.js → modes/daum-smarttrainer.js} +23 -26
- package/lib/modes/kettler-erg.d.ts +44 -0
- package/lib/{serial/kettler/ergo-racer/modes/erg.js → modes/kettler-erg.js} +12 -23
- package/lib/modes/power-base.d.ts +28 -3
- package/lib/modes/power-base.js +182 -5
- package/lib/modes/power-meter.d.ts +10 -16
- package/lib/modes/power-meter.js +15 -54
- package/lib/modes/simulator.d.ts +37 -10
- package/lib/modes/simulator.js +14 -46
- package/lib/modes/{cycling-mode.d.ts → types.d.ts} +22 -19
- package/lib/modes/types.js +56 -0
- package/lib/serial/adapter-factory.d.ts +7 -5
- package/lib/serial/adapter.d.ts +2 -2
- package/lib/serial/adapter.js +5 -2
- package/lib/serial/daum/DaumAdapter.d.ts +27 -24
- package/lib/serial/daum/DaumAdapter.js +200 -128
- package/lib/serial/daum/classic/adapter.d.ts +20 -21
- package/lib/serial/daum/classic/adapter.js +83 -157
- package/lib/serial/daum/classic/comms.d.ts +19 -13
- package/lib/serial/daum/classic/comms.js +39 -12
- package/lib/serial/daum/classic/mock.d.ts +4 -0
- package/lib/serial/daum/classic/mock.js +14 -4
- package/lib/serial/daum/premium/adapter.d.ts +16 -11
- package/lib/serial/daum/premium/adapter.js +98 -95
- package/lib/serial/daum/premium/comms.d.ts +4 -1
- package/lib/serial/daum/premium/comms.js +25 -17
- package/lib/serial/daum/premium/mock.d.ts +4 -0
- package/lib/serial/daum/premium/mock.js +15 -5
- package/lib/serial/daum/types.d.ts +11 -0
- package/lib/serial/daum/types.js +5 -0
- package/lib/serial/kettler/ergo-racer/adapter.d.ts +10 -8
- package/lib/serial/kettler/ergo-racer/adapter.js +17 -7
- package/lib/serial/serial-interface.js +1 -2
- package/lib/simulator/Simulator.d.ts +14 -17
- package/lib/simulator/Simulator.js +18 -47
- package/lib/types/adapter.d.ts +29 -8
- package/lib/types/adapter.js +68 -0
- package/lib/utils/utils.d.ts +1 -1
- package/package.json +3 -3
- package/lib/antv2/modes/ant-fe-adv-st-mode.d.ts +0 -9
- package/lib/antv2/modes/ant-fe-adv-st-mode.js +0 -51
- package/lib/antv2/modes/ant-fe-erg-mode.d.ts +0 -6
- package/lib/antv2/modes/ant-fe-erg-mode.js +0 -14
- package/lib/antv2/modes/ant-fe-st-mode.d.ts +0 -5
- package/lib/antv2/modes/ant-fe-st-mode.js +0 -13
- package/lib/modes/ble-erg-mode.d.ts +0 -18
- package/lib/modes/ble-erg-mode.js +0 -148
- package/lib/modes/ble-st-mode.d.ts +0 -15
- package/lib/modes/ble-st-mode.js +0 -96
- package/lib/serial/daum/DaumPowerMeterCyclingMode.d.ts +0 -8
- package/lib/serial/daum/ERGCyclingMode.d.ts +0 -26
- package/lib/serial/daum/SmartTrainerCyclingMode.d.ts +0 -42
- package/lib/serial/daum/classic/modes/daum-classic.d.ts +0 -13
- package/lib/serial/daum/classic/modes/daum-classic.js +0 -97
- package/lib/serial/daum/premium/modes/daum-classic.d.ts +0 -14
- package/lib/serial/kettler/ergo-racer/modes/erg.d.ts +0 -25
- /package/lib/serial/daum/{constants.d.ts → consts.d.ts} +0 -0
- /package/lib/serial/daum/{constants.js → consts.js} +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import ICyclingMode, { CyclingModeProperyType, IncyclistBikeData, UpdateRequest } from "./types";
|
|
2
|
+
import PowerBasedCyclingModeBase from "./power-base";
|
|
3
|
+
import { IncyclistDeviceAdapter } from "../types/adapter";
|
|
4
|
+
export type ERGEvent = {
|
|
5
|
+
rpmUpdated?: boolean;
|
|
6
|
+
gearUpdated?: boolean;
|
|
7
|
+
starting?: boolean;
|
|
8
|
+
tsStart?: number;
|
|
9
|
+
};
|
|
10
|
+
export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements ICyclingMode {
|
|
11
|
+
prevRequest: UpdateRequest;
|
|
12
|
+
hasBikeUpdate: boolean;
|
|
13
|
+
chain: number[];
|
|
14
|
+
cassette: number[];
|
|
15
|
+
event: ERGEvent;
|
|
16
|
+
protected static config: {
|
|
17
|
+
isERG: boolean;
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
properties: ({
|
|
21
|
+
key: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
type: CyclingModeProperyType;
|
|
25
|
+
options: string[];
|
|
26
|
+
default: string;
|
|
27
|
+
min?: undefined;
|
|
28
|
+
max?: undefined;
|
|
29
|
+
} | {
|
|
30
|
+
key: string;
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
type: CyclingModeProperyType;
|
|
34
|
+
default: number;
|
|
35
|
+
min: number;
|
|
36
|
+
max: number;
|
|
37
|
+
options?: undefined;
|
|
38
|
+
})[];
|
|
39
|
+
};
|
|
40
|
+
constructor(adapter: IncyclistDeviceAdapter, props?: any);
|
|
41
|
+
getBikeInitRequest(): UpdateRequest;
|
|
42
|
+
sendBikeUpdate(request: UpdateRequest): UpdateRequest;
|
|
43
|
+
copyBikeData(data: IncyclistBikeData, bikeData: IncyclistBikeData): IncyclistBikeData;
|
|
44
|
+
updateData(bikeData: IncyclistBikeData): IncyclistBikeData;
|
|
45
|
+
private checkForEvents;
|
|
46
|
+
private cleanupPrevEvents;
|
|
47
|
+
private checkIsStarting;
|
|
48
|
+
calculateTargetPower(request: any, updateMode?: boolean): any;
|
|
49
|
+
}
|
|
@@ -3,18 +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
|
|
7
|
-
const calculations_1 = __importDefault(require("
|
|
8
|
-
const power_base_1 = __importDefault(require("
|
|
9
|
-
const MIN_SPEED = 10;
|
|
10
|
-
const config = {
|
|
11
|
-
name: "ERG",
|
|
12
|
-
description: "Calculates speed based on power and slope. Power is either set by workout or calculated based on gear and cadence",
|
|
13
|
-
properties: [
|
|
14
|
-
{ key: 'bikeType', name: 'Bike Type', description: '', type: cycling_mode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
15
|
-
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: cycling_mode_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
|
|
16
|
-
]
|
|
17
|
-
};
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
const calculations_1 = __importDefault(require("../utils/calculations"));
|
|
8
|
+
const power_base_1 = __importDefault(require("./power-base"));
|
|
18
9
|
class ERGCyclingMode extends power_base_1.default {
|
|
19
10
|
constructor(adapter, props) {
|
|
20
11
|
super(adapter, props);
|
|
@@ -22,18 +13,6 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
22
13
|
this.event = {};
|
|
23
14
|
this.initLogger('ERGMode');
|
|
24
15
|
}
|
|
25
|
-
getName() {
|
|
26
|
-
return config.name;
|
|
27
|
-
}
|
|
28
|
-
getDescription() {
|
|
29
|
-
return config.description;
|
|
30
|
-
}
|
|
31
|
-
getProperties() {
|
|
32
|
-
return config.properties;
|
|
33
|
-
}
|
|
34
|
-
getProperty(name) {
|
|
35
|
-
return config.properties.find(p => p.name === name);
|
|
36
|
-
}
|
|
37
16
|
getBikeInitRequest() {
|
|
38
17
|
const startPower = this.getSetting('startPower');
|
|
39
18
|
return { targetPower: startPower, init: true };
|
|
@@ -133,61 +112,46 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
133
112
|
this.event.rpmUpdated = false;
|
|
134
113
|
return newRequest;
|
|
135
114
|
}
|
|
115
|
+
copyBikeData(data, bikeData) {
|
|
116
|
+
const newData = super.copyBikeData(data, bikeData);
|
|
117
|
+
if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
|
|
118
|
+
newData.power = 0;
|
|
119
|
+
}
|
|
120
|
+
if (newData.gear === undefined)
|
|
121
|
+
newData.gear = 0;
|
|
122
|
+
return newData;
|
|
123
|
+
}
|
|
136
124
|
updateData(bikeData) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
125
|
+
try {
|
|
126
|
+
const prevData = JSON.parse(JSON.stringify(this.getData()));
|
|
127
|
+
this.cleanupPrevEvents();
|
|
128
|
+
this.checkIsStarting(prevData);
|
|
129
|
+
const data = super.updateData(bikeData);
|
|
130
|
+
this.checkForEvents(bikeData, prevData);
|
|
131
|
+
return data;
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message, stack: err.stack });
|
|
135
|
+
return this.getData();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
checkForEvents(bikeData, prevData) {
|
|
139
|
+
if (bikeData.gear !== prevData.gear) {
|
|
140
|
+
this.event.gearUpdated = true;
|
|
141
|
+
}
|
|
142
|
+
if (bikeData.pedalRpm && bikeData.pedalRpm !== prevData.pedalRpm) {
|
|
143
|
+
this.event.rpmUpdated = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
cleanupPrevEvents() {
|
|
142
147
|
delete this.event.gearUpdated;
|
|
143
148
|
delete this.event.rpmUpdated;
|
|
149
|
+
}
|
|
150
|
+
checkIsStarting(prevData) {
|
|
144
151
|
if (Object.keys(prevData).length === 0 || prevData.speed === undefined || prevData.speed === 0) {
|
|
145
152
|
this.event.starting = true;
|
|
146
153
|
this.event.tsStart = Date.now();
|
|
147
154
|
}
|
|
148
|
-
try {
|
|
149
|
-
const rpm = bikeData.pedalRpm || 0;
|
|
150
|
-
const gear = bikeData.gear || 0;
|
|
151
|
-
let power = bikeData.power || 0;
|
|
152
|
-
const slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
|
|
153
|
-
const distanceInternal = prevData.distanceInternal || 0;
|
|
154
|
-
if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
|
|
155
|
-
power = 0;
|
|
156
|
-
}
|
|
157
|
-
const m = this.getWeight();
|
|
158
|
-
const t = this.getTimeSinceLastUpdate();
|
|
159
|
-
const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
160
|
-
if (power === 0 && speed < MIN_SPEED) {
|
|
161
|
-
data.speed = Math.round(prevData.speed - 1) < 0 ? 0 : Math.round(prevData.speed - 1);
|
|
162
|
-
data.distanceInternal = distanceInternal + data.speed / 3.6 * t;
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
data.speed = speed;
|
|
166
|
-
data.distanceInternal = distanceInternal + distance;
|
|
167
|
-
}
|
|
168
|
-
data.power = Math.round(power);
|
|
169
|
-
data.slope = slope;
|
|
170
|
-
data.pedalRpm = rpm;
|
|
171
|
-
data.gear = gear;
|
|
172
|
-
if (data.time !== undefined && !(this.event.starting && !bikeData.pedalRpm))
|
|
173
|
-
data.time += t;
|
|
174
|
-
else
|
|
175
|
-
data.time = 0;
|
|
176
|
-
data.heartrate = bikeData.heartrate;
|
|
177
|
-
data.isPedalling = bikeData.isPedalling;
|
|
178
|
-
if (gear !== prevData.gear) {
|
|
179
|
-
this.event.gearUpdated = true;
|
|
180
|
-
}
|
|
181
|
-
if (rpm && rpm !== prevData.pedalRpm) {
|
|
182
|
-
this.event.rpmUpdated = true;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (err) {
|
|
186
|
-
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err, stack: err.stack });
|
|
187
|
-
}
|
|
188
|
-
this.logger.logEvent({ message: "updateData result", data, bikeData, prevRequest, prevSpeed });
|
|
189
|
-
this.data = data;
|
|
190
|
-
return data;
|
|
191
155
|
}
|
|
192
156
|
calculateTargetPower(request, updateMode = true) {
|
|
193
157
|
const bikeType = this.getSetting('bikeType').toLowerCase();
|
|
@@ -206,5 +170,13 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
206
170
|
return target;
|
|
207
171
|
}
|
|
208
172
|
}
|
|
209
|
-
ERGCyclingMode.
|
|
173
|
+
ERGCyclingMode.config = {
|
|
174
|
+
isERG: true,
|
|
175
|
+
name: "ERG",
|
|
176
|
+
description: "Calculates speed based on power and slope. Power is either set by workout or calculated based on gear and cadence",
|
|
177
|
+
properties: [
|
|
178
|
+
{ key: 'bikeType', name: 'Bike Type', description: '', type: types_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
179
|
+
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: types_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
|
|
180
|
+
]
|
|
181
|
+
};
|
|
210
182
|
exports.default = ERGCyclingMode;
|
|
@@ -3,19 +3,10 @@ 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 power_meter_1 = __importDefault(require("
|
|
6
|
+
const power_meter_1 = __importDefault(require("./power-meter"));
|
|
7
7
|
class DaumPowerMeterCyclingMode extends power_meter_1.default {
|
|
8
|
-
constructor() {
|
|
9
|
-
super(...arguments);
|
|
10
|
-
this.hasBikeUpdate = false;
|
|
11
|
-
}
|
|
12
8
|
getBikeInitRequest() {
|
|
13
9
|
return { slope: 0 };
|
|
14
10
|
}
|
|
15
|
-
sendBikeUpdate(request) {
|
|
16
|
-
super.sendBikeUpdate(request);
|
|
17
|
-
this.prevRequest = {};
|
|
18
|
-
return {};
|
|
19
|
-
}
|
|
20
11
|
}
|
|
21
12
|
exports.default = DaumPowerMeterCyclingMode;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import ICyclingMode, { CyclingModeProperyType, IncyclistBikeData, Settings, UpdateRequest } from "./types";
|
|
2
|
+
import { IncyclistDeviceAdapter } from "../types/adapter";
|
|
3
|
+
import PowerMeterCyclingMode from "./power-meter";
|
|
4
|
+
export default class DaumClassicCyclingMode extends PowerMeterCyclingMode implements ICyclingMode {
|
|
5
|
+
prevInternalDistance: number;
|
|
6
|
+
distanceOffset: number;
|
|
7
|
+
protected static config: {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
properties: {
|
|
11
|
+
key: string;
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
type: CyclingModeProperyType;
|
|
15
|
+
options: string[];
|
|
16
|
+
default: string;
|
|
17
|
+
}[];
|
|
18
|
+
};
|
|
19
|
+
constructor(adapter: IncyclistDeviceAdapter, props?: Settings);
|
|
20
|
+
getBikeInitRequest(): UpdateRequest;
|
|
21
|
+
updateData(data: IncyclistBikeData): IncyclistBikeData;
|
|
22
|
+
sendBikeUpdate(request: UpdateRequest): UpdateRequest;
|
|
23
|
+
}
|
|
@@ -4,16 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
name: "Daum Classic",
|
|
11
|
-
description: "The device calculates speed and power based on slope. Incyclist will not modify any values recived from the device\nThis mode will not respect maximum power and/or workout limits",
|
|
12
|
-
properties: [
|
|
13
|
-
{ key: 'bikeType', name: 'Bike Type', description: '', type: cycling_mode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain'], default: 'Race' },
|
|
14
|
-
]
|
|
15
|
-
};
|
|
16
|
-
class DaumClassicCyclingMode extends DaumPowerMeterCyclingMode_1.default {
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
const power_meter_1 = __importDefault(require("./power-meter"));
|
|
9
|
+
class DaumClassicCyclingMode extends power_meter_1.default {
|
|
17
10
|
constructor(adapter, props) {
|
|
18
11
|
super(adapter, props);
|
|
19
12
|
this.logger = adapter ? adapter.getLogger() : undefined;
|
|
@@ -22,65 +15,60 @@ class DaumClassicCyclingMode extends DaumPowerMeterCyclingMode_1.default {
|
|
|
22
15
|
this.setModeProperty('eppSupport', true);
|
|
23
16
|
this.setModeProperty('setPersonSupport', true);
|
|
24
17
|
}
|
|
25
|
-
getName() {
|
|
26
|
-
return config.name;
|
|
27
|
-
}
|
|
28
|
-
getDescription() {
|
|
29
|
-
return config.description;
|
|
30
|
-
}
|
|
31
|
-
getProperties() {
|
|
32
|
-
return config.properties;
|
|
33
|
-
}
|
|
34
|
-
getProperty(name) {
|
|
35
|
-
return config.properties.find(p => p.name === name);
|
|
36
|
-
}
|
|
37
18
|
getBikeInitRequest() {
|
|
38
19
|
return {};
|
|
39
20
|
}
|
|
40
|
-
getSettings() {
|
|
41
|
-
const settings = super.getSettings();
|
|
42
|
-
settings['setPerson'] = true;
|
|
43
|
-
return settings;
|
|
44
|
-
}
|
|
45
|
-
getSetting(name) {
|
|
46
|
-
if (name === 'setPerson')
|
|
47
|
-
return true;
|
|
48
|
-
return super.getSetting(name);
|
|
49
|
-
}
|
|
50
21
|
updateData(data) {
|
|
51
22
|
try {
|
|
52
|
-
const prevData =
|
|
23
|
+
const prevData = Object.assign({}, this.getData());
|
|
53
24
|
const prevRequest = this.prevRequest || {};
|
|
54
25
|
const bikeData = JSON.parse(JSON.stringify(data));
|
|
55
26
|
let power = data.power || 0;
|
|
56
27
|
let speed = data.speed || 0;
|
|
57
28
|
let slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
|
|
58
29
|
let distanceBike = data.distanceInternal || 0;
|
|
59
|
-
let distancePrev =
|
|
60
|
-
let distanceInternal = distanceBike;
|
|
30
|
+
let distancePrev = this.prevInternalDistance || 0;
|
|
31
|
+
let distanceInternal = distanceBike + (this.distanceOffset || 0);
|
|
32
|
+
let time = prevData.time || 0;
|
|
61
33
|
let ts = Date.now();
|
|
34
|
+
let t = this.getTimeSinceLastUpdate();
|
|
62
35
|
if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
|
|
63
36
|
speed = 0;
|
|
64
37
|
power = 0;
|
|
65
38
|
}
|
|
66
39
|
if (distanceBike < distancePrev) {
|
|
67
|
-
this.logger.logEvent({ message: '
|
|
40
|
+
this.logger.logEvent({ message: 'distance overflow', distanceBike, distancePrev });
|
|
68
41
|
let v = speed / 3.6;
|
|
69
|
-
|
|
70
|
-
|
|
42
|
+
const calculateDistance = distancePrev + (this.distanceOffset || 0) + v * t;
|
|
43
|
+
this.distanceOffset = calculateDistance - distanceBike;
|
|
44
|
+
distanceInternal = calculateDistance;
|
|
71
45
|
}
|
|
72
46
|
data.speed = parseFloat(speed.toFixed(1));
|
|
73
47
|
data.power = Math.round(power);
|
|
74
48
|
data.distanceInternal = distanceInternal;
|
|
75
49
|
data.slope = slope;
|
|
50
|
+
data.time = speed > 0 ? time + t : time;
|
|
76
51
|
this.logger.logEvent({ message: "updateData result", data, bikeData, prevRequest: {}, prevSpeed: prevData.speed });
|
|
77
52
|
this.data = JSON.parse(JSON.stringify(data));
|
|
78
53
|
this.prevUpdateTS = ts;
|
|
54
|
+
this.prevInternalDistance = distanceBike;
|
|
79
55
|
}
|
|
80
56
|
catch (err) {
|
|
81
57
|
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
|
|
82
58
|
}
|
|
83
59
|
return data;
|
|
84
60
|
}
|
|
61
|
+
sendBikeUpdate(request) {
|
|
62
|
+
super.sendBikeUpdate(request);
|
|
63
|
+
this.prevRequest = {};
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
85
66
|
}
|
|
67
|
+
DaumClassicCyclingMode.config = {
|
|
68
|
+
name: "Daum Classic",
|
|
69
|
+
description: "The device calculates speed and power based on slope. Incyclist will not modify any values recived from the device\nThis mode will not respect maximum power and/or workout limits",
|
|
70
|
+
properties: [
|
|
71
|
+
{ key: 'bikeType', name: 'Bike Type', description: '', type: types_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain'], default: 'Race' },
|
|
72
|
+
]
|
|
73
|
+
};
|
|
86
74
|
exports.default = DaumClassicCyclingMode;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { EventLogger } from "gd-eventlog";
|
|
2
|
+
import ICyclingMode, { CyclingModeProperyType, IncyclistBikeData, Settings, UpdateRequest } from "./types";
|
|
3
|
+
import { IncyclistDeviceAdapter } from "..";
|
|
4
|
+
import { CyclingModeBase } from "./base";
|
|
5
|
+
interface STUpdateRequest extends UpdateRequest {
|
|
6
|
+
calculatedPower?: number;
|
|
7
|
+
delta?: number;
|
|
8
|
+
enforced?: boolean;
|
|
9
|
+
belowMin?: boolean;
|
|
10
|
+
aboveMax?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare enum direction {
|
|
13
|
+
up = "up",
|
|
14
|
+
down = "down"
|
|
15
|
+
}
|
|
16
|
+
interface STEvent {
|
|
17
|
+
gearUpdate?: direction;
|
|
18
|
+
rpmUpdate?: boolean;
|
|
19
|
+
targetNotReached?: number;
|
|
20
|
+
}
|
|
21
|
+
export default class SmartTrainerCyclingMode extends CyclingModeBase implements ICyclingMode {
|
|
22
|
+
logger: EventLogger;
|
|
23
|
+
data?: IncyclistBikeData;
|
|
24
|
+
prevRequest?: STUpdateRequest;
|
|
25
|
+
prevUpdateTS: number;
|
|
26
|
+
chain: number[];
|
|
27
|
+
cassette: number[];
|
|
28
|
+
event: STEvent;
|
|
29
|
+
protected static config: {
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
properties: ({
|
|
33
|
+
key: string;
|
|
34
|
+
name: string;
|
|
35
|
+
description: string;
|
|
36
|
+
type: CyclingModeProperyType;
|
|
37
|
+
options: string[];
|
|
38
|
+
default: string;
|
|
39
|
+
validation?: undefined;
|
|
40
|
+
condition?: undefined;
|
|
41
|
+
} | {
|
|
42
|
+
key: string;
|
|
43
|
+
name: string;
|
|
44
|
+
description: string;
|
|
45
|
+
type: CyclingModeProperyType;
|
|
46
|
+
default: number;
|
|
47
|
+
options?: undefined;
|
|
48
|
+
validation?: undefined;
|
|
49
|
+
condition?: undefined;
|
|
50
|
+
} | {
|
|
51
|
+
key: string;
|
|
52
|
+
name: string;
|
|
53
|
+
description: string;
|
|
54
|
+
type: CyclingModeProperyType;
|
|
55
|
+
default: boolean;
|
|
56
|
+
options?: undefined;
|
|
57
|
+
validation?: undefined;
|
|
58
|
+
condition?: undefined;
|
|
59
|
+
} | {
|
|
60
|
+
key: string;
|
|
61
|
+
name: string;
|
|
62
|
+
description: string;
|
|
63
|
+
type: CyclingModeProperyType;
|
|
64
|
+
validation: string;
|
|
65
|
+
default: string;
|
|
66
|
+
condition: (s: any) => any;
|
|
67
|
+
options?: undefined;
|
|
68
|
+
})[];
|
|
69
|
+
};
|
|
70
|
+
constructor(adapter: IncyclistDeviceAdapter, props?: Settings);
|
|
71
|
+
getData(): IncyclistBikeData;
|
|
72
|
+
getSlope(): number;
|
|
73
|
+
getWeight(): number;
|
|
74
|
+
getBikeInitRequest(): STUpdateRequest;
|
|
75
|
+
useGearSimulation(): boolean;
|
|
76
|
+
getMinMaxGears(source: string): [number, number];
|
|
77
|
+
sendBikeUpdate(request: STUpdateRequest): STUpdateRequest;
|
|
78
|
+
updateData(bikeData: IncyclistBikeData): any;
|
|
79
|
+
calculateSpeed(gear: any, rpm: any, slope: any, bikeSpeed: any, props?: any): any;
|
|
80
|
+
calculateTargetPower(request: STUpdateRequest, speed?: number): STUpdateRequest;
|
|
81
|
+
}
|
|
82
|
+
export {};
|
|
@@ -5,28 +5,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.direction = void 0;
|
|
7
7
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
8
|
-
const
|
|
9
|
-
const calculations_1 = __importDefault(require("
|
|
10
|
-
const utils_1 = require("
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
const calculations_1 = __importDefault(require("../utils/calculations"));
|
|
10
|
+
const utils_1 = require("../serial/daum/classic/utils");
|
|
11
|
+
const base_1 = require("./base");
|
|
11
12
|
const SEC_DELAY = 3;
|
|
12
|
-
const config = {
|
|
13
|
-
name: "SmartTrainer",
|
|
14
|
-
description: "Calculates power based on speed and slope.",
|
|
15
|
-
properties: [
|
|
16
|
-
{ key: 'bikeType', name: 'Bike Type', description: '', type: cycling_mode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
17
|
-
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: cycling_mode_1.CyclingModeProperyType.Integer, default: 50 },
|
|
18
|
-
{ key: 'minPower', name: 'Minimum Power', description: 'Minimum power in declines', type: cycling_mode_1.CyclingModeProperyType.Integer, default: 50 },
|
|
19
|
-
{ key: 'simulation', name: 'Simulate ', description: 'Simulate ', type: cycling_mode_1.CyclingModeProperyType.Boolean, default: false },
|
|
20
|
-
{ key: 'chainRings', name: 'Chain Rings', description: 'Simulated chain rings (format: <min>-<max>)', type: cycling_mode_1.CyclingModeProperyType.String, validation: '', default: '36-52', condition: (s) => s.simulation },
|
|
21
|
-
{ key: 'cassetteRings', name: 'Cassette', description: 'Simulated cassette (format: <min>-<max>)', type: cycling_mode_1.CyclingModeProperyType.String, validation: '', default: '11-30', condition: (s) => s.simulation },
|
|
22
|
-
]
|
|
23
|
-
};
|
|
24
13
|
var direction;
|
|
25
14
|
(function (direction) {
|
|
26
15
|
direction["up"] = "up";
|
|
27
16
|
direction["down"] = "down";
|
|
28
17
|
})(direction || (exports.direction = direction = {}));
|
|
29
|
-
class SmartTrainerCyclingMode extends
|
|
18
|
+
class SmartTrainerCyclingMode extends base_1.CyclingModeBase {
|
|
30
19
|
constructor(adapter, props) {
|
|
31
20
|
super(adapter, props);
|
|
32
21
|
this.prevUpdateTS = 0;
|
|
@@ -34,18 +23,14 @@ class SmartTrainerCyclingMode extends cycling_mode_1.CyclingModeBase {
|
|
|
34
23
|
this.logger = adapter ? adapter.getLogger() : undefined;
|
|
35
24
|
if (!this.logger)
|
|
36
25
|
this.logger = new gd_eventlog_1.EventLogger('SmartTrainer');
|
|
26
|
+
this.data = { speed: 0, power: 0, distanceInternal: 0, pedalRpm: 0, isPedalling: false, heartrate: 0 };
|
|
37
27
|
}
|
|
38
|
-
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
getDescription() {
|
|
42
|
-
return config.description;
|
|
28
|
+
getData() {
|
|
29
|
+
return this.data;
|
|
43
30
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
getProperty(name) {
|
|
48
|
-
return config.properties.find(p => p.name === name);
|
|
31
|
+
getSlope() {
|
|
32
|
+
const { slope } = this.data;
|
|
33
|
+
return slope || 0;
|
|
49
34
|
}
|
|
50
35
|
getWeight() {
|
|
51
36
|
const a = this.adapter;
|
|
@@ -347,4 +332,16 @@ class SmartTrainerCyclingMode extends cycling_mode_1.CyclingModeBase {
|
|
|
347
332
|
return request;
|
|
348
333
|
}
|
|
349
334
|
}
|
|
335
|
+
SmartTrainerCyclingMode.config = {
|
|
336
|
+
name: "SmartTrainer",
|
|
337
|
+
description: "Calculates power based on speed and slope.",
|
|
338
|
+
properties: [
|
|
339
|
+
{ key: 'bikeType', name: 'Bike Type', description: '', type: types_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
340
|
+
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: types_1.CyclingModeProperyType.Integer, default: 50 },
|
|
341
|
+
{ key: 'minPower', name: 'Minimum Power', description: 'Minimum power in declines', type: types_1.CyclingModeProperyType.Integer, default: 50 },
|
|
342
|
+
{ key: 'simulation', name: 'Simulate ', description: 'Simulate ', type: types_1.CyclingModeProperyType.Boolean, default: false },
|
|
343
|
+
{ key: 'chainRings', name: 'Chain Rings', description: 'Simulated chain rings (format: <min>-<max>)', type: types_1.CyclingModeProperyType.String, validation: '', default: '36-52', condition: (s) => s.simulation },
|
|
344
|
+
{ key: 'cassetteRings', name: 'Cassette', description: 'Simulated cassette (format: <min>-<max>)', type: types_1.CyclingModeProperyType.String, validation: '', default: '11-30', condition: (s) => s.simulation },
|
|
345
|
+
]
|
|
346
|
+
};
|
|
350
347
|
exports.default = SmartTrainerCyclingMode;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import ICyclingMode, { CyclingModeProperyType, IncyclistBikeData, UpdateRequest } from './types';
|
|
2
|
+
import PowerBasedCyclingModeBase from './power-base';
|
|
3
|
+
import { IncyclistDeviceAdapter } from '../types/adapter';
|
|
4
|
+
export type ERGEvent = {
|
|
5
|
+
rpmUpdated?: boolean;
|
|
6
|
+
gearUpdated?: boolean;
|
|
7
|
+
starting?: boolean;
|
|
8
|
+
tsStart?: number;
|
|
9
|
+
};
|
|
10
|
+
export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements ICyclingMode {
|
|
11
|
+
protected static config: {
|
|
12
|
+
isERG: boolean;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
properties: ({
|
|
16
|
+
key: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
type: CyclingModeProperyType;
|
|
20
|
+
options: string[];
|
|
21
|
+
default: string;
|
|
22
|
+
min?: undefined;
|
|
23
|
+
max?: undefined;
|
|
24
|
+
} | {
|
|
25
|
+
key: string;
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
type: CyclingModeProperyType;
|
|
29
|
+
default: number;
|
|
30
|
+
min: number;
|
|
31
|
+
max: number;
|
|
32
|
+
options?: undefined;
|
|
33
|
+
})[];
|
|
34
|
+
};
|
|
35
|
+
prevRequest: UpdateRequest;
|
|
36
|
+
hasBikeUpdate: boolean;
|
|
37
|
+
chain: number[];
|
|
38
|
+
cassette: number[];
|
|
39
|
+
event: ERGEvent;
|
|
40
|
+
constructor(adapter: IncyclistDeviceAdapter, props?: any);
|
|
41
|
+
getBikeInitRequest(): UpdateRequest;
|
|
42
|
+
sendBikeUpdate(request: UpdateRequest): UpdateRequest;
|
|
43
|
+
updateData(bikeData: IncyclistBikeData): any;
|
|
44
|
+
}
|
|
@@ -3,17 +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
|
|
7
|
-
const power_base_1 = __importDefault(require("
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
const power_base_1 = __importDefault(require("./power-base"));
|
|
8
8
|
const MIN_SPEED = 10;
|
|
9
|
-
const config = {
|
|
10
|
-
name: "ERG",
|
|
11
|
-
description: "Calculates speed based on power and slope. Power is either set by a workout",
|
|
12
|
-
properties: [
|
|
13
|
-
{ key: 'bikeType', name: 'Bike Type', description: '', type: cycling_mode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
14
|
-
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: cycling_mode_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
|
|
15
|
-
]
|
|
16
|
-
};
|
|
17
9
|
class ERGCyclingMode extends power_base_1.default {
|
|
18
10
|
constructor(adapter, props) {
|
|
19
11
|
super(adapter, props);
|
|
@@ -21,18 +13,6 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
21
13
|
this.event = {};
|
|
22
14
|
this.initLogger('ERGMode');
|
|
23
15
|
}
|
|
24
|
-
getName() {
|
|
25
|
-
return config.name;
|
|
26
|
-
}
|
|
27
|
-
getDescription() {
|
|
28
|
-
return config.description;
|
|
29
|
-
}
|
|
30
|
-
getProperties() {
|
|
31
|
-
return config.properties;
|
|
32
|
-
}
|
|
33
|
-
getProperty(name) {
|
|
34
|
-
return config.properties.find(p => p.name === name);
|
|
35
|
-
}
|
|
36
16
|
getBikeInitRequest() {
|
|
37
17
|
const startPower = this.getSetting('startPower');
|
|
38
18
|
return { targetPower: startPower };
|
|
@@ -131,6 +111,7 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
131
111
|
data.time = 0;
|
|
132
112
|
data.heartrate = bikeData.heartrate;
|
|
133
113
|
data.isPedalling = bikeData.isPedalling;
|
|
114
|
+
this.prevUpdateTS = Date.now();
|
|
134
115
|
}
|
|
135
116
|
catch (err) {
|
|
136
117
|
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
|
|
@@ -140,5 +121,13 @@ class ERGCyclingMode extends power_base_1.default {
|
|
|
140
121
|
return data;
|
|
141
122
|
}
|
|
142
123
|
}
|
|
143
|
-
ERGCyclingMode.
|
|
124
|
+
ERGCyclingMode.config = {
|
|
125
|
+
isERG: true,
|
|
126
|
+
name: "ERG",
|
|
127
|
+
description: "Calculates speed based on power and slope. Power is either set by a workout",
|
|
128
|
+
properties: [
|
|
129
|
+
{ key: 'bikeType', name: 'Bike Type', description: '', type: types_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
130
|
+
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: types_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
|
|
131
|
+
]
|
|
132
|
+
};
|
|
144
133
|
exports.default = ERGCyclingMode;
|