incyclist-devices 1.4.53 → 1.4.54
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/ant/antfe/AntFEAdapter.d.ts +43 -2
- package/lib/ant/antfe/AntFEAdapter.js +66 -35
- package/lib/ant/antfe/ant-fe-erg-mode.d.ts +5 -0
- package/lib/ant/antfe/ant-fe-erg-mode.js +13 -0
- package/lib/ant/antfe/ant-fe-st-mode.d.ts +7 -0
- package/lib/ant/antfe/ant-fe-st-mode.js +52 -0
- package/lib/ble/ble-erg-mode.d.ts +2 -2
- package/lib/ble/ble-st-mode.d.ts +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,41 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import AntAdapter from '../AntAdapter';
|
|
2
3
|
import { Queue } from '../../utils';
|
|
4
|
+
import CyclingMode, { IncyclistBikeData } from '../../CyclingMode';
|
|
5
|
+
export declare type AntFEDeviceData = {
|
|
6
|
+
DeviceID: number;
|
|
7
|
+
Temperature?: number;
|
|
8
|
+
ZeroOffset?: number;
|
|
9
|
+
SpinDownTime?: number;
|
|
10
|
+
EquipmentType?: 'Treadmill' | 'Elliptical' | 'StationaryBike' | 'Rower' | 'Climber' | 'NordicSkier' | 'Trainer' | 'General';
|
|
11
|
+
ElapsedTime?: number;
|
|
12
|
+
Distance?: number;
|
|
13
|
+
RealSpeed?: number;
|
|
14
|
+
VirtualSpeed?: number;
|
|
15
|
+
HeartRate?: number;
|
|
16
|
+
HeartRateSource?: 'HandContact' | 'EM' | 'ANT+';
|
|
17
|
+
State?: 'OFF' | 'READY' | 'IN_USE' | 'FINISHED';
|
|
18
|
+
CycleLength?: number;
|
|
19
|
+
Incline?: number;
|
|
20
|
+
Resistance?: number;
|
|
21
|
+
METs?: number;
|
|
22
|
+
CaloricBurnRate?: number;
|
|
23
|
+
Calories?: number;
|
|
24
|
+
_EventCount0x19?: number;
|
|
25
|
+
Cadence?: number;
|
|
26
|
+
AccumulatedPower?: number;
|
|
27
|
+
InstantaneousPower?: number;
|
|
28
|
+
AveragePower?: number;
|
|
29
|
+
TrainerStatus?: number;
|
|
30
|
+
TargetStatus?: 'OnTarget' | 'LowSpeed' | 'HighSpeed';
|
|
31
|
+
HwVersion?: number;
|
|
32
|
+
ManId?: number;
|
|
33
|
+
ModelNum?: number;
|
|
34
|
+
SwVersion?: number;
|
|
35
|
+
SerialNumber?: number;
|
|
36
|
+
PairedDevices?: any[];
|
|
37
|
+
RawData: Buffer;
|
|
38
|
+
};
|
|
3
39
|
export default class AntFEAdapter extends AntAdapter {
|
|
4
40
|
started: boolean;
|
|
5
41
|
starting: boolean;
|
|
@@ -8,6 +44,7 @@ export default class AntFEAdapter extends AntAdapter {
|
|
|
8
44
|
queue?: Queue<any>;
|
|
9
45
|
workerId?: any;
|
|
10
46
|
currentCmd?: any;
|
|
47
|
+
cyclingMode: CyclingMode;
|
|
11
48
|
constructor(DeviceID: any, port: any, stick: any, protocol: any);
|
|
12
49
|
isBike(): boolean;
|
|
13
50
|
isHrm(): boolean;
|
|
@@ -15,11 +52,15 @@ export default class AntFEAdapter extends AntAdapter {
|
|
|
15
52
|
getProfile(): string;
|
|
16
53
|
getName(): string;
|
|
17
54
|
getDisplayName(): string;
|
|
55
|
+
getSupportedCyclingModes(): Array<any>;
|
|
56
|
+
setCyclingMode(mode: string | CyclingMode, settings?: any): void;
|
|
57
|
+
getCyclingMode(): CyclingMode;
|
|
58
|
+
getDefaultCyclingMode(): CyclingMode;
|
|
18
59
|
onAttached(): void;
|
|
19
60
|
getLogData(data: any, excludeList: any): any;
|
|
20
|
-
onDeviceData(deviceData:
|
|
61
|
+
onDeviceData(deviceData: AntFEDeviceData): void;
|
|
62
|
+
mapData(deviceData: AntFEDeviceData): IncyclistBikeData;
|
|
21
63
|
onDeviceEvent(data: any): void;
|
|
22
|
-
updateData(data: any, deviceData: any): any;
|
|
23
64
|
transformData(bikeData: any): any;
|
|
24
65
|
start(props?: any): Promise<any>;
|
|
25
66
|
stop(): Promise<boolean>;
|
|
@@ -16,6 +16,8 @@ const gd_eventlog_1 = require("gd-eventlog");
|
|
|
16
16
|
const AntAdapter_1 = __importDefault(require("../AntAdapter"));
|
|
17
17
|
const utils_1 = require("../utils");
|
|
18
18
|
const utils_2 = require("../../utils");
|
|
19
|
+
const ant_fe_st_mode_1 = __importDefault(require("./ant-fe-st-mode"));
|
|
20
|
+
const ant_fe_erg_mode_1 = __importDefault(require("./ant-fe-erg-mode"));
|
|
19
21
|
const floatVal = (d) => d ? parseFloat(d) : d;
|
|
20
22
|
const intVal = (d) => d ? parseInt(d) : d;
|
|
21
23
|
const hex = (v) => Math.abs(v).toString(16).toUpperCase();
|
|
@@ -54,6 +56,34 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
54
56
|
const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
|
|
55
57
|
return `${(0, utils_1.getBrand)(ManId)} FE ${DeviceID}${hrmStr}`;
|
|
56
58
|
}
|
|
59
|
+
getSupportedCyclingModes() {
|
|
60
|
+
return [ant_fe_st_mode_1.default, ant_fe_erg_mode_1.default];
|
|
61
|
+
}
|
|
62
|
+
setCyclingMode(mode, settings) {
|
|
63
|
+
let selectedMode;
|
|
64
|
+
if (typeof mode === 'string') {
|
|
65
|
+
const supported = this.getSupportedCyclingModes();
|
|
66
|
+
const CyclingModeClass = supported.find(M => { const m = new M(this); return m.getName() === mode; });
|
|
67
|
+
if (CyclingModeClass) {
|
|
68
|
+
this.cyclingMode = new CyclingModeClass(this, settings);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
selectedMode = this.getDefaultCyclingMode();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
selectedMode = mode;
|
|
75
|
+
}
|
|
76
|
+
this.cyclingMode = selectedMode;
|
|
77
|
+
this.cyclingMode.setSettings(settings);
|
|
78
|
+
}
|
|
79
|
+
getCyclingMode() {
|
|
80
|
+
if (!this.cyclingMode)
|
|
81
|
+
this.cyclingMode = this.getDefaultCyclingMode();
|
|
82
|
+
return this.cyclingMode;
|
|
83
|
+
}
|
|
84
|
+
getDefaultCyclingMode() {
|
|
85
|
+
return new ant_fe_st_mode_1.default(this);
|
|
86
|
+
}
|
|
57
87
|
onAttached() {
|
|
58
88
|
this.logger.logEvent({ message: 'Device connected' });
|
|
59
89
|
this.connected = true;
|
|
@@ -74,8 +104,9 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
74
104
|
if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
|
|
75
105
|
const logData = this.getLogData(deviceData, ['PairedDevices', 'RawData']);
|
|
76
106
|
this.logger.logEvent({ message: 'onDeviceData', data: logData });
|
|
77
|
-
|
|
78
|
-
|
|
107
|
+
let incyclistData = this.mapData(deviceData);
|
|
108
|
+
incyclistData = this.getCyclingMode().updateData(incyclistData);
|
|
109
|
+
const data = this.transformData(incyclistData);
|
|
79
110
|
this.onDataFn(data);
|
|
80
111
|
this.lastUpdate = Date.now();
|
|
81
112
|
}
|
|
@@ -84,6 +115,25 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
84
115
|
catch (err) {
|
|
85
116
|
}
|
|
86
117
|
}
|
|
118
|
+
mapData(deviceData) {
|
|
119
|
+
const data = {
|
|
120
|
+
isPedalling: false,
|
|
121
|
+
power: 0,
|
|
122
|
+
pedalRpm: undefined,
|
|
123
|
+
speed: 0,
|
|
124
|
+
heartrate: 0,
|
|
125
|
+
distanceInternal: 0,
|
|
126
|
+
slope: undefined,
|
|
127
|
+
time: undefined
|
|
128
|
+
};
|
|
129
|
+
data.speed = (deviceData.VirtualSpeed !== undefined ? deviceData.VirtualSpeed : (deviceData.RealSpeed || 0)) * 3.6;
|
|
130
|
+
data.slope = (deviceData.Incline !== undefined ? deviceData.Incline : data.slope);
|
|
131
|
+
data.power = (deviceData.InstantaneousPower !== undefined ? deviceData.InstantaneousPower : data.power);
|
|
132
|
+
data.time = (deviceData.ElapsedTime !== undefined ? deviceData.ElapsedTime : data.time);
|
|
133
|
+
data.pedalRpm = (deviceData.Cadence !== undefined ? deviceData.Cadence : data.pedalRpm);
|
|
134
|
+
data.isPedalling = data.pedalRpm > 0 || (data.pedalRpm === undefined && data.power > 0);
|
|
135
|
+
return data;
|
|
136
|
+
}
|
|
87
137
|
onDeviceEvent(data) {
|
|
88
138
|
try {
|
|
89
139
|
const cmdInfo = this.currentCmd;
|
|
@@ -127,43 +177,21 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
127
177
|
this.logger.logEvent({ message: 'Error', fn: 'parseEvent', event: { message: hex(data.message), code: hex(data.code) }, error: err.message || err });
|
|
128
178
|
}
|
|
129
179
|
}
|
|
130
|
-
updateData(data, deviceData) {
|
|
131
|
-
if (data.distanceOffs === undefined)
|
|
132
|
-
data.distanceOffs = 0;
|
|
133
|
-
data.speed = (deviceData.VirtualSpeed !== undefined ? deviceData.VirtualSpeed : deviceData.RealSpeed) * 3.6;
|
|
134
|
-
data.slope = (deviceData.Incline !== undefined ? deviceData.Incline : data.slope);
|
|
135
|
-
data.power = (deviceData.InstantaneousPower !== undefined ? deviceData.InstantaneousPower : data.power);
|
|
136
|
-
data.pedalRpm = (deviceData.Cadence !== undefined ? deviceData.Cadence : data.pedalRpm);
|
|
137
|
-
data.heartrate = (deviceData.HeartRate !== undefined ? deviceData.HeartRate : data.heartrate);
|
|
138
|
-
if (deviceData.Distance !== undefined && deviceData.Distance !== 0) {
|
|
139
|
-
data.distanceInternal = deviceData.Distance - data.distanceOffs;
|
|
140
|
-
data.distance = data.distanceInternal / 1000;
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
if (this.lastUpdate && deviceData.Cadence !== undefined && deviceData.Cadence > 0 && data.speed) {
|
|
144
|
-
const t = (Date.now() - this.lastUpdate) / 1000;
|
|
145
|
-
const prevDistance = data.distanceInternal || 0;
|
|
146
|
-
data.distanceInternal = Math.round(data.speed / 3.6 * t) + prevDistance;
|
|
147
|
-
data.distance = data.distanceInternal / 1000;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return data;
|
|
151
|
-
}
|
|
152
180
|
transformData(bikeData) {
|
|
153
181
|
if (bikeData === undefined)
|
|
154
182
|
return;
|
|
155
183
|
let distance = 0;
|
|
156
184
|
if (this.distanceInternal !== undefined && bikeData.distanceInternal !== undefined) {
|
|
157
|
-
distance =
|
|
185
|
+
distance = Math.round(bikeData.distanceInternal - this.distanceInternal);
|
|
158
186
|
}
|
|
159
187
|
if (bikeData.distanceInternal !== undefined)
|
|
160
188
|
this.distanceInternal = bikeData.distanceInternal;
|
|
161
189
|
let data = {
|
|
162
|
-
speed:
|
|
163
|
-
slope:
|
|
164
|
-
power:
|
|
165
|
-
cadence:
|
|
166
|
-
heartrate:
|
|
190
|
+
speed: bikeData.speed,
|
|
191
|
+
slope: bikeData.slope,
|
|
192
|
+
power: bikeData.power !== undefined ? Math.round(bikeData.power) : undefined,
|
|
193
|
+
cadence: bikeData.pedalRpm !== undefined ? Math.round(bikeData.pedalRpm) : undefined,
|
|
194
|
+
heartrate: bikeData.heartrate !== undefined ? Math.round(bikeData.heartrate) : undefined,
|
|
167
195
|
distance,
|
|
168
196
|
timestamp: Date.now()
|
|
169
197
|
};
|
|
@@ -295,14 +323,17 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
295
323
|
}
|
|
296
324
|
sendUpdate(request) {
|
|
297
325
|
return __awaiter(this, void 0, void 0, function* () {
|
|
298
|
-
this.
|
|
326
|
+
if (this.paused)
|
|
327
|
+
return;
|
|
328
|
+
const update = this.getCyclingMode().sendBikeUpdate(request);
|
|
329
|
+
this.logger.logEvent({ message: 'send bike update requested', update, request });
|
|
299
330
|
try {
|
|
300
331
|
const isReset = (!request || request.reset || Object.keys(request).length === 0);
|
|
301
|
-
if (
|
|
302
|
-
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTrackResistance(
|
|
332
|
+
if (update.slope !== undefined) {
|
|
333
|
+
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTrackResistance(update.slope); }), 2, 100);
|
|
303
334
|
}
|
|
304
|
-
if (
|
|
305
|
-
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(
|
|
335
|
+
if (update.targetPower !== undefined) {
|
|
336
|
+
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(update.targetPower); }), 2, 100);
|
|
306
337
|
}
|
|
307
338
|
else if (request.maxPower !== undefined) {
|
|
308
339
|
if (this.data.power && this.data.power > request.maxPower)
|
|
@@ -0,0 +1,13 @@
|
|
|
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 ble_erg_mode_1 = __importDefault(require("../../ble/ble-erg-mode"));
|
|
7
|
+
class AntFeERGCyclingMode extends ble_erg_mode_1.default {
|
|
8
|
+
constructor(adapter, props) {
|
|
9
|
+
super(adapter, props);
|
|
10
|
+
this.initLogger('AntERGMode');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.default = AntFeERGCyclingMode;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import FtmsCyclingMode from "../../ble/ble-st-mode";
|
|
2
|
+
import { UpdateRequest } from "../../CyclingMode";
|
|
3
|
+
import { DeviceAdapter } from "../../Device";
|
|
4
|
+
export default class AntStCyclingMode extends FtmsCyclingMode {
|
|
5
|
+
constructor(adapter: DeviceAdapter, props?: any);
|
|
6
|
+
sendBikeUpdate(request: UpdateRequest): UpdateRequest;
|
|
7
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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 ble_st_mode_1 = __importDefault(require("../../ble/ble-st-mode"));
|
|
7
|
+
class AntStCyclingMode extends ble_st_mode_1.default {
|
|
8
|
+
constructor(adapter, props) {
|
|
9
|
+
super(adapter, props);
|
|
10
|
+
this.initLogger('AntSTMode');
|
|
11
|
+
}
|
|
12
|
+
sendBikeUpdate(request) {
|
|
13
|
+
const getData = () => {
|
|
14
|
+
if (!this.data)
|
|
15
|
+
return {};
|
|
16
|
+
const { gear, pedalRpm, slope, power, speed } = this.data;
|
|
17
|
+
return { gear, pedalRpm, slope, power, speed };
|
|
18
|
+
};
|
|
19
|
+
const event = {};
|
|
20
|
+
if (this.data === undefined)
|
|
21
|
+
event.noData = true;
|
|
22
|
+
if (request.slope !== undefined && (event.noData || Math.abs(request.slope - this.data.slope) >= 0.1))
|
|
23
|
+
event.slopeUpdate = true;
|
|
24
|
+
if (this.prevRequest === undefined)
|
|
25
|
+
event.initialCall = true;
|
|
26
|
+
this.logger.logEvent({ message: "processing update request", request, prev: this.prevRequest, data: getData(), event });
|
|
27
|
+
let newRequest = {};
|
|
28
|
+
if (request.slope === undefined && request.targetPower === undefined && request.refresh && this.prevRequest) {
|
|
29
|
+
return this.prevRequest;
|
|
30
|
+
}
|
|
31
|
+
if (request.slope !== undefined) {
|
|
32
|
+
newRequest.slope = parseFloat(request.slope.toFixed(1));
|
|
33
|
+
this.data.slope = newRequest.slope;
|
|
34
|
+
}
|
|
35
|
+
if (request.targetPower !== undefined) {
|
|
36
|
+
newRequest.targetPower = request.targetPower;
|
|
37
|
+
}
|
|
38
|
+
if (request.minPower && request.maxPower && request.minPower === request.maxPower) {
|
|
39
|
+
newRequest.targetPower = request.minPower;
|
|
40
|
+
}
|
|
41
|
+
const prevData = this.data;
|
|
42
|
+
if (newRequest.targetPower === undefined && prevData && prevData.power) {
|
|
43
|
+
if (request.minPower !== undefined && prevData.power < request.minPower)
|
|
44
|
+
newRequest.targetPower = request.minPower;
|
|
45
|
+
if (request.maxPower !== undefined && prevData.power > request.maxPower)
|
|
46
|
+
newRequest.targetPower = request.maxPower;
|
|
47
|
+
}
|
|
48
|
+
this.prevRequest = JSON.parse(JSON.stringify(newRequest));
|
|
49
|
+
return newRequest;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.default = AntStCyclingMode;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import CyclingMode, { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
|
|
2
|
+
import { DeviceAdapter } from "../Device";
|
|
2
3
|
import PowerBasedCyclingModeBase from "../modes/power-base";
|
|
3
|
-
import { FmAdapter } from "./fm";
|
|
4
4
|
export default class BleERGCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
|
|
5
5
|
prevRequest: UpdateRequest;
|
|
6
6
|
hasBikeUpdate: boolean;
|
|
7
7
|
chain: number[];
|
|
8
8
|
cassette: number[];
|
|
9
|
-
constructor(adapter:
|
|
9
|
+
constructor(adapter: DeviceAdapter, props?: any);
|
|
10
10
|
getName(): string;
|
|
11
11
|
getDescription(): string;
|
|
12
12
|
getProperties(): CyclingModeProperty[];
|
package/lib/ble/ble-st-mode.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import CyclingMode, { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
|
|
2
|
+
import { DeviceAdapter } from "../Device";
|
|
2
3
|
import PowerBasedCyclingModeBase from "../modes/power-base";
|
|
3
|
-
import { FmAdapter } from "./fm";
|
|
4
4
|
export default class FtmsCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
|
|
5
5
|
prevRequest: UpdateRequest;
|
|
6
6
|
hasBikeUpdate: boolean;
|
|
7
|
-
constructor(adapter:
|
|
7
|
+
constructor(adapter: DeviceAdapter, props?: any);
|
|
8
8
|
getName(): string;
|
|
9
9
|
getDescription(): string;
|
|
10
10
|
getProperties(): CyclingModeProperty[];
|