incyclist-devices 1.4.45 → 1.4.48

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.
@@ -8,10 +8,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const gd_eventlog_1 = require("gd-eventlog");
13
16
  const utils_1 = require("../utils");
14
17
  const ble_1 = require("./ble");
18
+ const ble_peripheral_1 = __importDefault(require("./ble-peripheral"));
15
19
  const CONNECT_TIMEOUT = 5000;
16
20
  const DEFAULT_SCAN_TIMEOUT = 20000;
17
21
  const BACKGROUND_SCAN_TIMEOUT = 30000;
@@ -71,6 +75,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
71
75
  connect(props = {}) {
72
76
  const timeout = props.timeout || 2000;
73
77
  const runBackgroundScan = () => {
78
+ return;
74
79
  this.scanState.isBackgroundScan = true;
75
80
  this.scan({ timeout: BACKGROUND_SCAN_TIMEOUT, isBackgroundScan: true })
76
81
  .then(() => {
@@ -267,7 +272,22 @@ class BleInterface extends ble_1.BleInterfaceClass {
267
272
  });
268
273
  }
269
274
  addPeripheralToCache(peripheral, props = {}) {
270
- this.peripheralCache.push(Object.assign({ address: peripheral.address, ts: Date.now(), peripheral }, props));
275
+ const info = this.peripheralCache.find(i => i.address === peripheral.address);
276
+ const connector = info && info.connector ? info.connector : new ble_peripheral_1.default(this, peripheral);
277
+ this.peripheralCache.push(Object.assign({ address: peripheral.address, ts: Date.now(), peripheral, connector }, props));
278
+ }
279
+ getConnector(peripheral) {
280
+ const info = this.peripheralCache.find(i => i.address === peripheral.address);
281
+ if (!info) {
282
+ const connector = new ble_peripheral_1.default(this, peripheral);
283
+ this.peripheralCache.push({ address: peripheral.address, ts: Date.now(), peripheral, connector });
284
+ return connector;
285
+ }
286
+ return info.connector;
287
+ }
288
+ findPeripheral(peripheral) {
289
+ const info = this.peripheralCache.find(i => i.address === peripheral.address || peripheral.address === i.peripheral.address || peripheral.name === i.peripheral.name || peripheral.id === i.peripheral.id);
290
+ return info ? info.peripheral : undefined;
271
291
  }
272
292
  getCharacteristics(peripheral) {
273
293
  return __awaiter(this, void 0, void 0, function* () {
@@ -280,28 +300,17 @@ class BleInterface extends ble_1.BleInterfaceClass {
280
300
  this.addPeripheralToCache(peripheral);
281
301
  chachedPeripheralInfo = this.peripheralCache.find(i => i.address === peripheral.address);
282
302
  }
303
+ const connector = chachedPeripheralInfo.connector;
283
304
  if (!chachedPeripheralInfo.characteristics) {
284
305
  try {
285
306
  chachedPeripheralInfo.state = { isConfigured: false, isLoading: true, isInterrupted: false };
286
- if (chachedPeripheralInfo.peripheral && chachedPeripheralInfo.peripheral.state !== 'connected') {
287
- yield peripheral.connectAsync();
288
- chachedPeripheralInfo.peripheral.state = peripheral.state;
289
- }
290
- else {
291
- peripheral.state = chachedPeripheralInfo.peripheral.state;
292
- }
293
- const res = yield peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
294
- if (!chachedPeripheralInfo.state.isInterrupted) {
295
- this.logEvent({ message: 'characteristic info (+):', info: res.characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
296
- chachedPeripheralInfo.characteristics = res.characteristics;
297
- chachedPeripheralInfo.state = { isConfigured: true, isLoading: false, isInterrupted: false };
298
- characteristics = res.characteristics;
299
- }
300
- else {
301
- this.logEvent({ message: 'characteristic info:', info: 'interrupted' });
302
- chachedPeripheralInfo.state = { isConfigured: false, isLoading: false, isInterrupted: false };
303
- throw new Error('interrupted');
304
- }
307
+ yield connector.connect();
308
+ peripheral.state = connector.getState();
309
+ yield connector.initialize();
310
+ characteristics = connector.getCharachteristics();
311
+ this.logEvent({ message: 'characteristic info (+):', info: characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
312
+ chachedPeripheralInfo.characteristics = characteristics;
313
+ chachedPeripheralInfo.state = { isConfigured: true, isLoading: false, isInterrupted: false };
305
314
  }
306
315
  catch (err) {
307
316
  console.log(err);
@@ -339,6 +348,9 @@ class BleInterface extends ble_1.BleInterfaceClass {
339
348
  createDevice(DeviceClass, peripheral, characteristics) {
340
349
  const C = DeviceClass;
341
350
  const device = new C({ peripheral });
351
+ const existingDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
352
+ if (existingDevice)
353
+ return existingDevice;
342
354
  device.setInterface(this);
343
355
  device.characteristics = characteristics;
344
356
  return device;
@@ -525,12 +537,13 @@ class BleInterface extends ble_1.BleInterfaceClass {
525
537
  const characteristics = yield this.getCharacteristics(peripheral);
526
538
  const DeviceClasses = this.getDeviceClasses(peripheral, { profile });
527
539
  let cntFound = 0;
528
- DeviceClasses.forEach(DeviceClass => {
540
+ DeviceClasses.forEach((DeviceClass) => __awaiter(this, void 0, void 0, function* () {
529
541
  if (!DeviceClass)
530
542
  return;
531
543
  if (scanForDevice && cntFound > 0)
532
544
  return;
533
545
  const d = this.createDevice(DeviceClass, peripheral, characteristics);
546
+ yield d.connect();
534
547
  if (scanForDevice) {
535
548
  if ((id && id !== '' && d.id === id) ||
536
549
  (address && address !== '' && d.address === address) ||
@@ -542,14 +555,14 @@ class BleInterface extends ble_1.BleInterfaceClass {
542
555
  const existing = devicesProcessed.find(device => device.id === d.id && device.getProfile() === d.getProfile());
543
556
  if (!scanForDevice && cntFound > 0 && !existing) {
544
557
  this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
545
- this.devices.push({ device: d, isConnected: peripheral.state === 'connected' });
558
+ this.addDeviceToCache(d, peripheral.state === 'connected');
546
559
  devicesProcessed.push(d);
547
560
  this.emit('device', d);
548
561
  return;
549
562
  }
550
563
  if (scanForDevice && cntFound > 0) {
551
564
  this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
552
- this.devices.push({ device: d, isConnected: peripheral.state === 'connected' });
565
+ this.addDeviceToCache(d, peripheral.state === 'connected');
553
566
  devicesProcessed.push(d);
554
567
  this.emit('device', d);
555
568
  process.nextTick(() => {
@@ -565,7 +578,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
565
578
  });
566
579
  });
567
580
  }
568
- });
581
+ }));
569
582
  });
570
583
  this.logEvent({ message: `${opStr}: start scanning`, requested: scanForDevice ? { name, address, profile } : undefined, timeout });
571
584
  this.peripheralCache.forEach(i => {
@@ -608,19 +621,30 @@ class BleInterface extends ble_1.BleInterfaceClass {
608
621
  return this.scanState.isScanning;
609
622
  }
610
623
  addConnectedDevice(device) {
611
- const existigDevice = this.devices.find(i => i.device.id === device.id);
624
+ const existigDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
612
625
  if (existigDevice) {
613
626
  existigDevice.isConnected = true;
614
627
  return;
615
628
  }
616
629
  this.devices.push({ device, isConnected: true });
617
630
  }
631
+ addDeviceToCache(device, isConnected) {
632
+ const existigDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
633
+ if (existigDevice) {
634
+ return;
635
+ }
636
+ this.devices.push({ device, isConnected });
637
+ }
618
638
  findConnected(device) {
619
639
  const connected = this.devices.find(i => i.device.id === device.id && i.isConnected);
620
640
  if (connected)
621
641
  return connected.device;
622
642
  return undefined;
623
643
  }
644
+ findDeviceInCache(device) {
645
+ const existing = this.devices.find(i => (i.device.id === device.id || i.device.address === device.address || i.device.name === device.name) && i.device.getProfile() === device.profile);
646
+ return existing ? existing.device : undefined;
647
+ }
624
648
  removeConnectedDevice(device) {
625
649
  const existigDevice = this.devices.find(i => i.device.id === device.id);
626
650
  if (existigDevice) {
@@ -0,0 +1,34 @@
1
+ import { BleCharacteristic, BlePeripheral } from "./ble";
2
+ import BleInterface from "./ble-interface";
3
+ export declare type ConnectorState = {
4
+ isConnected: boolean;
5
+ isConnecting: boolean;
6
+ isInitialized: boolean;
7
+ isInitializing: boolean;
8
+ isSubscribing: boolean;
9
+ subscribed?: string[];
10
+ };
11
+ export default class BlePeripheralConnector {
12
+ private state;
13
+ private services;
14
+ private characteristics;
15
+ private ble;
16
+ private peripheral;
17
+ private logger?;
18
+ private emitter;
19
+ constructor(ble: BleInterface, peripheral: BlePeripheral);
20
+ logEvent(event: any): void;
21
+ connect(): Promise<void>;
22
+ reconnect(): Promise<void>;
23
+ onDisconnect(): void;
24
+ initialize(enforce?: boolean): Promise<void>;
25
+ subscribeAll(callback: (characteristicUuid: string, data: any) => void): Promise<string[]>;
26
+ subscribe(characteristicUuid: string): Promise<boolean>;
27
+ onData(characteristicUuid: string, data: any): void;
28
+ on(characteristicUuid: string, callback: (characteristicUuid: string, data: any) => void): void;
29
+ off(characteristicUuid: string, callback: (characteristicUuid: string, data: any) => void): void;
30
+ removeAllListeners(characteristicUuid: string): void;
31
+ getState(): string;
32
+ getCharachteristics(): BleCharacteristic[];
33
+ getServices(): string[];
34
+ }
@@ -0,0 +1,170 @@
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 ble_1 = require("./ble");
16
+ const gd_eventlog_1 = require("gd-eventlog");
17
+ const events_1 = __importDefault(require("events"));
18
+ class BlePeripheralConnector {
19
+ constructor(ble, peripheral) {
20
+ this.ble = ble;
21
+ this.peripheral = peripheral;
22
+ this.emitter = new events_1.default();
23
+ if (!this.peripheral || !this.ble)
24
+ throw new Error('Illegal Arguments');
25
+ this.state = { isConnected: false, isConnecting: false, isInitialized: false, isInitializing: false, isSubscribing: false };
26
+ this.services = undefined;
27
+ this.characteristics = undefined;
28
+ this.logger = new gd_eventlog_1.EventLogger('BLE');
29
+ }
30
+ logEvent(event) {
31
+ if (this.logger) {
32
+ this.logger.logEvent(event);
33
+ }
34
+ if (process.env.BLE_DEBUG) {
35
+ console.log('~~~BLE:', event);
36
+ }
37
+ }
38
+ connect() {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ if (this.state.isConnected)
41
+ return;
42
+ this.logEvent({ message: 'connect', peripheral: this.peripheral.address, state: this.state });
43
+ this.state.isConnecting = true;
44
+ try {
45
+ if (!this.state.isConnected || (this.peripheral && this.peripheral.state !== 'connected')) {
46
+ yield this.peripheral.connectAsync();
47
+ this.peripheral.once('disconnect', this.onDisconnect.bind(this));
48
+ }
49
+ this.state.isConnected = this.peripheral.state === 'connected';
50
+ }
51
+ catch (err) {
52
+ this.logEvent({ message: 'Error', fn: 'connect()', error: err.message });
53
+ }
54
+ this.state.isConnecting = false;
55
+ });
56
+ }
57
+ reconnect() {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ this.connect();
60
+ });
61
+ }
62
+ onDisconnect() {
63
+ this.logEvent({ message: 'onDisconnected', peripheral: this.peripheral.address, state: this.state });
64
+ this.state.isConnected = false;
65
+ this.reconnect();
66
+ }
67
+ initialize(enforce = false) {
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ if (this.state.isInitialized && !enforce)
70
+ return;
71
+ this.logEvent({ message: 'initialize', peripheral: this.peripheral.address, state: this.state, enforce });
72
+ if (this.state.isInitialized && enforce) {
73
+ this.state.isInitialized = false;
74
+ }
75
+ this.state.isInitializing = true;
76
+ this.characteristics = undefined;
77
+ this.services = undefined;
78
+ try {
79
+ const res = yield this.peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
80
+ this.characteristics = res.characteristics;
81
+ this.services = res.services;
82
+ }
83
+ catch (err) {
84
+ }
85
+ this.state.isInitializing = false;
86
+ this.state.isInitialized = this.characteristics !== undefined && this.services !== undefined;
87
+ });
88
+ }
89
+ subscribeAll(callback) {
90
+ return __awaiter(this, void 0, void 0, function* () {
91
+ const cnt = this.characteristics.length;
92
+ this.state.isSubscribing = true;
93
+ const subscribed = [];
94
+ if (!this.state.subscribed)
95
+ this.state.subscribed = [];
96
+ for (let i = 0; i < cnt; i++) {
97
+ try {
98
+ const c = this.characteristics[i];
99
+ const isNotify = c.properties.find(p => p === 'notify');
100
+ if (isNotify && subscribed.find(uuid => uuid === c.uuid) === undefined) {
101
+ c.on('data', (data, _isNotification) => {
102
+ this.onData((0, ble_1.uuid)(c.uuid), data);
103
+ });
104
+ if (callback)
105
+ this.on((0, ble_1.uuid)(c.uuid), callback);
106
+ this.logEvent({ message: 'subscribe', peripheral: this.peripheral.address, characteristic: c.uuid });
107
+ if (this.state.subscribed.find(uuid => uuid === c.uuid) === undefined) {
108
+ try {
109
+ yield this.subscribe(c.uuid);
110
+ subscribed.push(c.uuid);
111
+ this.state.subscribed.push(c.uuid);
112
+ }
113
+ catch (err) {
114
+ this.logEvent({ message: 'cannot subscribe', peripheral: this.peripheral.address, characteristic: c.uuid, error: err.message || err });
115
+ }
116
+ }
117
+ }
118
+ }
119
+ catch (err) {
120
+ console.log('~~~ error', err);
121
+ }
122
+ }
123
+ this.state.isSubscribing = false;
124
+ this.state.subscribed = subscribed;
125
+ return subscribed;
126
+ });
127
+ }
128
+ subscribe(characteristicUuid) {
129
+ return new Promise((resolve, reject) => {
130
+ const characteristic = this.characteristics.find(c => c.uuid === characteristicUuid || (0, ble_1.uuid)(c.uuid) === characteristicUuid);
131
+ if (!characteristic) {
132
+ reject(new Error('Characteristic not found'));
133
+ return;
134
+ }
135
+ characteristic.on('data', (data, _isNotification) => {
136
+ this.onData(characteristicUuid, data);
137
+ });
138
+ characteristic.subscribe((err) => {
139
+ if (err)
140
+ reject(err);
141
+ else
142
+ resolve(true);
143
+ });
144
+ });
145
+ }
146
+ onData(characteristicUuid, data) {
147
+ this.emitter.emit(characteristicUuid, characteristicUuid, data);
148
+ }
149
+ on(characteristicUuid, callback) {
150
+ if (callback)
151
+ this.emitter.on(characteristicUuid, callback);
152
+ }
153
+ off(characteristicUuid, callback) {
154
+ if (callback)
155
+ this.emitter.off(characteristicUuid, callback);
156
+ }
157
+ removeAllListeners(characteristicUuid) {
158
+ this.emitter.removeAllListeners(characteristicUuid);
159
+ }
160
+ getState() {
161
+ return this.peripheral.state;
162
+ }
163
+ getCharachteristics() {
164
+ return this.characteristics;
165
+ }
166
+ getServices() {
167
+ return this.services;
168
+ }
169
+ }
170
+ exports.default = BlePeripheralConnector;
@@ -0,0 +1,24 @@
1
+ import CyclingMode, { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
2
+ import PowerBasedCyclingModeBase from "../modes/power-base";
3
+ import { FmAdapter } from "./fm";
4
+ export declare type ERGEvent = {
5
+ rpmUpdated?: boolean;
6
+ gearUpdated?: boolean;
7
+ starting?: boolean;
8
+ tsStart?: number;
9
+ };
10
+ export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
11
+ prevRequest: UpdateRequest;
12
+ hasBikeUpdate: boolean;
13
+ chain: number[];
14
+ cassette: number[];
15
+ event: ERGEvent;
16
+ constructor(adapter: FmAdapter, props?: any);
17
+ getName(): string;
18
+ getDescription(): string;
19
+ getProperties(): CyclingModeProperty[];
20
+ getProperty(name: string): CyclingModeProperty;
21
+ getBikeInitRequest(): UpdateRequest;
22
+ sendBikeUpdate(request: UpdateRequest): UpdateRequest;
23
+ updateData(bikeData: IncyclistBikeData): any;
24
+ }
@@ -0,0 +1,148 @@
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 CyclingMode_1 = require("../CyclingMode");
7
+ const power_base_1 = __importDefault(require("../modes/power-base"));
8
+ const config = {
9
+ name: "Smart Trainer",
10
+ description: "Calculates speed based on power and slope. Slope is set to the device",
11
+ properties: [
12
+ { key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
13
+ { 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 },
14
+ ]
15
+ };
16
+ class ERGCyclingMode extends power_base_1.default {
17
+ constructor(adapter, props) {
18
+ super(adapter, props);
19
+ this.hasBikeUpdate = false;
20
+ this.event = {};
21
+ this.initLogger('ERGMode');
22
+ }
23
+ getName() {
24
+ return config.name;
25
+ }
26
+ getDescription() {
27
+ return config.description;
28
+ }
29
+ getProperties() {
30
+ return config.properties;
31
+ }
32
+ getProperty(name) {
33
+ return config.properties.find(p => p.name === name);
34
+ }
35
+ getBikeInitRequest() {
36
+ const startPower = this.getSetting('startPower');
37
+ return { targetPower: startPower };
38
+ }
39
+ sendBikeUpdate(request) {
40
+ const getData = () => {
41
+ if (!this.data)
42
+ return {};
43
+ const { pedalRpm, slope, power, speed } = this.data;
44
+ return { pedalRpm, slope, power, speed };
45
+ };
46
+ this.logger.logEvent({ message: "processing update request", request, prev: this.prevRequest, data: getData(), event: this.event });
47
+ let newRequest = {};
48
+ try {
49
+ if (!request || request.reset || Object.keys(request).length === 0) {
50
+ this.prevRequest = {};
51
+ return request || {};
52
+ }
53
+ const prevData = this.data || {};
54
+ if (request.targetPower !== undefined) {
55
+ delete request.slope;
56
+ delete request.refresh;
57
+ }
58
+ if (this.event.starting && request.targetPower === undefined) {
59
+ newRequest.targetPower = this.getSetting('startPower');
60
+ if (this.event.tsStart && Date.now() - this.event.tsStart > 5000) {
61
+ delete this.event.starting;
62
+ delete this.event.tsStart;
63
+ }
64
+ }
65
+ if (request.refresh) {
66
+ delete request.refresh;
67
+ newRequest.targetPower = this.prevRequest.targetPower;
68
+ }
69
+ if (request.slope !== undefined) {
70
+ if (!this.data)
71
+ this.data = {};
72
+ this.data.slope = request.slope;
73
+ }
74
+ if (request.maxPower !== undefined && request.minPower !== undefined && request.maxPower === request.minPower) {
75
+ request.targetPower = request.maxPower;
76
+ }
77
+ if (request.targetPower !== undefined) {
78
+ newRequest.targetPower = request.targetPower;
79
+ }
80
+ delete request.slope;
81
+ if (request.maxPower !== undefined) {
82
+ if (newRequest.targetPower !== undefined && newRequest.targetPower > request.maxPower) {
83
+ newRequest.targetPower = request.maxPower;
84
+ }
85
+ newRequest.maxPower = request.maxPower;
86
+ }
87
+ if (request.minPower !== undefined) {
88
+ if (newRequest.targetPower !== undefined && newRequest.targetPower < request.minPower) {
89
+ newRequest.targetPower = request.minPower;
90
+ }
91
+ newRequest.minPower = request.minPower;
92
+ }
93
+ if (newRequest.targetPower !== undefined && prevData.power !== undefined && newRequest.targetPower === prevData.power) {
94
+ delete newRequest.targetPower;
95
+ }
96
+ this.prevRequest = JSON.parse(JSON.stringify(request));
97
+ }
98
+ catch (err) {
99
+ this.logger.logEvent({ message: "error", fn: 'sendBikeUpdate()', error: err.message || err, stack: err.stack });
100
+ }
101
+ return newRequest;
102
+ }
103
+ updateData(bikeData) {
104
+ const prevData = JSON.parse(JSON.stringify(this.data || {}));
105
+ const prevSpeed = prevData.speed;
106
+ const prevRequest = this.prevRequest || {};
107
+ const data = this.data || {};
108
+ const bikeType = this.getSetting('bikeType').toLowerCase();
109
+ delete this.event.rpmUpdated;
110
+ if (prevData === {} || prevData.speed === undefined || prevData.speed === 0) {
111
+ this.event.starting = true;
112
+ this.event.tsStart = Date.now();
113
+ }
114
+ try {
115
+ const rpm = bikeData.pedalRpm || 0;
116
+ let power = bikeData.power || 0;
117
+ const slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
118
+ const distanceInternal = prevData.distanceInternal || 0;
119
+ if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
120
+ power = 0;
121
+ }
122
+ const m = this.getWeight();
123
+ const t = this.getTimeSinceLastUpdate();
124
+ const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
125
+ data.speed = parseFloat(speed.toFixed(1));
126
+ data.power = Math.round(power);
127
+ data.distanceInternal = Math.round(distanceInternal + distance);
128
+ data.slope = slope;
129
+ data.pedalRpm = rpm;
130
+ if (data.time !== undefined && !(this.event.starting && !bikeData.pedalRpm))
131
+ data.time += t;
132
+ else
133
+ data.time = 0;
134
+ data.heartrate = bikeData.heartrate;
135
+ data.isPedalling = bikeData.isPedalling;
136
+ if (rpm && rpm !== prevData.pedalRpm) {
137
+ this.event.rpmUpdated = true;
138
+ }
139
+ }
140
+ catch (err) {
141
+ this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
142
+ }
143
+ this.logger.logEvent({ message: "updateData result", data, bikeData, prevRequest, prevSpeed });
144
+ this.data = data;
145
+ return data;
146
+ }
147
+ }
148
+ exports.default = ERGCyclingMode;
package/lib/ble/ble.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  import EventEmitter from "events";
4
+ import BlePeripheralConnector from "./ble-peripheral";
4
5
  export declare type ConnectProps = {
5
6
  timeout?: number;
6
7
  };
@@ -77,6 +78,12 @@ export declare abstract class BleInterfaceClass extends EventEmitter {
77
78
  abstract addConnectedDevice(device: BleDeviceClass): void;
78
79
  abstract removeConnectedDevice(device: BleDeviceClass): void;
79
80
  abstract findConnected(device: BleDeviceClass | BlePeripheral): BleDeviceClass;
81
+ abstract getConnector(peripheral: BlePeripheral): BlePeripheralConnector;
82
+ abstract findPeripheral(peripheral: BlePeripheral | {
83
+ id?: string;
84
+ address?: string;
85
+ name?: string;
86
+ }): BlePeripheral;
80
87
  getBinding(): BleBinding;
81
88
  setBinding(binding: BleBinding): void;
82
89
  }
@@ -89,6 +96,8 @@ export interface BlePeripheral extends EventEmitter, BleDeviceIdentifier {
89
96
  discoverSomeServicesAndCharacteristicsAsync(serviceUUIDs: string[], characteristicUUIDs: string[]): Promise<any>;
90
97
  }
91
98
  export interface BleCharacteristic extends EventEmitter {
99
+ uuid: string;
100
+ properties: string[];
92
101
  subscribe(callback: (err: Error) => void): void;
93
102
  read(callback: (err: Error, data: Buffer) => void): void;
94
103
  write(data: Buffer, withoutResponse: boolean, callback?: (err: Error) => void): void;
package/lib/ble/fm.d.ts CHANGED
@@ -41,8 +41,11 @@ export default class BleFitnessMachineDevice extends BleDevice {
41
41
  static characteristics: string[];
42
42
  data: IndoorBikeData;
43
43
  features: IndoorBikeFeatures;
44
+ hasControl: boolean;
45
+ isCPSubscribed: boolean;
44
46
  constructor(props?: any);
45
47
  init(): Promise<boolean>;
48
+ onDisconnect(): void;
46
49
  getProfile(): string;
47
50
  getServiceUUids(): string[];
48
51
  isBike(): boolean;
@@ -52,7 +55,8 @@ export default class BleFitnessMachineDevice extends BleDevice {
52
55
  parseIndoorBikeData(_data: Uint8Array): IndoorBikeData;
53
56
  getFitnessMachineFeatures(): Promise<IndoorBikeFeatures>;
54
57
  onData(characteristic: string, data: Buffer): void;
55
- write(characteristic: any, data: any): Promise<boolean>;
58
+ requestControl(): Promise<boolean>;
59
+ setTargetPower(power: number): Promise<void>;
56
60
  reset(): void;
57
61
  }
58
62
  export declare class FmAdapter extends DeviceAdapter {
@@ -69,6 +73,7 @@ export declare class FmAdapter extends DeviceAdapter {
69
73
  isBike(): boolean;
70
74
  isHrm(): boolean;
71
75
  isPower(): boolean;
76
+ isSame(device: DeviceAdapter): boolean;
72
77
  getProfile(): string;
73
78
  getName(): string;
74
79
  getDisplayName(): string;
@@ -82,6 +87,7 @@ export declare class FmAdapter extends DeviceAdapter {
82
87
  transformData(bikeData: IncyclistBikeData): DeviceData;
83
88
  start(props?: any): Promise<any>;
84
89
  stop(): Promise<boolean>;
90
+ sendUpdate(request: any): Promise<void>;
85
91
  pause(): Promise<boolean>;
86
92
  resume(): Promise<boolean>;
87
93
  }