incyclist-devices 2.0.0-beta.1 → 2.0.1
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/README.MD +238 -0
- package/lib/adapters.d.ts +1 -0
- package/lib/adapters.js +19 -0
- package/lib/antv2/adapter-factory.d.ts +8 -7
- package/lib/antv2/adapter-factory.js +4 -2
- package/lib/antv2/adapter.d.ts +3 -2
- package/lib/antv2/adapter.js +15 -4
- package/lib/antv2/ant-interface.d.ts +6 -2
- package/lib/antv2/ant-interface.js +27 -21
- package/lib/antv2/binding.d.ts +1 -1
- package/lib/antv2/binding.js +1 -1
- package/lib/antv2/fe/adapter.d.ts +12 -9
- package/lib/antv2/fe/adapter.js +67 -27
- package/lib/antv2/hr/adapter.d.ts +6 -5
- package/lib/antv2/hr/adapter.js +19 -16
- package/lib/antv2/index.d.ts +2 -2
- package/lib/antv2/pwr/adapter.d.ts +6 -4
- package/lib/antv2/pwr/adapter.js +24 -16
- package/lib/antv2/sensor-factory.d.ts +2 -2
- package/lib/antv2/types.d.ts +5 -2
- package/lib/antv2/types.js +3 -0
- package/lib/antv2/utils.d.ts +3 -0
- package/lib/antv2/utils.js +12 -1
- package/lib/base/adpater.d.ts +14 -2
- package/lib/base/adpater.js +43 -4
- package/lib/ble/adapter-factory.d.ts +18 -16
- package/lib/ble/adapter-factory.js +54 -45
- package/lib/ble/base/adapter.d.ts +53 -0
- package/lib/ble/{adapter.js → base/adapter.js} +111 -9
- package/lib/ble/base/comms-utils.d.ts +7 -0
- package/lib/ble/base/comms-utils.js +91 -0
- package/lib/ble/{ble-comms.d.ts → base/comms.d.ts} +27 -17
- package/lib/ble/{ble-comms.js → base/comms.js} +179 -53
- package/lib/ble/bindings/index.d.ts +2 -0
- package/lib/ble/bindings/index.js +8 -0
- package/lib/ble/bindings/linux.d.ts +15 -0
- package/lib/ble/bindings/linux.js +39 -0
- package/lib/ble/bindings/mock.d.ts +9 -0
- package/lib/ble/bindings/mock.js +108 -0
- package/lib/ble/bindings/types.d.ts +57 -0
- package/lib/ble/bindings/types.js +96 -0
- package/lib/ble/ble-interface.d.ts +34 -46
- package/lib/ble/ble-interface.js +242 -345
- package/lib/ble/ble-peripheral.d.ts +4 -2
- package/lib/ble/ble-peripheral.js +39 -8
- package/lib/ble/consts.d.ts +1 -0
- package/lib/ble/consts.js +2 -1
- package/lib/ble/cp/adapter.d.ts +1 -2
- package/lib/ble/cp/adapter.js +2 -15
- package/lib/ble/cp/comm.d.ts +8 -5
- package/lib/ble/cp/comm.js +12 -27
- package/lib/ble/elite/adapter.d.ts +1 -2
- package/lib/ble/elite/adapter.js +12 -19
- package/lib/ble/elite/comms.d.ts +8 -4
- package/lib/ble/elite/comms.js +12 -25
- package/lib/ble/fm/adapter.d.ts +3 -2
- package/lib/ble/fm/adapter.js +129 -70
- package/lib/ble/fm/comms.d.ts +8 -8
- package/lib/ble/fm/comms.js +33 -55
- package/lib/ble/fm/types.d.ts +5 -0
- package/lib/ble/hr/adapter.d.ts +1 -4
- package/lib/ble/hr/adapter.js +1 -18
- package/lib/ble/hr/comm.d.ts +6 -2
- package/lib/ble/hr/comm.js +6 -2
- package/lib/ble/hr/mock.d.ts +7 -0
- package/lib/ble/hr/mock.js +47 -0
- package/lib/ble/index.d.ts +2 -1
- package/lib/ble/index.js +5 -5
- package/lib/ble/peripheral-cache.d.ts +43 -0
- package/lib/ble/peripheral-cache.js +107 -0
- package/lib/ble/tacx/adapter.d.ts +1 -1
- package/lib/ble/tacx/adapter.js +20 -14
- package/lib/ble/tacx/comms.d.ts +6 -6
- package/lib/ble/tacx/comms.js +10 -43
- package/lib/ble/types.d.ts +54 -27
- package/lib/ble/types.js +0 -17
- package/lib/ble/utils.d.ts +15 -5
- package/lib/ble/utils.js +25 -66
- package/lib/ble/wahoo/adapter.d.ts +1 -1
- package/lib/ble/wahoo/adapter.js +12 -10
- package/lib/ble/wahoo/comms.d.ts +7 -6
- package/lib/ble/wahoo/comms.js +15 -17
- package/lib/index.d.ts +10 -7
- package/lib/index.js +21 -25
- package/lib/interfaces.d.ts +2 -1
- package/lib/interfaces.js +4 -0
- package/lib/modes/power-base.js +4 -0
- package/lib/serial/adapter.d.ts +5 -0
- package/lib/serial/adapter.js +19 -0
- package/lib/serial/bindings/tcp.d.ts +2 -1
- package/lib/serial/bindings/tcp.js +19 -5
- package/lib/serial/daum/DaumAdapter.d.ts +1 -1
- package/lib/serial/daum/DaumAdapter.js +16 -10
- package/lib/serial/daum/premium/adapter.d.ts +1 -0
- package/lib/serial/daum/premium/adapter.js +9 -2
- package/lib/serial/daum/premium/comms.js +10 -3
- package/lib/serial/daum/premium/mock.js +0 -1
- package/lib/serial/index.d.ts +3 -3
- package/lib/serial/index.js +2 -2
- package/lib/serial/kettler/ergo-racer/adapter.d.ts +1 -4
- package/lib/serial/kettler/ergo-racer/adapter.js +15 -39
- package/lib/serial/serial-interface.d.ts +3 -1
- package/lib/serial/serial-interface.js +43 -17
- package/lib/simulator/Simulator.d.ts +2 -0
- package/lib/simulator/Simulator.js +8 -5
- package/lib/types/adapter.d.ts +10 -3
- package/lib/types/device.d.ts +3 -0
- package/lib/types/interface.d.ts +7 -3
- package/package.json +3 -5
- package/lib/ble/adapter.d.ts +0 -41
- package/lib/ble/ble.d.ts +0 -57
- package/lib/ble/ble.js +0 -48
- package/lib/device.d.ts +0 -0
- package/lib/device.js +0 -0
package/lib/ble/fm/adapter.js
CHANGED
|
@@ -17,7 +17,7 @@ const power_meter_1 = __importDefault(require("../../modes/power-meter"));
|
|
|
17
17
|
const ble_st_mode_1 = __importDefault(require("../../modes/ble-st-mode"));
|
|
18
18
|
const ble_erg_mode_1 = __importDefault(require("../../modes/ble-erg-mode"));
|
|
19
19
|
const comms_1 = __importDefault(require("./comms"));
|
|
20
|
-
const adapter_1 = require("../adapter");
|
|
20
|
+
const adapter_1 = require("../base/adapter");
|
|
21
21
|
const consts_1 = require("./consts");
|
|
22
22
|
const utils_1 = require("../../utils/utils");
|
|
23
23
|
const capabilities_1 = require("../../types/capabilities");
|
|
@@ -50,23 +50,27 @@ class BleFmAdapter extends adapter_1.BleControllableAdapter {
|
|
|
50
50
|
return this.getName();
|
|
51
51
|
}
|
|
52
52
|
getSupportedCyclingModes() {
|
|
53
|
-
|
|
53
|
+
var _a;
|
|
54
|
+
const modes = [power_meter_1.default];
|
|
55
|
+
const features = (_a = this.getComms()) === null || _a === void 0 ? void 0 : _a.features;
|
|
56
|
+
if (!features)
|
|
57
|
+
return [power_meter_1.default, ble_st_mode_1.default, ble_erg_mode_1.default];
|
|
58
|
+
if (features.setPower === undefined || features.setPower)
|
|
59
|
+
modes.push(ble_erg_mode_1.default);
|
|
60
|
+
if (features.setSlope === undefined || features.setSlope)
|
|
61
|
+
modes.push(ble_st_mode_1.default);
|
|
62
|
+
return modes;
|
|
54
63
|
}
|
|
55
64
|
getDefaultCyclingMode() {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (
|
|
61
|
-
return;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
incyclistData = this.getCyclingMode().updateData(incyclistData);
|
|
66
|
-
this.data = this.transformData(incyclistData);
|
|
67
|
-
this.onDataFn(this.data);
|
|
68
|
-
this.lastUpdate = Date.now();
|
|
69
|
-
}
|
|
65
|
+
var _a;
|
|
66
|
+
const features = (_a = this.getComms()) === null || _a === void 0 ? void 0 : _a.features;
|
|
67
|
+
if (!features)
|
|
68
|
+
return new ble_st_mode_1.default(this);
|
|
69
|
+
if (features.setSlope === undefined || features.setSlope)
|
|
70
|
+
return new ble_st_mode_1.default(this);
|
|
71
|
+
if (features.setPower === undefined || features.setPower)
|
|
72
|
+
return new ble_erg_mode_1.default(this);
|
|
73
|
+
return new power_meter_1.default(this);
|
|
70
74
|
}
|
|
71
75
|
mapData(deviceData) {
|
|
72
76
|
const data = {
|
|
@@ -83,6 +87,7 @@ class BleFmAdapter extends adapter_1.BleControllableAdapter {
|
|
|
83
87
|
data.pedalRpm = (deviceData.cadence !== undefined ? deviceData.cadence : data.pedalRpm);
|
|
84
88
|
data.time = (deviceData.time !== undefined ? deviceData.time : data.time);
|
|
85
89
|
data.isPedalling = data.pedalRpm > 0 || (data.pedalRpm === undefined && data.power > 0);
|
|
90
|
+
data.heartrate = deviceData.heartrate || data.heartrate;
|
|
86
91
|
return data;
|
|
87
92
|
}
|
|
88
93
|
transformData(bikeData) {
|
|
@@ -100,73 +105,104 @@ class BleFmAdapter extends adapter_1.BleControllableAdapter {
|
|
|
100
105
|
power: bikeData.power !== undefined ? Math.round(bikeData.power) : undefined,
|
|
101
106
|
cadence: bikeData.pedalRpm !== undefined ? Math.round(bikeData.pedalRpm) : undefined,
|
|
102
107
|
distance,
|
|
108
|
+
heartrate: bikeData.heartrate,
|
|
103
109
|
timestamp: Date.now()
|
|
104
110
|
};
|
|
105
111
|
return data;
|
|
106
112
|
}
|
|
107
113
|
start(props = {}) {
|
|
108
114
|
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
-
|
|
115
|
+
const wasPaused = this.paused;
|
|
116
|
+
this.resume();
|
|
117
|
+
if (this.started && !wasPaused)
|
|
110
118
|
return true;
|
|
111
|
-
this.
|
|
112
|
-
const { restart } = props;
|
|
113
|
-
if (!restart && this.ble.isScanning())
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
this.logEvent(Object.assign(Object.assign({ message: 'start requested' }, this.getSettings()), { protocol: this.getProtocolName(), props }));
|
|
120
|
+
const { restart = wasPaused } = props;
|
|
121
|
+
if (!restart && this.ble.isScanning() && !this.getComms().isConnected()) {
|
|
122
|
+
}
|
|
123
|
+
let scanOnly = props.scanOnly;
|
|
124
|
+
if (this.ble.isScanning() && this.getComms().isConnected()) {
|
|
125
|
+
scanOnly = true;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
const { timeout = 20000 } = props || {};
|
|
129
|
+
if (!this.connectPromise)
|
|
130
|
+
this.connectPromise = this.connect();
|
|
131
|
+
const res = yield Promise.race([
|
|
132
|
+
this.connectPromise.then((connected) => {
|
|
133
|
+
this.connectPromise = undefined;
|
|
134
|
+
return { connected, reason: connected ? null : 'could not connect' };
|
|
135
|
+
}),
|
|
136
|
+
(0, utils_1.sleep)(timeout).then(() => ({ connected: false, reason: 'timeout' }))
|
|
137
|
+
]);
|
|
138
|
+
const connected = res.connected;
|
|
139
|
+
if (!connected) {
|
|
140
|
+
throw new Error(`could not start device, reason:${res.reason}`);
|
|
120
141
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const comms = this.device;
|
|
145
|
+
if (comms) {
|
|
146
|
+
if (!scanOnly) {
|
|
147
|
+
const mode = this.getCyclingMode();
|
|
148
|
+
if (mode && mode.getSetting('bikeType')) {
|
|
149
|
+
const bikeType = mode.getSetting('bikeType').toLowerCase();
|
|
150
|
+
comms.setCrr(consts_1.cRR);
|
|
151
|
+
switch (bikeType) {
|
|
152
|
+
case 'race':
|
|
153
|
+
comms.setCw(consts_1.cwABike.race);
|
|
154
|
+
break;
|
|
155
|
+
case 'triathlon':
|
|
156
|
+
comms.setCw(consts_1.cwABike.triathlon);
|
|
157
|
+
break;
|
|
158
|
+
case 'mountain':
|
|
159
|
+
comms.setCw(consts_1.cwABike.mountain);
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
139
162
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
163
|
+
let hasControl = yield comms.requestControl();
|
|
164
|
+
if (!hasControl) {
|
|
165
|
+
let retry = 1;
|
|
166
|
+
while (!hasControl && retry < 3) {
|
|
167
|
+
yield (0, utils_1.sleep)(1000);
|
|
168
|
+
hasControl = yield comms.requestControl();
|
|
169
|
+
retry++;
|
|
170
|
+
}
|
|
148
171
|
}
|
|
172
|
+
if (!hasControl)
|
|
173
|
+
throw new Error('could not establish control');
|
|
174
|
+
const startRequest = this.getCyclingMode().getBikeInitRequest();
|
|
175
|
+
yield this.sendUpdate(startRequest);
|
|
176
|
+
}
|
|
177
|
+
if (!this.started && !wasPaused) {
|
|
178
|
+
comms.on('data', (data) => {
|
|
179
|
+
this.onDeviceData(data);
|
|
180
|
+
});
|
|
181
|
+
comms.on('disconnected', this.emit);
|
|
149
182
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const startRequest = this.getCyclingMode().getBikeInitRequest();
|
|
153
|
-
yield this.sendUpdate(startRequest);
|
|
154
|
-
bleDevice.on('data', (data) => {
|
|
155
|
-
this.onDeviceData(data);
|
|
156
|
-
});
|
|
157
|
-
bleDevice.on('disconnected', this.emit);
|
|
158
|
-
if (bleDevice.isHrm() && !this.hasCapability(capabilities_1.IncyclistCapability.HeartRate)) {
|
|
183
|
+
const before = this.capabilities.join(',');
|
|
184
|
+
if (comms.features.heartrate && !this.hasCapability(capabilities_1.IncyclistCapability.HeartRate)) {
|
|
159
185
|
this.capabilities.push(capabilities_1.IncyclistCapability.HeartRate);
|
|
160
186
|
}
|
|
187
|
+
if (comms.features.cadence && !this.hasCapability(capabilities_1.IncyclistCapability.Cadence)) {
|
|
188
|
+
this.capabilities.push(capabilities_1.IncyclistCapability.Cadence);
|
|
189
|
+
}
|
|
190
|
+
if (comms.features.power && !this.hasCapability(capabilities_1.IncyclistCapability.Power)) {
|
|
191
|
+
this.capabilities.push(capabilities_1.IncyclistCapability.Power);
|
|
192
|
+
}
|
|
193
|
+
const after = this.capabilities.join(',');
|
|
194
|
+
if (before !== after) {
|
|
195
|
+
this.emit('device-info', this.getSettings(), { capabilities: this.capabilities });
|
|
196
|
+
}
|
|
161
197
|
this.resetData();
|
|
162
198
|
this.stopped = false;
|
|
163
199
|
this.started = true;
|
|
164
|
-
this.
|
|
200
|
+
this.resume();
|
|
165
201
|
return true;
|
|
166
202
|
}
|
|
167
203
|
}
|
|
168
204
|
catch (err) {
|
|
169
|
-
this.
|
|
205
|
+
this.logEvent({ message: 'start result: error', error: err.message, profile: this.getProfile() });
|
|
170
206
|
throw new Error(`could not start device, reason:${err.message}`);
|
|
171
207
|
}
|
|
172
208
|
});
|
|
@@ -175,16 +211,39 @@ class BleFmAdapter extends adapter_1.BleControllableAdapter {
|
|
|
175
211
|
return __awaiter(this, void 0, void 0, function* () {
|
|
176
212
|
if (this.paused || !this.device)
|
|
177
213
|
return;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
214
|
+
try {
|
|
215
|
+
const update = this.getCyclingMode().sendBikeUpdate(request);
|
|
216
|
+
this.logEvent({ message: 'send bike update requested', profile: this.getProfile(), update, request });
|
|
217
|
+
const device = this.device;
|
|
218
|
+
if (update.slope !== undefined) {
|
|
219
|
+
yield device.setSlope(update.slope);
|
|
220
|
+
}
|
|
221
|
+
if (update.targetPower !== undefined) {
|
|
222
|
+
yield device.setTargetPower(update.targetPower);
|
|
223
|
+
}
|
|
183
224
|
}
|
|
184
|
-
|
|
185
|
-
|
|
225
|
+
catch (err) {
|
|
226
|
+
this.logEvent({ message: 'error', fn: 'sendUpdate()', request, error: err.message, stack: err.stack });
|
|
186
227
|
}
|
|
187
228
|
});
|
|
188
229
|
}
|
|
230
|
+
setCyclingMode(mode, settings) {
|
|
231
|
+
const modeChange = this.cyclingMode.getName() !== mode;
|
|
232
|
+
const prevMode = this.getCyclingMode();
|
|
233
|
+
super.setCyclingMode(mode, settings);
|
|
234
|
+
const isPaused = this.isPaused();
|
|
235
|
+
if (modeChange && this.started && !this.stopped) {
|
|
236
|
+
if (prevMode instanceof ble_st_mode_1.default) {
|
|
237
|
+
const power = this.data.power;
|
|
238
|
+
const request = power ? { targetPower: power } : this.getCyclingMode().getBikeInitRequest();
|
|
239
|
+
if (isPaused)
|
|
240
|
+
this.resume();
|
|
241
|
+
this.sendUpdate(request).then().catch().finally(() => {
|
|
242
|
+
if (isPaused)
|
|
243
|
+
this.pause();
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
189
248
|
}
|
|
190
249
|
exports.default = BleFmAdapter;
|
package/lib/ble/fm/comms.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { BleWriteProps, IBlePeripheralConnector } from "../types";
|
|
3
|
-
import { BleComms } from "../ble-comms";
|
|
2
|
+
import { BleProtocol, BleWriteProps, IBlePeripheralConnector } from "../types";
|
|
4
3
|
import { IndoorBikeData, IndoorBikeFeatures } from "./types";
|
|
4
|
+
import { BleComms } from "../base/comms";
|
|
5
|
+
import { LegacyProfile } from "../../antv2/types";
|
|
5
6
|
export default class BleFitnessMachineDevice extends BleComms {
|
|
7
|
+
static protocol: BleProtocol;
|
|
6
8
|
static services: string[];
|
|
7
9
|
static characteristics: string[];
|
|
8
10
|
static detectionPriority: number;
|
|
@@ -16,16 +18,14 @@ export default class BleFitnessMachineDevice extends BleComms {
|
|
|
16
18
|
windSpeed: number;
|
|
17
19
|
wheelSize: number;
|
|
18
20
|
constructor(props?: any);
|
|
19
|
-
isMatching(characteristics: string[]): boolean;
|
|
21
|
+
static isMatching(characteristics: string[]): boolean;
|
|
20
22
|
subscribeWriteResponse(cuuid: string): Promise<void>;
|
|
21
23
|
subscribeAll(conn?: IBlePeripheralConnector): Promise<void>;
|
|
22
24
|
init(): Promise<boolean>;
|
|
23
|
-
onDisconnect(): void
|
|
24
|
-
getProfile():
|
|
25
|
+
onDisconnect(): Promise<void>;
|
|
26
|
+
getProfile(): LegacyProfile;
|
|
27
|
+
getProtocol(): BleProtocol;
|
|
25
28
|
getServiceUUids(): string[];
|
|
26
|
-
isBike(): boolean;
|
|
27
|
-
isPower(): boolean;
|
|
28
|
-
isHrm(): boolean;
|
|
29
29
|
parseHrm(_data: Uint8Array): IndoorBikeData;
|
|
30
30
|
setCrr(crr: number): void;
|
|
31
31
|
getCrr(): number;
|
package/lib/ble/fm/comms.js
CHANGED
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const ble_comms_1 = require("../ble-comms");
|
|
13
12
|
const consts_1 = require("../consts");
|
|
13
|
+
const comms_1 = require("../base/comms");
|
|
14
14
|
const bit = (nr) => (1 << nr);
|
|
15
15
|
const IndoorBikeDataFlag = {
|
|
16
16
|
MoreData: bit(0),
|
|
@@ -65,7 +65,7 @@ const TargetSettingFeatureFlag = {
|
|
|
65
65
|
SpinDownControlSupported: bit(15),
|
|
66
66
|
TargetedCadenceConfigurationSupported: bit(16)
|
|
67
67
|
};
|
|
68
|
-
class BleFitnessMachineDevice extends
|
|
68
|
+
class BleFitnessMachineDevice extends comms_1.BleComms {
|
|
69
69
|
constructor(props) {
|
|
70
70
|
super(props);
|
|
71
71
|
this.features = undefined;
|
|
@@ -79,7 +79,7 @@ class BleFitnessMachineDevice extends ble_comms_1.BleComms {
|
|
|
79
79
|
this.data = {};
|
|
80
80
|
this.services = BleFitnessMachineDevice.services;
|
|
81
81
|
}
|
|
82
|
-
isMatching(characteristics) {
|
|
82
|
+
static isMatching(characteristics) {
|
|
83
83
|
if (!characteristics)
|
|
84
84
|
return false;
|
|
85
85
|
const hasStatus = characteristics.find(c => c === consts_1.FTMS_STATUS) !== undefined;
|
|
@@ -90,7 +90,7 @@ class BleFitnessMachineDevice extends ble_comms_1.BleComms {
|
|
|
90
90
|
subscribeWriteResponse(cuuid) {
|
|
91
91
|
return __awaiter(this, void 0, void 0, function* () {
|
|
92
92
|
this.logEvent({ message: 'subscribe to CP response', characteristics: cuuid });
|
|
93
|
-
const connector = this.ble.getConnector(this.peripheral);
|
|
93
|
+
const connector = this.ble.peripheralCache.getConnector(this.peripheral);
|
|
94
94
|
const isAlreadySubscribed = connector.isSubscribed(cuuid);
|
|
95
95
|
if (!isAlreadySubscribed) {
|
|
96
96
|
connector.removeAllListeners(cuuid);
|
|
@@ -110,36 +110,14 @@ class BleFitnessMachineDevice extends ble_comms_1.BleComms {
|
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
subscribeAll(conn) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
resolve();
|
|
122
|
-
}
|
|
123
|
-
}, 100);
|
|
124
|
-
try {
|
|
125
|
-
const connector = conn || this.ble.getConnector(this.peripheral);
|
|
126
|
-
for (let i = 0; i < characteristics.length; i++) {
|
|
127
|
-
const c = characteristics[i];
|
|
128
|
-
const isAlreadySubscribed = connector.isSubscribed(c);
|
|
129
|
-
if (!isAlreadySubscribed) {
|
|
130
|
-
connector.removeAllListeners(c);
|
|
131
|
-
connector.on(c, (uuid, data) => {
|
|
132
|
-
this.onData(uuid, data);
|
|
133
|
-
});
|
|
134
|
-
connector.subscribe(c);
|
|
135
|
-
this.subscribedCharacteristics.push(c);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
catch (err) {
|
|
140
|
-
this.logEvent({ message: 'Error', fn: 'subscribeAll()', error: err.message, stack: err.stack });
|
|
141
|
-
}
|
|
142
|
-
});
|
|
113
|
+
const characteristics = [consts_1.INDOOR_BIKE_DATA, consts_1.FTMS_STATUS, consts_1.FTMS_CP];
|
|
114
|
+
if (!this.features || (this.features && this.features.cadence))
|
|
115
|
+
characteristics.push(consts_1.CSC_MEASUREMENT);
|
|
116
|
+
if (!this.features || (this.features && this.features.power))
|
|
117
|
+
characteristics.push(consts_1.CSP_MEASUREMENT);
|
|
118
|
+
if (!this.features || (this.features && this.features.heartrate))
|
|
119
|
+
characteristics.push(consts_1.HR_MEASUREMENT);
|
|
120
|
+
return this.subscribeMultiple(characteristics, conn);
|
|
143
121
|
}
|
|
144
122
|
init() {
|
|
145
123
|
const _super = Object.create(null, {
|
|
@@ -150,39 +128,32 @@ class BleFitnessMachineDevice extends ble_comms_1.BleComms {
|
|
|
150
128
|
yield _super.initDevice.call(this);
|
|
151
129
|
yield this.getFitnessMachineFeatures();
|
|
152
130
|
this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
|
|
131
|
+
return true;
|
|
153
132
|
}
|
|
154
133
|
catch (err) {
|
|
155
134
|
this.logEvent({ message: 'error', fn: 'BleFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
|
|
156
|
-
return
|
|
135
|
+
return false;
|
|
157
136
|
}
|
|
158
137
|
});
|
|
159
138
|
}
|
|
160
139
|
onDisconnect() {
|
|
161
|
-
|
|
162
|
-
|
|
140
|
+
const _super = Object.create(null, {
|
|
141
|
+
onDisconnect: { get: () => super.onDisconnect }
|
|
142
|
+
});
|
|
143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
_super.onDisconnect.call(this);
|
|
145
|
+
this.hasControl = false;
|
|
146
|
+
});
|
|
163
147
|
}
|
|
164
148
|
getProfile() {
|
|
165
149
|
return 'Smart Trainer';
|
|
166
150
|
}
|
|
151
|
+
getProtocol() {
|
|
152
|
+
return BleFitnessMachineDevice.protocol;
|
|
153
|
+
}
|
|
167
154
|
getServiceUUids() {
|
|
168
155
|
return BleFitnessMachineDevice.services;
|
|
169
156
|
}
|
|
170
|
-
isBike() {
|
|
171
|
-
return this.features === undefined ||
|
|
172
|
-
((this.features.targetSettings & TargetSettingFeatureFlag.IndoorBikeSimulationParametersSupported) !== 0);
|
|
173
|
-
}
|
|
174
|
-
isPower() {
|
|
175
|
-
if (this.hasService('1818'))
|
|
176
|
-
return true;
|
|
177
|
-
if (this.features === undefined)
|
|
178
|
-
return false;
|
|
179
|
-
const { fitnessMachine } = this.features;
|
|
180
|
-
if (fitnessMachine & FitnessMachineFeatureFlag.PowerMeasurementSupported)
|
|
181
|
-
return true;
|
|
182
|
-
}
|
|
183
|
-
isHrm() {
|
|
184
|
-
return this.hasService('180d') || (this.features && (this.features.fitnessMachine & FitnessMachineFeatureFlag.HeartRateMeasurementSupported) !== 0);
|
|
185
|
-
}
|
|
186
157
|
parseHrm(_data) {
|
|
187
158
|
const data = Buffer.from(_data);
|
|
188
159
|
try {
|
|
@@ -327,8 +298,14 @@ class BleFitnessMachineDevice extends ble_comms_1.BleComms {
|
|
|
327
298
|
if (buffer) {
|
|
328
299
|
const fitnessMachine = buffer.readUInt32LE(0);
|
|
329
300
|
const targetSettings = buffer.readUInt32LE(4);
|
|
330
|
-
|
|
331
|
-
|
|
301
|
+
const power = (fitnessMachine & FitnessMachineFeatureFlag.PowerMeasurementSupported) !== 0;
|
|
302
|
+
const heartrate = (fitnessMachine & FitnessMachineFeatureFlag.HeartRateMeasurementSupported) !== 0;
|
|
303
|
+
const cadence = (fitnessMachine & FitnessMachineFeatureFlag.CadenceSupported) !== 0;
|
|
304
|
+
const setSlope = (targetSettings & TargetSettingFeatureFlag.IndoorBikeSimulationParametersSupported) !== 0
|
|
305
|
+
|| (targetSettings & TargetSettingFeatureFlag.InclinationTargetSettingSupported) !== 0;
|
|
306
|
+
const setPower = (targetSettings & TargetSettingFeatureFlag.PowerTargetSettingSupported) !== 0;
|
|
307
|
+
this.features = { fitnessMachine, targetSettings, power, heartrate, cadence, setPower, setSlope };
|
|
308
|
+
this.logEvent({ message: 'supported Features: ', fatures: this.features, power, heartrate, cadence });
|
|
332
309
|
}
|
|
333
310
|
}
|
|
334
311
|
catch (err) {
|
|
@@ -520,6 +497,7 @@ class BleFitnessMachineDevice extends ble_comms_1.BleComms {
|
|
|
520
497
|
}
|
|
521
498
|
}
|
|
522
499
|
exports.default = BleFitnessMachineDevice;
|
|
500
|
+
BleFitnessMachineDevice.protocol = 'fm';
|
|
523
501
|
BleFitnessMachineDevice.services = [consts_1.FTMS];
|
|
524
502
|
BleFitnessMachineDevice.characteristics = ['2acc', consts_1.INDOOR_BIKE_DATA, '2ad6', '2ad8', consts_1.FTMS_CP, consts_1.FTMS_STATUS];
|
|
525
503
|
BleFitnessMachineDevice.detectionPriority = 100;
|
package/lib/ble/fm/types.d.ts
CHANGED
package/lib/ble/hr/adapter.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import BleAdapter from '../adapter';
|
|
1
|
+
import BleAdapter from '../base/adapter';
|
|
2
2
|
import { DeviceProperties } from '../../types/device';
|
|
3
3
|
import { BleDeviceSettings } from '../types';
|
|
4
4
|
import { HrmData } from './types';
|
|
@@ -10,8 +10,5 @@ export default class HrmAdapter extends BleAdapter {
|
|
|
10
10
|
getProfile(): string;
|
|
11
11
|
getName(): string;
|
|
12
12
|
getDisplayName(): string;
|
|
13
|
-
getPort(): string;
|
|
14
|
-
setIgnoreHrm(ignore: any): void;
|
|
15
|
-
onDeviceData(deviceData: HrmData): void;
|
|
16
13
|
mapData(deviceData: HrmData): DeviceData;
|
|
17
14
|
}
|
package/lib/ble/hr/adapter.js
CHANGED
|
@@ -4,7 +4,7 @@ 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 adapter_1 = __importDefault(require("../adapter"));
|
|
7
|
+
const adapter_1 = __importDefault(require("../base/adapter"));
|
|
8
8
|
const comm_1 = __importDefault(require("./comm"));
|
|
9
9
|
const capabilities_1 = require("../../types/capabilities");
|
|
10
10
|
class HrmAdapter extends adapter_1.default {
|
|
@@ -37,23 +37,6 @@ class HrmAdapter extends adapter_1.default {
|
|
|
37
37
|
const hrmStr = hrm ? ` (${hrm})` : '';
|
|
38
38
|
return `${name}${hrmStr}`;
|
|
39
39
|
}
|
|
40
|
-
getPort() {
|
|
41
|
-
return 'ble';
|
|
42
|
-
}
|
|
43
|
-
setIgnoreHrm(ignore) {
|
|
44
|
-
this.ignore = ignore;
|
|
45
|
-
}
|
|
46
|
-
onDeviceData(deviceData) {
|
|
47
|
-
super.onDeviceData(deviceData);
|
|
48
|
-
if (!this.started || this.paused || !this.onDataFn)
|
|
49
|
-
return;
|
|
50
|
-
if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
|
|
51
|
-
this.logger.logEvent({ message: 'onDeviceData', data: deviceData });
|
|
52
|
-
this.data = this.mapData(this.deviceData);
|
|
53
|
-
this.onDataFn(this.data);
|
|
54
|
-
this.lastUpdate = Date.now();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
40
|
mapData(deviceData) {
|
|
58
41
|
const { heartrate } = deviceData;
|
|
59
42
|
return { heartrate };
|
package/lib/ble/hr/comm.d.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import {
|
|
2
|
+
import { LegacyProfile } from '../../antv2/types';
|
|
3
|
+
import { BleComms } from '../base/comms';
|
|
4
|
+
import { BleProtocol } from '../types';
|
|
3
5
|
import { HrmData } from './types';
|
|
4
6
|
export default class BleHrmDevice extends BleComms {
|
|
7
|
+
static protocol: BleProtocol;
|
|
5
8
|
static services: string[];
|
|
6
9
|
static characteristics: string[];
|
|
7
10
|
static detectionPriority: number;
|
|
8
11
|
heartrate: number;
|
|
9
12
|
rr: number;
|
|
10
13
|
constructor(props?: any);
|
|
11
|
-
getProfile():
|
|
14
|
+
getProfile(): LegacyProfile;
|
|
15
|
+
getProtocol(): BleProtocol;
|
|
12
16
|
getServiceUUids(): string[];
|
|
13
17
|
parseHrm(_data: Uint8Array): HrmData;
|
|
14
18
|
onData(characteristic: string, data: Buffer): boolean;
|
package/lib/ble/hr/comm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
class BleHrmDevice extends
|
|
3
|
+
const comms_1 = require("../base/comms");
|
|
4
|
+
class BleHrmDevice extends comms_1.BleComms {
|
|
5
5
|
constructor(props) {
|
|
6
6
|
super(props);
|
|
7
7
|
this.heartrate = undefined;
|
|
@@ -10,6 +10,9 @@ class BleHrmDevice extends ble_comms_1.BleComms {
|
|
|
10
10
|
getProfile() {
|
|
11
11
|
return 'Heartrate Monitor';
|
|
12
12
|
}
|
|
13
|
+
getProtocol() {
|
|
14
|
+
return BleHrmDevice.protocol;
|
|
15
|
+
}
|
|
13
16
|
getServiceUUids() {
|
|
14
17
|
return BleHrmDevice.services;
|
|
15
18
|
}
|
|
@@ -47,6 +50,7 @@ class BleHrmDevice extends ble_comms_1.BleComms {
|
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
exports.default = BleHrmDevice;
|
|
53
|
+
BleHrmDevice.protocol = 'hr';
|
|
50
54
|
BleHrmDevice.services = ['180d'];
|
|
51
55
|
BleHrmDevice.characteristics = ['2a37', '2a38', '2a39', '2a3c'];
|
|
52
56
|
BleHrmDevice.detectionPriority = 1;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HrMock = void 0;
|
|
4
|
+
const types_1 = require("../bindings/types");
|
|
5
|
+
class HeartRateMeasuremenCharacteristic extends types_1.StaticNotifyCharacteristic {
|
|
6
|
+
constructor(uuid, description, heartrate = 0) {
|
|
7
|
+
super(uuid, description);
|
|
8
|
+
this.heartrate = heartrate;
|
|
9
|
+
this.value = Buffer.from(this.heartrate.toString());
|
|
10
|
+
}
|
|
11
|
+
notify() {
|
|
12
|
+
const buffer = Buffer.alloc(2);
|
|
13
|
+
buffer.writeUInt8(0, 0);
|
|
14
|
+
buffer.writeUInt8(this.heartrate, 1);
|
|
15
|
+
this.emit('data', buffer);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const HR = {
|
|
19
|
+
uuid: "180d",
|
|
20
|
+
characteristics: [
|
|
21
|
+
new HeartRateMeasuremenCharacteristic('2a37', 'Heart Rate Measurement', 60)
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
const DIS = {
|
|
25
|
+
uuid: '180a',
|
|
26
|
+
characteristics: [
|
|
27
|
+
new types_1.StaticReadCharacteristic('2a23', 'System Id', '0'),
|
|
28
|
+
new types_1.StaticReadCharacteristic('2a24', 'Model Number', '1'),
|
|
29
|
+
new types_1.StaticReadCharacteristic('2a25', 'Serial Number', '4711'),
|
|
30
|
+
new types_1.StaticReadCharacteristic('2a26', 'Firmware Revision', '1'),
|
|
31
|
+
new types_1.StaticReadCharacteristic('2a27', 'Hardware Revision', '1'),
|
|
32
|
+
new types_1.StaticReadCharacteristic('2a28', 'Software Revision', '1'),
|
|
33
|
+
new types_1.StaticReadCharacteristic('2a29', 'Manufacturer Name', 'Incyclist')
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
exports.HrMock = {
|
|
37
|
+
services: [HR, DIS],
|
|
38
|
+
id: "a87b6100820d48b1401bf83a8cf6f046",
|
|
39
|
+
name: "HRM-Mock",
|
|
40
|
+
address: "a87b6100820d48b1401bf83a8cf6f046",
|
|
41
|
+
setNotifyFrequency: (ms) => {
|
|
42
|
+
HR.characteristics[0].notifyFrequency = ms;
|
|
43
|
+
},
|
|
44
|
+
setHeartrate: (hr) => {
|
|
45
|
+
HR.characteristics[0].heartrate = hr;
|
|
46
|
+
}
|
|
47
|
+
};
|
package/lib/ble/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ import { BlePwrAdapter } from './cp';
|
|
|
5
5
|
import { BleFmAdapter } from './fm';
|
|
6
6
|
import { BleWahooAdapter } from './wahoo';
|
|
7
7
|
import { BleTacxAdapter } from './tacx';
|
|
8
|
-
|
|
8
|
+
import { BleDeviceSettings, BleInterfaceProps } from './types';
|
|
9
|
+
export { BleAdapterFactory, BleInterface, BleInterfaceProps, BleDeviceSettings, BleHrmAdapter, BlePwrAdapter, BleFmAdapter, BleWahooAdapter, BleTacxAdapter };
|
package/lib/ble/index.js
CHANGED
|
@@ -19,8 +19,8 @@ Object.defineProperty(exports, "BleWahooAdapter", { enumerable: true, get: funct
|
|
|
19
19
|
const tacx_1 = require("./tacx");
|
|
20
20
|
Object.defineProperty(exports, "BleTacxAdapter", { enumerable: true, get: function () { return tacx_1.BleTacxAdapter; } });
|
|
21
21
|
const af = adapter_factory_1.default.getInstance();
|
|
22
|
-
af.register('hr',
|
|
23
|
-
af.register('cp',
|
|
24
|
-
af.register('fm',
|
|
25
|
-
af.register('wahoo',
|
|
26
|
-
af.register('tacx',
|
|
22
|
+
af.register('hr', hr_1.BleHrmAdapter, hr_1.BleHrmComms);
|
|
23
|
+
af.register('cp', cp_1.BlePwrAdapter, cp_1.BlePwrComms);
|
|
24
|
+
af.register('fm', fm_1.BleFmAdapter, fm_1.BleFmComms);
|
|
25
|
+
af.register('wahoo', wahoo_1.BleWahooAdapter, wahoo_1.BleWahooComms);
|
|
26
|
+
af.register('tacx', tacx_1.BleTacxAdapter, tacx_1.BleTacxComms);
|