incyclist-devices 3.0.5 → 3.0.7

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 (66) hide show
  1. package/lib/cjs/antv2/base/adapter.js +13 -7
  2. package/lib/cjs/antv2/base/interface.js +4 -4
  3. package/lib/cjs/base/adpater.js +2 -5
  4. package/lib/cjs/ble/base/adapter.js +14 -2
  5. package/lib/cjs/ble/base/interface.js +68 -36
  6. package/lib/cjs/ble/base/peripheral.js +25 -9
  7. package/lib/cjs/ble/base/sensor.js +40 -6
  8. package/lib/cjs/ble/bindings/linux.js +2 -5
  9. package/lib/cjs/ble/bindings/mock.js +3 -6
  10. package/lib/cjs/ble/bindings/types.js +2 -5
  11. package/lib/cjs/ble/fm/sensor.js +11 -0
  12. package/lib/cjs/direct-connect/base/interface.js +4 -6
  13. package/lib/cjs/direct-connect/base/peripheral.js +17 -3
  14. package/lib/cjs/serial/base/serial-interface.js +9 -9
  15. package/lib/cjs/serial/base/serial-provider.js +113 -0
  16. package/lib/cjs/serial/daum/DaumAdapter.js +3 -3
  17. package/lib/cjs/serial/daum/classic/mock.js +2 -2
  18. package/lib/cjs/serial/index.js +3 -3
  19. package/lib/cjs/serial/kettler/comms.js +2 -5
  20. package/lib/cjs/utils/task.js +2 -5
  21. package/lib/esm/antv2/base/adapter.js +12 -6
  22. package/lib/esm/antv2/base/interface.js +2 -2
  23. package/lib/esm/base/adpater.js +1 -1
  24. package/lib/esm/ble/base/adapter.js +14 -2
  25. package/lib/esm/ble/base/interface.js +66 -31
  26. package/lib/esm/ble/base/peripheral.js +25 -9
  27. package/lib/esm/ble/base/sensor.js +40 -6
  28. package/lib/esm/ble/bindings/linux.js +1 -1
  29. package/lib/esm/ble/bindings/mock.js +1 -1
  30. package/lib/esm/ble/bindings/types.js +1 -1
  31. package/lib/esm/ble/fm/sensor.js +11 -0
  32. package/lib/esm/direct-connect/base/interface.js +2 -1
  33. package/lib/esm/direct-connect/base/peripheral.js +16 -2
  34. package/lib/esm/serial/base/serial-interface.js +2 -2
  35. package/lib/esm/serial/base/serial-provider.js +75 -0
  36. package/lib/esm/serial/base/serialport.js +0 -2
  37. package/lib/esm/serial/daum/DaumAdapter.js +1 -1
  38. package/lib/esm/serial/daum/classic/mock.js +1 -1
  39. package/lib/esm/serial/index.js +1 -1
  40. package/lib/esm/serial/kettler/comms.js +1 -1
  41. package/lib/esm/utils/task.js +1 -1
  42. package/lib/types/antv2/base/adapter.d.ts +2 -2
  43. package/lib/types/antv2/base/binding.d.ts +1 -1
  44. package/lib/types/antv2/base/interface.d.ts +2 -2
  45. package/lib/types/antv2/types.d.ts +1 -1
  46. package/lib/types/base/adpater.d.ts +1 -1
  47. package/lib/types/ble/base/interface.d.ts +4 -2
  48. package/lib/types/ble/base/peripheral.d.ts +2 -2
  49. package/lib/types/ble/base/sensor.d.ts +9 -3
  50. package/lib/types/ble/bindings/linux.d.ts +1 -1
  51. package/lib/types/ble/bindings/types.d.ts +1 -1
  52. package/lib/types/ble/fm/sensor.d.ts +2 -1
  53. package/lib/types/ble/types.d.ts +1 -1
  54. package/lib/types/ble/zwift/play/sensor.d.ts +1 -1
  55. package/lib/types/direct-connect/base/interface.d.ts +1 -1
  56. package/lib/types/direct-connect/base/peripheral.d.ts +2 -1
  57. package/lib/types/direct-connect/bindings/types.d.ts +1 -1
  58. package/lib/types/serial/base/serial-interface.d.ts +1 -1
  59. package/lib/types/serial/base/serial-provider.d.ts +16 -0
  60. package/lib/types/serial/daum/DaumAdapter.d.ts +1 -1
  61. package/lib/types/serial/index.d.ts +1 -1
  62. package/lib/types/serial/kettler/comms.d.ts +1 -1
  63. package/lib/types/types/adapter.d.ts +1 -1
  64. package/lib/types/types/interface.d.ts +1 -1
  65. package/lib/types/utils/task.d.ts +1 -1
  66. package/package.json +1 -1
@@ -12,7 +12,7 @@ const utils_js_2 = require("../utils.js");
12
12
  const consts_js_1 = require("../consts.js");
13
13
  const sensor_factory_js_1 = __importDefault(require("../factories/sensor-factory.js"));
14
14
  const gd_eventlog_1 = require("gd-eventlog");
15
- const node_events_1 = __importDefault(require("node:events"));
15
+ const node_events_1 = require("node:events");
16
16
  const INTERFACE_NAME = 'ant';
17
17
  const MAX_RETRIES = 3;
18
18
  class AntAdapter extends adpater_js_1.default {
@@ -30,7 +30,7 @@ class AntAdapter extends adpater_js_1.default {
30
30
  sensorConnected;
31
31
  startStatus;
32
32
  startupRetryPause = 1000;
33
- internalEmitter = new node_events_1.default();
33
+ internalEmitter = new node_events_1.EventEmitter();
34
34
  constructor(settings, props) {
35
35
  super(settings, props);
36
36
  const profile = this.getProfileName();
@@ -334,21 +334,27 @@ class AntAdapter extends adpater_js_1.default {
334
334
  async initSensor(props) {
335
335
  this.startStatus.sensorStarted = this.sensorConnected;
336
336
  if (this.startStatus.sensorStarted)
337
- return;
338
- this.logEvent({ message: 'start sensor', device: this.getName(), props });
337
+ return true;
338
+ const logProps = structuredClone(props ?? {});
339
+ logProps.routeName = logProps?.route?.title;
340
+ logProps.routeId = logProps?.route?.id;
341
+ delete logProps.route;
342
+ this.logEvent({ message: 'start sensor', device: this.getName(), props: logProps });
339
343
  try {
340
344
  this.sensorConnected = await this.startSensor();
341
345
  if (this.sensorConnected) {
342
- this.logEvent({ message: 'sensor started', device: this.getName(), channel: this.sensor?.getChannel()?.getChannelNo(), props });
346
+ this.logEvent({ message: 'sensor started', device: this.getName(), channelNo: this.sensor?.getChannel()?.getChannelNo(), props: logProps });
343
347
  this.startStatus.sensorStarted = true;
348
+ return true;
344
349
  }
345
350
  else {
346
- this.logEvent({ message: 'start sensor failed', device: this.getName(), reason: 'unknown', props });
351
+ this.logEvent({ message: 'start sensor failed', device: this.getName(), reason: 'unknown', props: logProps });
347
352
  }
348
353
  }
349
354
  catch (err) {
350
- this.logEvent({ message: 'start sensor failed', device: this.getName(), reason: err.message, props });
355
+ this.logEvent({ message: 'start sensor failed', device: this.getName(), reason: err.message, props: logProps });
351
356
  }
357
+ return false;
352
358
  }
353
359
  getLogProps(startProps) {
354
360
  const { user, userWeight, bikeWeight, startupTimeout, automaticReconnect } = startProps ?? {};
@@ -3,12 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const node_events_1 = __importDefault(require("node:events"));
6
+ const node_events_1 = require("node:events");
7
7
  const gd_eventlog_1 = require("gd-eventlog");
8
8
  const sensor_factory_js_1 = __importDefault(require("../factories/sensor-factory.js"));
9
9
  const utils_js_1 = require("../../utils/utils.js");
10
10
  const adapter_factory_js_1 = __importDefault(require("../factories/adapter-factory.js"));
11
- class AntInterface extends node_events_1.default {
11
+ class AntInterface extends node_events_1.EventEmitter {
12
12
  static _instance = undefined;
13
13
  static INTERFACE_NAME = 'ant';
14
14
  static getInstance(props = {}) {
@@ -178,7 +178,7 @@ class AntInterface extends node_events_1.default {
178
178
  if (this.isScanning()) {
179
179
  return await this.scanPromise;
180
180
  }
181
- this.activeScan = { emitter: new node_events_1.default() };
181
+ this.activeScan = { emitter: new node_events_1.EventEmitter() };
182
182
  const detected = [];
183
183
  const _scan = () => new Promise(async (done) => {
184
184
  const onDetected = (profile, deviceID) => {
@@ -340,7 +340,7 @@ class AntInterface extends node_events_1.default {
340
340
  this.logEvent({ message: 'could not start sensor' });
341
341
  channel.off('data', onData);
342
342
  }
343
- this.logEvent({ message: 'sensor started', channel: sensor.getChannel()?.getChannelNo(), profile: sensor.getProfile(), deviceID: sensor.getDeviceID() });
343
+ this.logEvent({ message: 'sensor started', channelNo: sensor.getChannel()?.getChannelNo(), profile: sensor.getProfile(), deviceID: sensor.getDeviceID() });
344
344
  return started;
345
345
  }
346
346
  catch (err) {
@@ -1,13 +1,10 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  const index_js_1 = require("../types/index.js");
7
- const node_events_1 = __importDefault(require("node:events"));
4
+ const node_events_1 = require("node:events");
8
5
  const consts_js_1 = require("./consts.js");
9
6
  const utils_js_1 = require("../utils/utils.js");
10
- class IncyclistDevice extends node_events_1.default {
7
+ class IncyclistDevice extends node_events_1.EventEmitter {
11
8
  onDataFn;
12
9
  settings;
13
10
  lastUpdate;
@@ -349,9 +349,21 @@ class BleAdapter extends adpater_js_1.default {
349
349
  }
350
350
  async restart(pause) {
351
351
  const sensor = this.getSensor();
352
+ sensor.off('data', this.onDeviceDataHandler);
353
+ let connected = false;
354
+ if (sensor.isReconnectBusy()) {
355
+ connected = await sensor.reconnectSensor();
356
+ }
357
+ if (connected) {
358
+ sensor.on('data', this.onDeviceDataHandler);
359
+ return true;
360
+ }
352
361
  await sensor.getPeripheral().disconnect();
353
- const res = await super.restart(pause);
354
- return res;
362
+ const success = await super.restart(pause);
363
+ if (success) {
364
+ sensor.on('data', this.onDeviceDataHandler);
365
+ }
366
+ return success;
355
367
  }
356
368
  async stop() {
357
369
  this.logEvent({ message: 'stopping device', device: this.getName(), interface: this.getInterface() });
@@ -1,10 +1,7 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.BleInterfaceFactory = exports.BleInterface = void 0;
7
- const node_events_1 = __importDefault(require("node:events"));
4
+ const node_events_1 = require("node:events");
8
5
  const gd_eventlog_1 = require("gd-eventlog");
9
6
  const task_js_1 = require("../../utils/task.js");
10
7
  const peripheral_js_1 = require("./peripheral.js");
@@ -14,7 +11,7 @@ const index_js_1 = require("../factories/index.js");
14
11
  const BLE_EXPIRATION_TIMEOUT = 10 * 1000 * 60;
15
12
  const BLE_DEFAULT_CONNECT_TIMEOUT = 30 * 1000;
16
13
  let instanceCount = 0;
17
- class BleInterface extends node_events_1.default {
14
+ class BleInterface extends node_events_1.EventEmitter {
18
15
  static _instance;
19
16
  static INTERFACE_NAME = 'ble';
20
17
  logger;
@@ -39,6 +36,7 @@ class BleInterface extends node_events_1.default {
39
36
  emitted = [];
40
37
  confirmedBleState;
41
38
  currentBleState;
39
+ stateChangeEventHandler = null;
42
40
  static getInstance(props = {}) {
43
41
  if (BleInterface._instance === undefined)
44
42
  BleInterface._instance = new BleInterface(props);
@@ -66,7 +64,7 @@ class BleInterface extends node_events_1.default {
66
64
  if (binding) {
67
65
  this.setBinding(binding);
68
66
  }
69
- this.internalEvents = new node_events_1.default();
67
+ this.internalEvents = new node_events_1.EventEmitter();
70
68
  this.onDiscovered = this.onPeripheralFound.bind(this);
71
69
  const { enabled = true } = props;
72
70
  if (this.binding && enabled)
@@ -94,10 +92,16 @@ class BleInterface extends node_events_1.default {
94
92
  getBinding() {
95
93
  return this.binding;
96
94
  }
97
- autoConnect() {
98
- this.connect();
95
+ async autoConnect() {
96
+ await this.connect();
99
97
  }
100
98
  async connect(reconnect) {
99
+ if (this.isConnected())
100
+ return true;
101
+ if (!this.stateChangeEventHandler) {
102
+ this.stateChangeEventHandler = this.onBleStateChange.bind(this);
103
+ this.getBinding()?.on('stateChange', this.stateChangeEventHandler);
104
+ }
101
105
  if (!this.getBinding()) {
102
106
  this.logEvent({ message: 'BLE not available' });
103
107
  return false;
@@ -106,8 +110,6 @@ class BleInterface extends node_events_1.default {
106
110
  this.logEvent({ message: 'BLE connect - already connecting' });
107
111
  return this.connectTask.getPromise();
108
112
  }
109
- if (this.isConnected())
110
- return true;
111
113
  this.logEvent({ message: 'BLE connect request' });
112
114
  this.connectTask = new task_js_1.InteruptableTask(this.connectBle(), {
113
115
  timeout: this.getConnectTimeout(),
@@ -116,6 +118,9 @@ class BleInterface extends node_events_1.default {
116
118
  log: this.logEvent.bind(this),
117
119
  });
118
120
  const success = await this.connectTask.run().catch(() => false);
121
+ this.removeAllListeners('ble-state-change');
122
+ if (success)
123
+ this.emit('connected');
119
124
  return success;
120
125
  }
121
126
  async disconnect(connectionLost) {
@@ -126,7 +131,7 @@ class BleInterface extends node_events_1.default {
126
131
  this.confirmedBleState = 'poweredOff';
127
132
  return false;
128
133
  }
129
- this.getBinding().removeAllListeners('error');
134
+ this.getBinding()?.removeAllListeners('error');
130
135
  if (!this.isConnected() && !connectionLost) {
131
136
  this.confirmedBleState = 'poweredOff';
132
137
  return true;
@@ -144,9 +149,16 @@ class BleInterface extends node_events_1.default {
144
149
  if (this.isConnecting())
145
150
  await this.connectTask?.stop();
146
151
  this.emit('disconnect-done');
147
- this.getBinding().removeAllListeners('stateChange');
148
- this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
149
- this.getBinding().on('error', this.onError.bind(this));
152
+ if (connectionLost) {
153
+ this.getBinding()?.removeAllListeners('stateChange');
154
+ this.stateChangeEventHandler = this.stateChangeEventHandler ?? this.onBleStateChange.bind(this);
155
+ this.getBinding()?.on('stateChange', this.stateChangeEventHandler);
156
+ }
157
+ else {
158
+ this.getBinding()?.removeAllListeners('stateChange');
159
+ this.stateChangeEventHandler = null;
160
+ }
161
+ this.getBinding()?.on('error', this.onError.bind(this));
150
162
  this.logEvent({ message: 'interface disconnected', interface: 'BLE' });
151
163
  this.confirmedBleState = 'poweredOff';
152
164
  return true;
@@ -156,7 +168,7 @@ class BleInterface extends node_events_1.default {
156
168
  }
157
169
  this.disconnectTask = new task_js_1.InteruptableTask(performDisconnect(), {
158
170
  timeout: this.getConnectTimeout(),
159
- name: 'BLE connect',
171
+ name: 'BLE disconnect',
160
172
  errorOnTimeout: false,
161
173
  log: this.logEvent.bind(this),
162
174
  });
@@ -225,13 +237,13 @@ class BleInterface extends node_events_1.default {
225
237
  this.logEvent({ message: 'pausing logging' });
226
238
  this.logDisabled = true;
227
239
  try {
228
- this.getBinding().pauseLogging();
240
+ this.getBinding()?.pauseLogging();
229
241
  }
230
242
  catch { }
231
243
  }
232
244
  resumeLogging() {
233
245
  try {
234
- this.getBinding().resumeLogging();
246
+ this.getBinding()?.resumeLogging();
235
247
  }
236
248
  catch { }
237
249
  this.logDisabled = false;
@@ -568,27 +580,37 @@ class BleInterface extends node_events_1.default {
568
580
  addKnownDevice(_settings) {
569
581
  }
570
582
  async connectBle() {
571
- this.currentBleState = this.getBinding().state;
583
+ this.currentBleState = this.getBinding()?.state;
572
584
  if (this.currentBleState === 'poweredOn') {
573
585
  this.onConnected();
574
586
  return true;
575
587
  }
588
+ else if (this.currentBleState === 'unauthorized' || this.currentBleState === 'unsupported') {
589
+ return false;
590
+ }
576
591
  const res = await this.waitForBleConnected();
577
592
  return res;
578
593
  }
579
594
  waitForBleConnected() {
580
595
  return new Promise((done) => {
581
- this.getBinding().once('error', (err) => {
596
+ this.getBinding()?.once('error', (err) => {
582
597
  this.logEvent({ message: 'Ble connect result: error', error: err.message });
583
598
  return done(false);
584
599
  });
585
- this.getBinding().on('stateChange', (state) => {
586
- if (state === this.confirmedBleState)
587
- return;
588
- this.logEvent({ message: 'BLE state change', state });
589
- if (state === 'poweredOn') {
590
- this.onConnected();
591
- return done(true);
600
+ this.on('ble-state-change', (state) => {
601
+ try {
602
+ if (state === 'poweredOn') {
603
+ this.onConnected();
604
+ this.removeAllListeners('ble-state-change');
605
+ return done(true);
606
+ }
607
+ if (state === 'unauthorized') {
608
+ this.removeAllListeners('ble-state-change');
609
+ return done(false);
610
+ }
611
+ }
612
+ catch (err) {
613
+ console.log('# BLE waitForBleConnected error', err);
592
614
  }
593
615
  });
594
616
  });
@@ -599,13 +621,16 @@ class BleInterface extends node_events_1.default {
599
621
  async onConnected() {
600
622
  if (this.isConnected())
601
623
  return;
602
- this.confirmedBleState = 'poweredOn';
603
- this.getBinding().removeAllListeners('error');
604
- this.getBinding().removeAllListeners('stateChange');
605
- this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
606
- this.getBinding().on('error', this.onError.bind(this));
607
- this.logEvent({ message: 'BLE connected' });
608
- this.startPeripheralScan();
624
+ try {
625
+ this.confirmedBleState = 'poweredOn';
626
+ this.getBinding()?.removeAllListeners('error');
627
+ this.getBinding()?.on('error', this.onError.bind(this));
628
+ this.logEvent({ message: 'BLE connected' });
629
+ this.startPeripheralScan();
630
+ }
631
+ catch (err) {
632
+ console.log('# BLE onConnected error', err);
633
+ }
609
634
  }
610
635
  async onDisconnected() {
611
636
  if (this.isDisconnecting() || !this.isConnected())
@@ -616,15 +641,22 @@ class BleInterface extends node_events_1.default {
616
641
  async onBleStateChange(state) {
617
642
  if (state === this.currentBleState)
618
643
  return;
644
+ this.logEvent({ message: 'BLE state change', state });
619
645
  this.currentBleState = state;
620
- if (state === 'poweredOff') {
621
- this.onDisconnected();
646
+ if (this.isConnecting()) {
647
+ this.emit('ble-state-change', state);
648
+ return;
649
+ }
650
+ if (state === 'poweredOff' || state === 'unauthorized') {
651
+ if (this.isConnected()) {
652
+ this.onDisconnected();
653
+ }
622
654
  }
623
655
  else {
624
656
  if (this.isDisconnecting()) {
625
657
  await this.disconnectTask.getPromise();
626
658
  }
627
- this.onConnected();
659
+ this.connect();
628
660
  }
629
661
  }
630
662
  getAdapterFactory() {
@@ -29,7 +29,7 @@ class BlePeripheral {
29
29
  return this.announcement.serviceUUIDs.map(s => (0, utils_js_1.beautifyUUID)(s));
30
30
  }
31
31
  getDiscoveredServices() {
32
- return this.discoveredServiceUUIds;
32
+ return this.discoveredServiceUUIds ?? [];
33
33
  }
34
34
  getInfo() {
35
35
  return {
@@ -47,17 +47,24 @@ class BlePeripheral {
47
47
  this.connectPromise = new Promise((done) => {
48
48
  const peripheral = this.getPeripheral();
49
49
  this.connected = false;
50
+ if (!peripheral?.id)
51
+ return done();
52
+ const peripheralId = peripheral.id;
50
53
  this.ble.unregisterConnected(peripheral.id);
51
54
  if (!this.ble.isConnected()) {
52
55
  return done();
53
56
  }
54
57
  this.logEvent({ message: 'connect peripheral', address: peripheral.address });
55
58
  peripheral.connectAsync().then(() => {
56
- this.ble.registerConnected(this, peripheral.id);
59
+ this.ble.registerConnected(this, peripheralId);
57
60
  peripheral.once('disconnect', () => { this.onPeripheralDisconnect(); });
58
61
  peripheral.on('error', this.onErrorHandler);
59
62
  this.connected = true;
60
63
  done();
64
+ })
65
+ .catch(() => {
66
+ this.connected = false;
67
+ done();
61
68
  });
62
69
  });
63
70
  await this.connectPromise;
@@ -66,10 +73,9 @@ class BlePeripheral {
66
73
  }
67
74
  async disconnect(connectionLost = false) {
68
75
  this.disconnecting = true;
69
- if (!this.isConnected()) {
70
- return true;
76
+ if (this.isConnected()) {
77
+ await this.unsubscribeAll(connectionLost);
71
78
  }
72
- await this.unsubscribeAll(connectionLost);
73
79
  Object.keys(this.characteristics).forEach(uuid => {
74
80
  const c = this.characteristics[uuid];
75
81
  c.removeAllListeners();
@@ -85,7 +91,8 @@ class BlePeripheral {
85
91
  return new Promise((done) => { this.getPeripheral().disconnect(() => { done(); }); });
86
92
  };
87
93
  }
88
- await this.getPeripheral().disconnectAsync();
94
+ await this.getPeripheral().disconnectAsync()
95
+ .catch(() => { });
89
96
  }
90
97
  peripheral.removeAllListeners();
91
98
  }
@@ -113,6 +120,7 @@ class BlePeripheral {
113
120
  if (this.disconnectedSignalled || this.disconnecting)
114
121
  return;
115
122
  this.disconnectedSignalled = true;
123
+ this.getPeripheral().removeAllListeners();
116
124
  this.ble.resumeLogging();
117
125
  this.logEvent({ message: 'peripheral disconnected', address: this.getPeripheral()?.address });
118
126
  try {
@@ -131,14 +139,21 @@ class BlePeripheral {
131
139
  return [];
132
140
  if (this.getPeripheral().discoverServicesAsync) {
133
141
  this.logEvent({ message: 'discover services', address: this.getPeripheral().address });
134
- const services = await this.getPeripheral().discoverServicesAsync([]);
142
+ const peripheral = this.getPeripheral();
143
+ let services = [];
144
+ if (peripheral?.discoverServicesAsync) {
145
+ services = await peripheral.discoverServicesAsync([])
146
+ .catch(() => []);
147
+ }
135
148
  this.discoveredServiceUUIds = services.map(s => (0, utils_js_1.beautifyUUID)(s.uuid));
149
+ this.logEvent({ message: 'discover services result', address: this.getPeripheral().address, services: this.discoveredServiceUUIds });
136
150
  return services.map(s => s.uuid);
137
151
  }
138
152
  else {
139
153
  this.logEvent({ message: 'discover services and characteristics', address: this.getPeripheral().address });
140
154
  const res = await this.getPeripheral().discoverSomeServicesAndCharacteristicsAsync([], []);
141
155
  this.discoveredServiceUUIds = res.services.map(s => (0, utils_js_1.beautifyUUID)(s.uuid));
156
+ this.logEvent({ message: 'discover services result', address: this.getPeripheral().address, services: this.discoveredServiceUUIds });
142
157
  return res.services.map(s => s.uuid);
143
158
  }
144
159
  }
@@ -146,7 +161,8 @@ class BlePeripheral {
146
161
  if (!this.getPeripheral())
147
162
  return [];
148
163
  this.logEvent({ message: 'discover services and characteristics', service: serviceUUID, address: this.getPeripheral().address });
149
- const res = await this.getPeripheral().discoverSomeServicesAndCharacteristicsAsync([serviceUUID], []);
164
+ const res = await this.getPeripheral().discoverSomeServicesAndCharacteristicsAsync([serviceUUID], [])
165
+ .catch(() => ({ services: [], characteristics: [] }));
150
166
  res.characteristics.forEach(c => this.characteristics[(0, utils_js_1.beautifyUUID)(c.uuid)] = c);
151
167
  return res.characteristics.map(c => {
152
168
  const { uuid, properties, name, _serviceUuid } = c;
@@ -173,7 +189,7 @@ class BlePeripheral {
173
189
  }
174
190
  return true;
175
191
  }
176
- let c = await this.queryRawCharacteristic(characteristicUUID);
192
+ let c = await this.queryRawCharacteristic(characteristicUUID).catch(() => null);
177
193
  if (!c) {
178
194
  return false;
179
195
  }
@@ -9,7 +9,9 @@ class TBleSensor extends node_events_1.EventEmitter {
9
9
  peripheral;
10
10
  static protocol;
11
11
  logger;
12
- stopRequested;
12
+ stopRequested = false;
13
+ subscribeSuccess = false;
14
+ reconnectPromise;
13
15
  onDataHandler;
14
16
  logEvent(event, ...args) {
15
17
  this.logger.logEvent(event, ...args);
@@ -82,39 +84,65 @@ class TBleSensor extends node_events_1.EventEmitter {
82
84
  async subscribe() {
83
85
  const selected = this.getRequiredCharacteristics();
84
86
  if (selected === null) {
85
- const res = await this.peripheral.subscribeAll(this.onDataHandler);
87
+ const res = this.peripheral?.subscribeAll ? await this.peripheral.subscribeAll(this.onDataHandler) : false;
88
+ this.subscribeSuccess = res;
86
89
  return res;
87
90
  }
88
91
  if (selected.length === 0) {
92
+ this.subscribeSuccess = true;
89
93
  return true;
90
94
  }
91
95
  const res = await this.peripheral.subscribeSelected(selected, this.onDataHandler);
96
+ this.subscribeSuccess = res;
92
97
  return res;
93
98
  }
94
99
  async stopSensor() {
100
+ this.onDisconnect();
95
101
  this.removeAllListeners();
96
102
  if (!this.peripheral)
97
103
  return true;
98
104
  this.stopRequested = true;
99
105
  return await this.peripheral.disconnect();
100
106
  }
107
+ isReconnectBusy() {
108
+ return (this.reconnectPromise !== undefined);
109
+ }
101
110
  async reconnectSensor() {
111
+ if (this.reconnectPromise !== undefined) {
112
+ return await this.reconnectPromise;
113
+ }
114
+ this.reconnectPromise = this.doReconnectSensor();
115
+ const res = await this.reconnectPromise;
116
+ delete this.reconnectPromise;
117
+ return res;
118
+ }
119
+ async doReconnectSensor() {
120
+ this.onDisconnect();
102
121
  this.logEvent({ message: 'reconnect sensor' });
103
122
  let connected = false;
104
123
  let subscribed = false;
105
124
  let success = false;
125
+ await (0, utils_js_1.sleep)(500);
106
126
  do {
107
- if (!connected) {
108
- connected = await this.startSensor(true);
127
+ try {
128
+ if (!connected) {
129
+ connected = await this.startSensor(true);
130
+ }
131
+ if (connected && !subscribed) {
132
+ subscribed = await this.subscribe();
133
+ }
109
134
  }
110
- if (connected && !subscribed) {
111
- subscribed = await this.subscribe();
135
+ catch {
112
136
  }
113
137
  success = connected && subscribed;
114
138
  if (!success) {
115
139
  await (0, utils_js_1.sleep)(1000);
116
140
  }
141
+ if (!this.stopRequested)
142
+ this.logEvent({ message: 'reconnect sensor retry' });
117
143
  } while (!success || this.stopRequested);
144
+ this.logEvent({ message: 'reconnect sensor completed', success, stopRequested: this.stopRequested });
145
+ return success;
118
146
  }
119
147
  reset() {
120
148
  throw new Error("Method not implemented.");
@@ -122,6 +150,12 @@ class TBleSensor extends node_events_1.EventEmitter {
122
150
  isConnected() {
123
151
  return this.peripheral?.isConnected();
124
152
  }
153
+ isSubscribed() {
154
+ return this.subscribeSuccess;
155
+ }
156
+ onDisconnect() {
157
+ this.subscribeSuccess = false;
158
+ }
125
159
  read(characteristicUUID) {
126
160
  if (!this.isConnected()) {
127
161
  return Promise.reject(new Error('not connected'));
@@ -1,11 +1,8 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.BleLinuxBinding = void 0;
7
- const events_1 = __importDefault(require("events"));
8
- class BleLinuxBinding extends events_1.default {
4
+ const events_1 = require("events");
5
+ class BleLinuxBinding extends events_1.EventEmitter {
9
6
  static _instance;
10
7
  _bindings;
11
8
  state;
@@ -1,11 +1,8 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const events_1 = __importDefault(require("events"));
3
+ const events_1 = require("events");
7
4
  const utils_js_1 = require("../../utils/utils.js");
8
- class Binding extends events_1.default {
5
+ class Binding extends events_1.EventEmitter {
9
6
  static _instance;
10
7
  _bindings;
11
8
  state;
@@ -64,7 +61,7 @@ class Binding extends events_1.default {
64
61
  callback();
65
62
  }
66
63
  }
67
- class MockPeripheral extends events_1.default {
64
+ class MockPeripheral extends events_1.EventEmitter {
68
65
  id;
69
66
  address;
70
67
  name;
@@ -1,16 +1,13 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.StaticNotifyCharacteristic = exports.StaticWriteCharacteristic = exports.StaticReadCharacteristic = exports.MockCharacteristic = exports.RESULT_UNLIKELY_ERROR = exports.RESULT_INVALID_ATTRIBUTE_LENGTH = exports.RESULT_ATTR_NOT_LONG = exports.RESULT_INVALID_OFFSET = exports.RESULT_SUCCESS = void 0;
7
- const node_events_1 = __importDefault(require("node:events"));
4
+ const node_events_1 = require("node:events");
8
5
  exports.RESULT_SUCCESS = 0x00;
9
6
  exports.RESULT_INVALID_OFFSET = 0x07;
10
7
  exports.RESULT_ATTR_NOT_LONG = 0x0b;
11
8
  exports.RESULT_INVALID_ATTRIBUTE_LENGTH = 0x0d;
12
9
  exports.RESULT_UNLIKELY_ERROR = 0x0e;
13
- class MockCharacteristic extends node_events_1.default {
10
+ class MockCharacteristic extends node_events_1.EventEmitter {
14
11
  uuid;
15
12
  properties;
16
13
  secure;
@@ -76,10 +76,15 @@ class BleFitnessMachineDevice extends sensor_js_1.TBleSensor {
76
76
  getCw() { return this.cw; }
77
77
  setWindSpeed(windSpeed) { this.windSpeed = windSpeed; }
78
78
  getWindSpeed() { return this.windSpeed; }
79
+ onDisconnect() {
80
+ this.hasControl = false;
81
+ }
79
82
  async requestControl() {
80
83
  if (this.hasControl) {
81
84
  return true;
82
85
  }
86
+ if (!this.isSubscribed())
87
+ return false;
83
88
  if (this.features?.setPower === false && this.features?.setSlope === false && this.features?.setResistance === false) {
84
89
  return true;
85
90
  }
@@ -98,6 +103,8 @@ class BleFitnessMachineDevice extends sensor_js_1.TBleSensor {
98
103
  return this.hasControl;
99
104
  }
100
105
  async setTargetPower(power) {
106
+ if (!this.isSubscribed())
107
+ return false;
101
108
  this.logEvent({ message: 'setTargetPower', device: this.getName(), power, skip: (this.data.targetPower !== undefined && this.data.targetPower === power) });
102
109
  if (this.data.targetPower !== undefined && this.data.targetPower === power)
103
110
  return true;
@@ -116,6 +123,8 @@ class BleFitnessMachineDevice extends sensor_js_1.TBleSensor {
116
123
  return (res === 1);
117
124
  }
118
125
  async setTargetResistanceLevel(resistanceLevel) {
126
+ if (!this.isSubscribed())
127
+ return false;
119
128
  this.logEvent({ message: 'setTargetResistanceLevel', device: this.getName(), resistanceLevel, skip: (this.data.resistanceLevel !== undefined && this.data.resistanceLevel === resistanceLevel) });
120
129
  if (this.data.resistanceLevel !== undefined && this.data.resistanceLevel === resistanceLevel)
121
130
  return true;
@@ -136,6 +145,8 @@ class BleFitnessMachineDevice extends sensor_js_1.TBleSensor {
136
145
  return (res === 1);
137
146
  }
138
147
  async setSlope(slope) {
148
+ if (!this.isSubscribed())
149
+ return false;
139
150
  this.logEvent({ message: 'setSlope', device: this.getName(), slope });
140
151
  const { windSpeed, crr, cw } = this;
141
152
  return await this.setIndoorBikeSimulation(windSpeed, slope, crr, cw);