incyclist-devices 2.1.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/lib/antv2/base/adapter.d.ts +13 -7
  2. package/lib/antv2/base/adapter.js +162 -89
  3. package/lib/antv2/base/interface.d.ts +46 -0
  4. package/lib/antv2/base/interface.js +343 -0
  5. package/lib/antv2/factories/adapter-factory.d.ts +4 -4
  6. package/lib/antv2/factories/adapter-factory.js +17 -9
  7. package/lib/antv2/fe/adapter.d.ts +7 -11
  8. package/lib/antv2/fe/adapter.js +50 -145
  9. package/lib/antv2/index.d.ts +1 -1
  10. package/lib/antv2/index.js +2 -2
  11. package/lib/antv2/types.d.ts +9 -0
  12. package/lib/base/adpater.js +10 -2
  13. package/lib/ble/adapter-factory.d.ts +9 -8
  14. package/lib/ble/base/adapter.d.ts +13 -10
  15. package/lib/ble/base/adapter.js +9 -8
  16. package/lib/ble/base/types.d.ts +2 -0
  17. package/lib/ble/base/types.js +2 -0
  18. package/lib/ble/ble-interface.d.ts +0 -4
  19. package/lib/ble/ble-interface.js +0 -11
  20. package/lib/ble/cp/adapter.d.ts +5 -3
  21. package/lib/ble/cp/adapter.js +1 -7
  22. package/lib/ble/elite/adapter.d.ts +5 -3
  23. package/lib/ble/elite/adapter.js +1 -7
  24. package/lib/ble/fm/adapter.d.ts +4 -3
  25. package/lib/ble/fm/adapter.js +1 -6
  26. package/lib/ble/hr/adapter.d.ts +4 -2
  27. package/lib/ble/hr/adapter.js +1 -3
  28. package/lib/ble/peripheral-cache.d.ts +3 -1
  29. package/lib/ble/tacx/adapter.d.ts +3 -1
  30. package/lib/ble/tacx/adapter.js +1 -0
  31. package/lib/ble/wahoo/adapter.d.ts +3 -1
  32. package/lib/ble/wahoo/adapter.js +1 -0
  33. package/lib/factories/interfaces.d.ts +1 -1
  34. package/lib/factories/interfaces.js +2 -2
  35. package/lib/modes/power-base.js +1 -4
  36. package/lib/serial/base/serial-interface.js +1 -1
  37. package/lib/serial/base/serial-scanner.js +2 -2
  38. package/lib/serial/daum/classic/mock.js +1 -1
  39. package/lib/utils/utils.d.ts +1 -0
  40. package/lib/utils/utils.js +18 -1
  41. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  /// <reference types="node" />
2
2
  import { IChannel, ISensor, Profile } from 'incyclist-ant-plus';
3
- import AntInterface from './ant-interface';
3
+ import AntInterface from './interface';
4
4
  import IncyclistDevice from '../../base/adpater';
5
- import { AntDeviceProperties, AntDeviceSettings, LegacyProfile, BaseDeviceData } from '../types';
5
+ import { AntDeviceProperties, AntDeviceSettings, LegacyProfile, BaseDeviceData, AdapterStartStatus } from '../types';
6
6
  import { IAdapter, IncyclistAdapterData, IncyclistBikeData } from '../../types';
7
7
  export default class AntAdapter<TDeviceData extends BaseDeviceData> extends IncyclistDevice<AntDeviceProperties> {
8
8
  sensor: ISensor;
@@ -18,17 +18,20 @@ export default class AntAdapter<TDeviceData extends BaseDeviceData> extends Incy
18
18
  weight?: number;
19
19
  };
20
20
  onDataFn: (data: IncyclistAdapterData) => void;
21
- startupRetryPause: number;
22
21
  protected ivDataTimeout: NodeJS.Timeout;
23
22
  protected lastDataTS: number;
24
23
  protected dataMsgCount: number;
25
24
  protected ivWaitForData: NodeJS.Timeout;
26
25
  protected promiseWaitForData: Promise<boolean>;
26
+ protected sensorConnected: boolean;
27
+ protected startStatus: AdapterStartStatus;
28
+ protected startupRetryPause: number;
27
29
  constructor(settings: AntDeviceSettings, props?: AntDeviceProperties);
28
30
  getProfileName(): Profile;
29
31
  getLegacyProfileName(): LegacyProfile;
30
32
  createSensor(settings: AntDeviceSettings): ISensor;
31
33
  isEqual(settings: AntDeviceSettings): boolean;
34
+ getDefaultReconnectDelay(): number;
32
35
  connect(): Promise<boolean>;
33
36
  close(): Promise<boolean>;
34
37
  resetData(): void;
@@ -48,15 +51,18 @@ export default class AntAdapter<TDeviceData extends BaseDeviceData> extends Incy
48
51
  getInterface(): string;
49
52
  getProfile(): Profile;
50
53
  getLogData(data: any, excludeList: any): any;
51
- triggerTimeoutCheck(): void;
52
- startDataTimeoutCheck(): void;
53
- stopDataTimeoutCheck(): void;
54
54
  check(): Promise<boolean>;
55
55
  checkCapabilities(): Promise<void>;
56
56
  initControl(): Promise<void>;
57
57
  getDefaultStartupTimeout(): number;
58
- sendUpdate(request: any): void;
58
+ startPreChecks(props: AntDeviceProperties): Promise<'done' | 'connected' | 'connection-failed'>;
59
+ resetStartStatus(): void;
60
+ isStartSuccess(): boolean;
61
+ reportStartStatus(): boolean;
62
+ protected waitForInitialData(startupTimeout: any): Promise<void>;
63
+ protected initSensor(props: any): Promise<boolean>;
59
64
  start(props?: AntDeviceProperties): Promise<boolean>;
60
65
  stop(): Promise<boolean>;
61
66
  startSensor(): Promise<boolean>;
67
+ stopSensor(): Promise<void>;
62
68
  }
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const ant_interface_1 = __importDefault(require("./ant-interface"));
15
+ const interface_1 = __importDefault(require("./interface"));
16
16
  const adpater_1 = __importDefault(require("../../base/adpater"));
17
17
  const types_1 = require("../types");
18
18
  const types_2 = require("../../types");
@@ -22,6 +22,7 @@ const consts_1 = require("../consts");
22
22
  const sensor_factory_1 = __importDefault(require("../factories/sensor-factory"));
23
23
  const gd_eventlog_1 = require("gd-eventlog");
24
24
  const INTERFACE_NAME = 'ant';
25
+ const MAX_RETRIES = 3;
25
26
  class AntAdapter extends adpater_1.default {
26
27
  constructor(settings, props) {
27
28
  super(settings, props);
@@ -37,6 +38,7 @@ class AntAdapter extends adpater_1.default {
37
38
  if (this.settings.interface !== 'ant')
38
39
  throw new Error('Incorrect interface');
39
40
  this.sensor = this.createSensor(settings);
41
+ this.sensorConnected = false;
40
42
  this.deviceData = {
41
43
  DeviceID: Number(settings.deviceID)
42
44
  };
@@ -45,7 +47,7 @@ class AntAdapter extends adpater_1.default {
45
47
  this.logger = new gd_eventlog_1.EventLogger(`Ant+${profile}`);
46
48
  this.updateFrequency = consts_1.DEFAULT_UPDATE_FREQUENCY;
47
49
  this.channel = undefined;
48
- this.ant = ant_interface_1.default.getInstance();
50
+ this.ant = interface_1.default.getInstance();
49
51
  }
50
52
  getProfileName() {
51
53
  const C = this.constructor;
@@ -66,9 +68,12 @@ class AntAdapter extends adpater_1.default {
66
68
  return false;
67
69
  return true;
68
70
  }
71
+ getDefaultReconnectDelay() {
72
+ return this.startupRetryPause;
73
+ }
69
74
  connect() {
70
75
  return __awaiter(this, void 0, void 0, function* () {
71
- const connected = yield ant_interface_1.default.getInstance().connect();
76
+ const connected = yield interface_1.default.getInstance().connect();
72
77
  return connected;
73
78
  });
74
79
  }
@@ -113,7 +118,6 @@ class AntAdapter extends adpater_1.default {
113
118
  }
114
119
  if (!this.started || this.isStopped())
115
120
  return;
116
- this.triggerTimeoutCheck();
117
121
  if (!this.canEmitData())
118
122
  return;
119
123
  const logData = this.getLogData(deviceData, ['PairedDevices', 'RawData']);
@@ -158,16 +162,13 @@ class AntAdapter extends adpater_1.default {
158
162
  }
159
163
  const tsStart = Date.now();
160
164
  if (this.promiseWaitForData) {
165
+ let hasData = false;
161
166
  try {
162
- const hasData = yield (0, utils_1.runWithTimeout)(this.promiseWaitForData, timeout);
163
- if (hasData || Date.now() - tsStart > timeout)
164
- return hasData;
165
- }
166
- catch (_a) {
167
- timeout -= (Date.now() - tsStart);
168
- if (timeout < 0)
169
- return false;
167
+ hasData = yield this.promiseWaitForData;
170
168
  }
169
+ catch (_a) { }
170
+ if (hasData || Date.now() > tsStart + timeout)
171
+ return hasData;
171
172
  }
172
173
  try {
173
174
  this.promiseWaitForData = (0, utils_1.runWithTimeout)(this._wait(), timeout);
@@ -187,10 +188,11 @@ class AntAdapter extends adpater_1.default {
187
188
  return id.toString();
188
189
  }
189
190
  getName() {
191
+ var _a;
190
192
  if (this.settings.name)
191
193
  return this.settings.name;
192
- const deviceID = this.sensor.getDeviceID();
193
- const profile = this.sensor.getProfile();
194
+ const deviceID = this.getID();
195
+ const profile = (_a = this.sensor) === null || _a === void 0 ? void 0 : _a.getProfile();
194
196
  return `Ant+${profile} ${deviceID}`;
195
197
  }
196
198
  getUniqueName() {
@@ -226,30 +228,6 @@ class AntAdapter extends adpater_1.default {
226
228
  });
227
229
  return logData;
228
230
  }
229
- triggerTimeoutCheck() {
230
- if (!this.ivDataTimeout && this.dataMsgCount > 0) {
231
- this.startDataTimeoutCheck();
232
- }
233
- }
234
- startDataTimeoutCheck() {
235
- if (this.ivDataTimeout)
236
- return;
237
- this.ivDataTimeout = setInterval(() => {
238
- if (!this.lastDataTS)
239
- return;
240
- if (this.lastDataTS + consts_1.NO_DATA_TIMEOUT < Date.now()) {
241
- this.emit('disconnected', Date.now() - this.lastDataTS);
242
- }
243
- }, 1000);
244
- }
245
- stopDataTimeoutCheck() {
246
- if (!this.ivDataTimeout)
247
- return;
248
- clearInterval(this.ivDataTimeout);
249
- this.ivDataTimeout = undefined;
250
- this.lastDataTS = undefined;
251
- this.dataMsgCount = 0;
252
- }
253
231
  check() {
254
232
  return __awaiter(this, void 0, void 0, function* () {
255
233
  try {
@@ -273,81 +251,165 @@ class AntAdapter extends adpater_1.default {
273
251
  getDefaultStartupTimeout() {
274
252
  return 20000;
275
253
  }
276
- sendUpdate(request) {
277
- if (!this.isControllable())
278
- return;
279
- if (this.isPaused() || this.isStopped())
280
- return;
281
- if (!this.hasCapability(types_2.IncyclistCapability.Control))
282
- this.getCyclingMode().sendBikeUpdate(request);
283
- else
284
- throw new Error('method not implemented');
285
- }
286
- start(props = {}) {
254
+ startPreChecks(props) {
287
255
  return __awaiter(this, void 0, void 0, function* () {
288
- if (this.started && !this.stopped) {
289
- if (this.paused)
290
- this.resume();
291
- return true;
292
- }
256
+ const wasPaused = this.paused;
257
+ const wasStopped = this.stopped;
293
258
  this.stopped = false;
259
+ if (wasPaused)
260
+ this.resume();
261
+ if (this.started && !wasPaused && !wasStopped) {
262
+ return 'done';
263
+ }
264
+ if (this.started && wasPaused) {
265
+ return 'done';
266
+ }
294
267
  const connected = yield this.connect();
295
268
  if (!connected)
269
+ return 'connection-failed';
270
+ return 'connected';
271
+ });
272
+ }
273
+ resetStartStatus() {
274
+ this.startStatus = { timeout: false, hasData: false, sensorStarted: false };
275
+ }
276
+ isStartSuccess() {
277
+ const { timeout, hasData, sensorStarted, controlInitialized, userInitialized, interrupted } = this.startStatus;
278
+ if (interrupted)
279
+ return false;
280
+ if (this.hasCapability(types_2.IncyclistCapability.Control))
281
+ return sensorStarted && hasData && userInitialized && controlInitialized && !timeout;
282
+ else
283
+ return sensorStarted && hasData && !timeout;
284
+ }
285
+ reportStartStatus() {
286
+ const success = this.isStartSuccess();
287
+ if (success) {
288
+ this.logEvent({ message: 'start device success', device: this.getName() });
289
+ this.started = true;
290
+ this.paused = false;
291
+ return true;
292
+ }
293
+ else {
294
+ this.started = false;
295
+ const { sensorStarted, hasData, interrupted } = this.startStatus;
296
+ if (interrupted)
297
+ return;
298
+ if (!sensorStarted) {
299
+ this.logEvent({ message: 'start device failed', device: this.getName(), reason: 'could not connect' });
300
+ throw new Error('could not start device, reason:could not connect');
301
+ }
302
+ else if (!hasData) {
303
+ this.logEvent({ message: 'start device failed', device: this.getName(), reason: 'no data received' });
304
+ throw new Error('could not start device, reason:no data received');
305
+ }
306
+ else {
307
+ this.logEvent({ message: 'start device failed', device: this.getName(), reason: 'could not send FE commands' });
308
+ throw new Error('could not start device, reason:could not send FE commands');
309
+ }
310
+ }
311
+ }
312
+ waitForInitialData(startupTimeout) {
313
+ return __awaiter(this, void 0, void 0, function* () {
314
+ const { sensorStarted, hasData, timeout } = this.startStatus;
315
+ if ((sensorStarted && hasData) || !sensorStarted || timeout)
316
+ return;
317
+ this.logEvent({ message: 'wait for sensor data', device: this.getName() });
318
+ this.startStatus.hasData = yield this.waitForData(startupTimeout);
319
+ if (this.startStatus.hasData)
320
+ this.logEvent({ message: 'sensor data received', device: this.getName() });
321
+ });
322
+ }
323
+ initSensor(props) {
324
+ return __awaiter(this, void 0, void 0, function* () {
325
+ this.startStatus.sensorStarted = this.sensorConnected;
326
+ if (this.startStatus.sensorStarted || this.startStatus.sensorStarted)
327
+ return;
328
+ this.logEvent({ message: 'start sensor', device: this.getName(), props });
329
+ try {
330
+ this.sensorConnected = yield this.startSensor();
331
+ if (this.sensorConnected) {
332
+ this.logEvent({ message: 'sensor started', props });
333
+ this.startStatus.sensorStarted = true;
334
+ }
335
+ }
336
+ catch (err) {
337
+ this.logEvent({ message: 'start sensor failed', device: this.getName(), reason: err.message, props });
338
+ }
339
+ });
340
+ }
341
+ start(props = {}) {
342
+ return __awaiter(this, void 0, void 0, function* () {
343
+ const preCheckResult = yield this.startPreChecks(props);
344
+ if (preCheckResult === 'done')
345
+ return this.started;
346
+ if (preCheckResult === 'connection-failed')
296
347
  throw new Error(`could not start device, reason:could not connect`);
297
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
298
- this.resetData();
299
- this.stopped = false;
300
- this.resume();
301
- const { startupTimeout = this.getDefaultStartupTimeout() } = props;
302
- let to = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
348
+ this.logEvent({ message: 'starting device', device: this.getName(), props, isStarted: this.started });
349
+ this.resetStartStatus();
350
+ this.resetData();
351
+ const { startupTimeout = this.getDefaultStartupTimeout() } = props || {};
352
+ const retryDelay = this.getDefaultReconnectDelay();
353
+ const totalTimeout = Math.min(startupTimeout + 10000, (startupTimeout + retryDelay) * MAX_RETRIES);
354
+ const doStart = () => __awaiter(this, void 0, void 0, function* () {
355
+ let success = false;
356
+ let retry = 0;
357
+ while (!success && retry < MAX_RETRIES && !this.startStatus.timeout && !this.startStatus.interrupted) {
303
358
  try {
304
- yield this.stop();
359
+ retry++;
360
+ yield this.initSensor(props);
361
+ yield this.waitForInitialData(startupTimeout);
362
+ yield this.checkCapabilities();
363
+ if (this.hasCapability(types_2.IncyclistCapability.Control))
364
+ yield this.initControl();
365
+ if (!this.startStatus.hasData) {
366
+ yield this.stopSensor();
367
+ yield (0, utils_1.sleep)(retryDelay);
368
+ continue;
369
+ }
370
+ success = this.isStartSuccess();
371
+ }
372
+ catch (err) {
373
+ this.logEvent({ message: 'error', fn: 'start#doStart', device: this.getName(), error: err.message, stack: err.stack });
305
374
  }
306
- catch (_a) { }
307
- this.started = false;
308
- reject(new Error(`could not start device, reason:timeout`));
309
- }), startupTimeout);
310
- let started = false;
311
- do {
312
- started = yield this.ant.startSensor(this.sensor, (data) => {
313
- this.onDeviceData(data);
314
- });
315
- if (!started)
316
- yield (0, utils_1.sleep)(this.startupRetryPause);
317
- } while (!started);
318
- try {
319
- this.logEvent({ message: 'wait for sensor data', });
320
- const hasData = yield this.waitForData(startupTimeout - 100);
321
- if (!hasData)
322
- throw new Error('timeout');
323
- this.logEvent({ message: 'sensor data received', });
324
- yield this.checkCapabilities();
325
- if (this.hasCapability(types_2.IncyclistCapability.Control))
326
- yield this.initControl();
327
- this.started = true;
328
- if (to)
329
- clearTimeout(to);
330
- resolve(true);
331
375
  }
332
- catch (err) {
376
+ this.reportStartStatus();
377
+ return this.started;
378
+ });
379
+ try {
380
+ yield (0, utils_1.runWithTimeout)(doStart(), totalTimeout);
381
+ }
382
+ catch (err) {
383
+ if (err.message === 'Timeout') {
384
+ this.started = false;
385
+ this.startStatus.timeout = true;
386
+ this.logEvent({ message: 'start device failed', device: this.getName(), reason: 'timeout' });
387
+ throw new Error(`could not start device, reason:timeout`);
333
388
  }
334
- }));
389
+ throw err;
390
+ }
391
+ return true;
335
392
  });
336
393
  }
337
394
  stop() {
338
395
  return __awaiter(this, void 0, void 0, function* () {
339
396
  let stopped;
397
+ this.logger.logEvent({ message: 'stopping device', device: this.getName() });
398
+ this.promiseWaitForData = null;
399
+ if (this.startStatus)
400
+ this.startStatus.interrupted = true;
340
401
  try {
341
- this.stopDataTimeoutCheck();
342
402
  stopped = yield this.ant.stopSensor(this.sensor);
343
403
  }
344
404
  catch (err) {
345
405
  this.logEvent({ message: 'stop sensor failed', reason: err.message });
346
406
  }
407
+ this.sensorConnected = false;
347
408
  this.started = false;
348
409
  this.stopped = true;
349
410
  this.paused = false;
350
411
  this.removeAllListeners();
412
+ this.logEvent({ message: 'stopping device finished', device: this.getName(), stopped });
351
413
  return stopped;
352
414
  });
353
415
  }
@@ -356,5 +418,16 @@ class AntAdapter extends adpater_1.default {
356
418
  return this.ant.startSensor(this.sensor, this.onDeviceData.bind(this));
357
419
  });
358
420
  }
421
+ stopSensor() {
422
+ return __awaiter(this, void 0, void 0, function* () {
423
+ if (!this.sensorConnected)
424
+ return;
425
+ try {
426
+ yield yield this.ant.stopSensor(this.sensor);
427
+ this.sensorConnected = false;
428
+ }
429
+ catch (_a) { }
430
+ });
431
+ }
359
432
  }
360
433
  exports.default = AntAdapter;
@@ -0,0 +1,46 @@
1
+ /// <reference types="node" />
2
+ import EventEmitter from "events";
3
+ import { EventLogger } from "gd-eventlog";
4
+ import { IAntDevice, IChannel, ISensor } from "incyclist-ant-plus";
5
+ import { AntDeviceSettings, AntScanProps, AntInterfaceProps } from "../types";
6
+ import { IncyclistInterface } from "../../types";
7
+ import AntDeviceBinding from "./binding";
8
+ export default class AntInterface extends EventEmitter implements IncyclistInterface {
9
+ static _instance: AntInterface;
10
+ static INTERFACE_NAME: string;
11
+ static getInstance(props?: AntInterfaceProps): AntInterface;
12
+ static hasInstance(): boolean;
13
+ protected logger: EventLogger;
14
+ protected device: IAntDevice;
15
+ protected Binding: typeof AntDeviceBinding;
16
+ protected connected: boolean;
17
+ protected connectPromise: Promise<boolean>;
18
+ protected scanPromise: Promise<AntDeviceSettings[]>;
19
+ protected activeScan: {
20
+ emitter: EventEmitter;
21
+ channel?: IChannel;
22
+ };
23
+ protected props: AntInterfaceProps;
24
+ protected logEnabled: boolean;
25
+ constructor(props: AntInterfaceProps);
26
+ getName(): string;
27
+ getBinding(): typeof AntDeviceBinding;
28
+ setBinding(binding: typeof AntDeviceBinding): void;
29
+ getLogger(): EventLogger;
30
+ setLogger(logger: EventLogger): void;
31
+ enableLogging(): void;
32
+ disableLogging(): void;
33
+ logEvent(event: any): void;
34
+ isConnected(): boolean;
35
+ connect(): Promise<boolean>;
36
+ disconnect(): Promise<boolean>;
37
+ onError(profile: any, error: any): void;
38
+ onData(profile: any, id: any, data: any, tag: any): void;
39
+ getReconnectPause(): number;
40
+ scannerWaitForConnection(): Promise<void>;
41
+ scan(props?: AntScanProps): Promise<AntDeviceSettings[]>;
42
+ isScanning(): boolean;
43
+ stopScan(): Promise<boolean>;
44
+ startSensor(sensor: ISensor, onDeviceData: (data: any) => void): Promise<boolean>;
45
+ stopSensor(sensor: ISensor): Promise<boolean>;
46
+ }