incyclist-devices 2.3.0-beta.2 → 2.3.0-beta.20

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 (75) hide show
  1. package/README.MD +55 -0
  2. package/lib/antv2/base/adapter.d.ts +2 -2
  3. package/lib/base/adpater.d.ts +4 -0
  4. package/lib/base/adpater.js +16 -2
  5. package/lib/ble/adapter-factory.d.ts +24 -20
  6. package/lib/ble/adapter-factory.js +36 -13
  7. package/lib/ble/base/adapter.d.ts +6 -3
  8. package/lib/ble/base/adapter.js +72 -38
  9. package/lib/ble/base/comms.d.ts +74 -2
  10. package/lib/ble/base/comms.js +596 -3
  11. package/lib/ble/base/interface.d.ts +14 -5
  12. package/lib/ble/base/interface.js +125 -66
  13. package/lib/ble/base/peripheral.d.ts +7 -3
  14. package/lib/ble/base/peripheral.js +76 -22
  15. package/lib/ble/base/sensor.d.ts +1 -1
  16. package/lib/ble/base/sensor.js +17 -3
  17. package/lib/ble/ble-interface.d.ts +4 -7
  18. package/lib/ble/ble-interface.js +2 -16
  19. package/lib/ble/ble-peripheral.d.ts +0 -1
  20. package/lib/ble/ble-peripheral.js +11 -7
  21. package/lib/ble/characteristics/csc/features.d.ts +10 -0
  22. package/lib/ble/characteristics/csc/features.js +19 -0
  23. package/lib/ble/characteristics/csc/measurement.d.ts +33 -0
  24. package/lib/ble/characteristics/csc/measurement.js +109 -0
  25. package/lib/ble/characteristics/types.d.ts +6 -0
  26. package/lib/ble/characteristics/types.js +2 -0
  27. package/lib/ble/consts.d.ts +1 -0
  28. package/lib/ble/consts.js +2 -1
  29. package/lib/ble/cp/comm.d.ts +1 -1
  30. package/lib/ble/cp/comm.js +2 -2
  31. package/lib/ble/csc/adapter.d.ts +17 -0
  32. package/lib/ble/csc/adapter.js +66 -0
  33. package/lib/ble/csc/index.d.ts +3 -0
  34. package/lib/ble/csc/index.js +19 -0
  35. package/lib/ble/csc/sensor.d.ts +21 -0
  36. package/lib/ble/csc/sensor.js +64 -0
  37. package/lib/ble/csc/types.d.ts +6 -0
  38. package/lib/ble/csc/types.js +2 -0
  39. package/lib/ble/elite/comms.d.ts +1 -1
  40. package/lib/ble/elite/comms.js +2 -2
  41. package/lib/ble/fm/adapter.d.ts +4 -3
  42. package/lib/ble/fm/adapter.js +53 -49
  43. package/lib/ble/fm/comms.d.ts +1 -1
  44. package/lib/ble/fm/comms.js +3 -3
  45. package/lib/ble/fm/sensor.d.ts +1 -1
  46. package/lib/ble/fm/sensor.js +6 -5
  47. package/lib/ble/hr/comm.d.ts +1 -1
  48. package/lib/ble/hr/comm.js +2 -2
  49. package/lib/ble/index.js +2 -0
  50. package/lib/ble/tacx/adapter.d.ts +1 -1
  51. package/lib/ble/tacx/adapter.js +12 -10
  52. package/lib/ble/tacx/comms.d.ts +1 -1
  53. package/lib/ble/tacx/comms.js +2 -2
  54. package/lib/ble/tacx/sensor.js +9 -3
  55. package/lib/ble/types.d.ts +8 -2
  56. package/lib/ble/utils.d.ts +1 -0
  57. package/lib/ble/utils.js +5 -1
  58. package/lib/ble/wahoo/adapter.d.ts +1 -0
  59. package/lib/ble/wahoo/adapter.js +14 -0
  60. package/lib/ble/wahoo/comms.d.ts +1 -1
  61. package/lib/ble/wahoo/comms.js +2 -2
  62. package/lib/ble/wahoo/sensor.js +3 -6
  63. package/lib/direct-connect/base/interface.d.ts +1 -0
  64. package/lib/direct-connect/base/interface.js +9 -4
  65. package/lib/direct-connect/base/peripheral.d.ts +4 -4
  66. package/lib/direct-connect/base/peripheral.js +106 -31
  67. package/lib/direct-connect/messages/message.d.ts +1 -0
  68. package/lib/direct-connect/messages/message.js +16 -1
  69. package/lib/modes/ant-fe-adv-st-mode.d.ts +7 -1
  70. package/lib/modes/ant-fe-adv-st-mode.js +4 -3
  71. package/lib/types/adapter.d.ts +3 -0
  72. package/lib/types/interface.d.ts +1 -0
  73. package/lib/utils/task.d.ts +3 -0
  74. package/lib/utils/task.js +12 -0
  75. package/package.json +1 -1
@@ -28,6 +28,7 @@ class BleInterface extends events_1.default {
28
28
  if (BleInterface._instance === undefined)
29
29
  BleInterface._instance = new BleInterface(props);
30
30
  else {
31
+ BleInterface._instance.setProps(props);
31
32
  if (props.binding) {
32
33
  BleInterface._instance.setBinding(props.binding);
33
34
  }
@@ -49,6 +50,7 @@ class BleInterface extends events_1.default {
49
50
  this.expectedServices = ['180d', '1818', '1826', '6e40fec1'];
50
51
  this.matching = [];
51
52
  this.connectedPeripherals = [];
53
+ this.connectAttemptCnt = 0;
52
54
  this.instanceId = ++instanceCount;
53
55
  this.props = props;
54
56
  this.logEnabled = props.log || true;
@@ -59,9 +61,13 @@ class BleInterface extends events_1.default {
59
61
  }
60
62
  this.internalEvents = new events_1.default();
61
63
  this.onDiscovered = this.onPeripheralFound.bind(this);
62
- if (this.binding)
64
+ const { enabled = true } = props;
65
+ if (this.binding && enabled)
63
66
  this.autoConnect();
64
67
  }
68
+ setProps(props) {
69
+ this.props = props;
70
+ }
65
71
  getLogger() {
66
72
  return this.logger;
67
73
  }
@@ -72,8 +78,9 @@ class BleInterface extends events_1.default {
72
78
  return BleInterface.INTERFACE_NAME;
73
79
  }
74
80
  setBinding(binding) {
81
+ const prev = this.binding;
75
82
  this.binding = binding;
76
- if (!this.isConnected()) {
83
+ if (!prev && !this.isConnected() && this.props.enabled) {
77
84
  this.autoConnect();
78
85
  }
79
86
  }
@@ -90,46 +97,54 @@ class BleInterface extends events_1.default {
90
97
  return false;
91
98
  }
92
99
  if (this.isConnecting()) {
93
- this.logEvent({ message: 'connect - already connecting' });
100
+ this.logEvent({ message: 'BLE connect - already connecting' });
94
101
  return this.connectTask.getPromise();
95
102
  }
96
103
  if (this.isConnected())
97
104
  return true;
98
- this.logEvent({ message: 'Ble connect request' });
105
+ this.logEvent({ message: 'BLE connect request' });
99
106
  this.connectTask = new task_1.InteruptableTask(this.connectBle(), {
100
- timeout: BLE_DEFAULT_CONNECT_TIMEOUT,
101
- name: 'connect',
107
+ timeout: this.getConnectTimeout(),
108
+ name: 'BLE connect',
102
109
  errorOnTimeout: false,
103
110
  log: this.logEvent.bind(this),
104
111
  });
105
- const success = yield this.connectTask.run();
112
+ const success = yield this.connectTask.run().catch(() => false);
106
113
  if (success) {
107
114
  this.startPeripheralScan();
108
115
  }
109
- this.expectedServices = factories_1.BleAdapterFactory.getInstance('ble').getAllSupportedServices();
110
116
  return success;
111
117
  });
112
118
  }
113
- disconnect() {
119
+ disconnect(connectionLost) {
114
120
  return __awaiter(this, void 0, void 0, function* () {
121
+ var _a;
115
122
  if (!this.getBinding()) {
116
123
  return false;
117
124
  }
118
- if (!this.isConnected())
125
+ if (!this.isConnected() && !connectionLost)
119
126
  return true;
120
- this.logEvent({ message: 'disconnect request' });
127
+ if (!connectionLost)
128
+ this.logEvent({ message: 'disconnect request' });
129
+ this.emit('disconnect-request');
121
130
  yield this.stopPeripheralScan();
122
- const promises = this.connectedPeripherals.map(p => p.disconnect());
123
- yield Promise.allSettled(promises);
124
- this.connectedPeripherals = [];
125
- yield this.connectTask.stop();
131
+ if (connectionLost) {
132
+ this.emitDisconnectAllPeripherals();
133
+ }
134
+ else {
135
+ yield this.disconnectAllPeripherals();
136
+ }
137
+ if (this.isConnecting())
138
+ yield ((_a = this.connectTask) === null || _a === void 0 ? void 0 : _a.stop());
126
139
  this.getBinding().removeAllListeners();
140
+ this.connectAttemptCnt = 0;
141
+ this.emit('disconnect-done');
127
142
  return true;
128
143
  });
129
144
  }
130
145
  isConnected() {
131
146
  var _a;
132
- return ((_a = this.getBinding()) === null || _a === void 0 ? void 0 : _a.state) === 'poweredOn';
147
+ return this.connectAttemptCnt > 0 && ((_a = this.getBinding()) === null || _a === void 0 ? void 0 : _a.state) === 'poweredOn';
133
148
  }
134
149
  registerConnected(peripheral) {
135
150
  this.connectedPeripherals.push(peripheral);
@@ -147,7 +162,7 @@ class BleInterface extends events_1.default {
147
162
  .then(() => { return this.onScanDone(); })
148
163
  .catch(() => []);
149
164
  }
150
- this.logEvent({ message: 'starting scan ..' });
165
+ this.logEvent({ message: 'starting scan ..', interface: 'ble' });
151
166
  this.scanTask = new task_1.InteruptableTask(this.startScan(), {
152
167
  timeout: props.timeout,
153
168
  name: 'scan',
@@ -178,10 +193,14 @@ class BleInterface extends events_1.default {
178
193
  return this.buildDeviceSettings(this.matching);
179
194
  }
180
195
  pauseLogging() {
196
+ this.logEvent({ message: 'pausing logging' });
181
197
  this.logDisabled = true;
198
+ this.getBinding().pauseLogging();
182
199
  }
183
200
  resumeLogging() {
201
+ this.getBinding().resumeLogging();
184
202
  this.logDisabled = false;
203
+ this.logEvent({ message: 'resuming logging' });
185
204
  }
186
205
  isLoggingPaused() {
187
206
  return this.logDisabled;
@@ -200,11 +219,16 @@ class BleInterface extends events_1.default {
200
219
  if (peripheral)
201
220
  return Promise.resolve(peripheral);
202
221
  return new Promise((done) => {
222
+ const wasDiscovering = this.isDiscovering();
223
+ if (!wasDiscovering)
224
+ this.startPeripheralScan();
203
225
  const onDevice = (device) => {
204
226
  if (device.name === settings.name) {
205
227
  const peripheral = this.createPeripheralFromSettings(settings);
206
228
  if (peripheral) {
207
229
  this.off('device', onDevice);
230
+ if (!wasDiscovering)
231
+ this.stopPeripheralScan();
208
232
  done(peripheral);
209
233
  }
210
234
  }
@@ -228,6 +252,7 @@ class BleInterface extends events_1.default {
228
252
  }
229
253
  startPeripheralScan() {
230
254
  return __awaiter(this, arguments, void 0, function* (retry = false) {
255
+ this.expectedServices = this.getExpectedServices();
231
256
  if (!retry)
232
257
  this.logEvent({ message: 'starting peripheral discovery ...' });
233
258
  if (!this.isConnected() || this.isDiscovering()) {
@@ -254,13 +279,28 @@ class BleInterface extends events_1.default {
254
279
  return;
255
280
  this.logEvent({ message: 'stopping peripheral discovery ...' });
256
281
  this.discoverTask.stop();
257
- this.getBinding().off('discover', this.onDiscovered);
282
+ const ble = this.getBinding();
283
+ ble.off('discover', this.onDiscovered);
258
284
  return new Promise(done => {
259
- this.getBinding().stopScanning(() => {
285
+ ble.stopScanning(() => {
260
286
  done();
261
287
  });
262
288
  });
263
289
  }
290
+ emitDisconnectAllPeripherals() {
291
+ this.connectedPeripherals.forEach(p => {
292
+ const peripheral = p.getPeripheral();
293
+ peripheral.emit('disconnect');
294
+ });
295
+ this.connectedPeripherals = [];
296
+ }
297
+ disconnectAllPeripherals() {
298
+ return __awaiter(this, void 0, void 0, function* () {
299
+ const promises = this.connectedPeripherals.map(p => p.disconnect());
300
+ yield Promise.allSettled(promises);
301
+ this.connectedPeripherals = [];
302
+ });
303
+ }
264
304
  isDiscovering() {
265
305
  var _a;
266
306
  return ((_a = this.discoverTask) === null || _a === void 0 ? void 0 : _a.isRunning()) === true;
@@ -284,21 +324,6 @@ class BleInterface extends events_1.default {
284
324
  });
285
325
  });
286
326
  }
287
- pauseDiscovery() {
288
- this.getBinding().off('discover', this.onDiscovered);
289
- return new Promise(done => {
290
- try {
291
- this.getBinding().stopScanning();
292
- done();
293
- }
294
- catch (err) {
295
- done();
296
- }
297
- });
298
- }
299
- resumeDiscovery() {
300
- return this.discoverPeripherals();
301
- }
302
327
  onPeripheralFound(peripheral) {
303
328
  if (!this.isConnected() || !this.isDiscovering())
304
329
  return;
@@ -312,24 +337,33 @@ class BleInterface extends events_1.default {
312
337
  return;
313
338
  }
314
339
  if (announcement.serviceUUIDs.length === 0) {
315
- if (this.isCompleting(announcement)) {
316
- return;
317
- }
318
- this.addCompleting(announcement);
319
- setTimeout(() => {
320
- if (this.find(announcement)) {
321
- this.removeCompleting(announcement);
322
- return;
323
- }
324
- this.updateWithServices(announcement)
325
- .then(() => {
326
- if (this.isSupportedPeripheral(announcement))
327
- this.addService(announcement);
328
- });
329
- }, 1000);
340
+ return;
341
+ }
342
+ const isWahoo = this.checkForWahooEnhancement(announcement);
343
+ if (isWahoo) {
344
+ this.processWahooAnnouncement(announcement);
345
+ return;
330
346
  }
331
347
  this.addService(announcement);
332
348
  }
349
+ checkForWahooEnhancement(announcement) {
350
+ if (announcement.name.includes('KICKR')) {
351
+ const supported = announcement.serviceUUIDs.map(s => (0, utils_1.beautifyUUID)(s));
352
+ if (supported.length === 1 && supported[0] === '1818')
353
+ return true;
354
+ }
355
+ return false;
356
+ }
357
+ processWahooAnnouncement(announcement) {
358
+ if (this.isCompleting(announcement)) {
359
+ return;
360
+ }
361
+ this.updateWithServices(announcement)
362
+ .then(() => {
363
+ if (this.isSupportedPeripheral(announcement))
364
+ this.addService(announcement);
365
+ });
366
+ }
333
367
  buildAnnouncement(peripheral) {
334
368
  var _a;
335
369
  return {
@@ -344,9 +378,10 @@ class BleInterface extends events_1.default {
344
378
  return __awaiter(this, void 0, void 0, function* () {
345
379
  if (!this.isConnected() || !this.isDiscovering())
346
380
  return;
381
+ this.addCompleting(announcement);
382
+ this.logEvent({ message: 'updateWithServices', peripheral: announcement.name });
347
383
  try {
348
- yield this.discoverServices(announcement);
349
- return announcement;
384
+ announcement.serviceUUIDs = yield this.discoverServices(announcement);
350
385
  }
351
386
  catch (err) {
352
387
  this.logError(err, 'updateWithServices');
@@ -359,15 +394,14 @@ class BleInterface extends events_1.default {
359
394
  const device = Object.assign({}, announcement);
360
395
  delete device.peripheral;
361
396
  const { peripheral } = announcement;
362
- let paused = false;
363
397
  try {
364
398
  peripheral.on('error', (err) => {
365
399
  peripheral.removeAllListeners();
366
- this.logEvent({ message: 'Device error', error: err.message });
400
+ this.logEvent({ message: 'peripheral error', error: err.message });
367
401
  });
368
402
  peripheral.on('disconnect', () => {
369
403
  peripheral.removeAllListeners();
370
- this.logEvent({ message: 'Device disconnected' });
404
+ this.logEvent({ message: 'peripheral disconnected' });
371
405
  });
372
406
  yield peripheral.connectAsync();
373
407
  if (peripheral.discoverServicesAsync !== undefined) {
@@ -378,15 +412,12 @@ class BleInterface extends events_1.default {
378
412
  const res = yield peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
379
413
  announcement.serviceUUIDs = res.services.map(s => s.uuid);
380
414
  }
381
- peripheral.removeAllListeners();
382
415
  }
383
416
  catch (err) {
384
417
  this.logEvent({ message: 'discover services failed', reason: err.message, device });
385
418
  }
386
- if (paused) {
387
- yield this.resumeDiscovery();
388
- }
389
- return device.serviceUUIDs;
419
+ peripheral === null || peripheral === void 0 ? void 0 : peripheral.removeAllListeners();
420
+ return announcement.serviceUUIDs;
390
421
  });
391
422
  }
392
423
  isScanning() {
@@ -481,7 +512,7 @@ class BleInterface extends events_1.default {
481
512
  const expected = this.expectedServices.map(utils_1.parseUUID);
482
513
  const supported = (_b = found.filter(uuid => expected.includes(uuid))) !== null && _b !== void 0 ? _b : [];
483
514
  if (!supported.length) {
484
- this.logEvent({ message: 'service not supported', name: service.name, uuids: service.serviceUUIDs });
515
+ this.logEvent({ message: 'peripheral not supported', name: service.name, uuids: service.serviceUUIDs });
485
516
  this.addUnsupported(service);
486
517
  }
487
518
  return supported.length > 0;
@@ -497,8 +528,10 @@ class BleInterface extends events_1.default {
497
528
  }
498
529
  connectBle() {
499
530
  return __awaiter(this, void 0, void 0, function* () {
531
+ this.connectAttemptCnt++;
500
532
  const state = this.getBinding().state;
501
533
  if (state === 'poweredOn') {
534
+ this.logEvent({ message: 'BLE connected' });
502
535
  return true;
503
536
  }
504
537
  const res = yield this.waitForBleConnected();
@@ -513,10 +546,7 @@ class BleInterface extends events_1.default {
513
546
  });
514
547
  this.getBinding().on('stateChange', (state) => {
515
548
  if (state === 'poweredOn') {
516
- this.logEvent({ message: 'Ble connect result: success' });
517
- this.getBinding().removeAllListeners('stateChange');
518
- this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
519
- this.getBinding().on('error', console.log);
549
+ this.onConnected();
520
550
  return done(true);
521
551
  }
522
552
  else {
@@ -525,21 +555,50 @@ class BleInterface extends events_1.default {
525
555
  });
526
556
  });
527
557
  }
558
+ onError(err) {
559
+ this.logError(err, 'BLE connect');
560
+ }
561
+ onConnected() {
562
+ this.logEvent({ message: 'BLE connected' });
563
+ this.getBinding().removeAllListeners('error');
564
+ this.getBinding().removeAllListeners('stateChange');
565
+ this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
566
+ this.getBinding().on('error', this.onError.bind(this));
567
+ }
568
+ onDisconnected() {
569
+ return __awaiter(this, void 0, void 0, function* () {
570
+ this.logEvent({ message: 'BLE Disconnected' });
571
+ yield this.disconnect(true);
572
+ this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
573
+ this.getBinding().on('error', this.onError.bind(this));
574
+ });
575
+ }
528
576
  onBleStateChange(state) {
577
+ if (state !== 'poweredOn') {
578
+ this.onDisconnected();
579
+ }
580
+ else
581
+ this.onConnected();
529
582
  }
530
583
  getAdapterFactory() {
531
584
  return factories_1.BleAdapterFactory.getInstance('ble');
532
585
  }
586
+ getConnectTimeout() {
587
+ return BLE_DEFAULT_CONNECT_TIMEOUT;
588
+ }
589
+ getExpectedServices() {
590
+ return this.getAdapterFactory().getAllSupportedServices();
591
+ }
533
592
  logEvent(event) {
534
593
  if (this.logDisabled && event.message !== 'Error')
535
594
  return;
536
- this.getLogger().logEvent(event);
595
+ this.getLogger().logEvent(Object.assign(Object.assign({}, event), { interface: 'ble' }));
537
596
  const emitPayload = Object.assign({}, event);
538
597
  delete emitPayload.ts;
539
598
  this.emit('log', emitPayload);
540
599
  const w = global.window;
541
600
  if (this.debug || (w === null || w === void 0 ? void 0 : w.SERVICE_DEBUG) || process.env.DEBUG)
542
- console.log(`~~~ ${this.logger.getName().toUpperCase()}-SVC`, event);
601
+ console.log(`~~~ ${this.logger.getName().toUpperCase()}-SVC`, Object.assign(Object.assign({}, event), { interface: 'ble' }));
543
602
  }
544
603
  logError(err, fn, args) {
545
604
  const logInfo = args || {};
@@ -11,22 +11,26 @@ export declare class BlePeripheral implements IBlePeripheral {
11
11
  callback: (data: Buffer) => void;
12
12
  }>;
13
13
  protected disconnecting: boolean;
14
+ protected onErrorHandler: any;
14
15
  constructor(announcement: BlePeripheralAnnouncement);
15
16
  get services(): BleService[];
16
- protected getPeripheral(): BleRawPeripheral;
17
+ getPeripheral(): BleRawPeripheral;
17
18
  connect(): Promise<boolean>;
18
- disconnect(): Promise<boolean>;
19
+ disconnect(connectionLost?: boolean): Promise<boolean>;
19
20
  isConnected(): boolean;
20
21
  isConnecting(): boolean;
21
22
  onDisconnect(callback: () => void): void;
23
+ protected onPeripheralDisconnect(): Promise<void>;
24
+ protected onPeripheralError(err: Error): void;
22
25
  discoverServices(): Promise<string[]>;
23
26
  discoverCharacteristics(serviceUUID: string): Promise<BleCharacteristic[]>;
24
27
  subscribe(characteristicUUID: string, callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
25
28
  unsubscribe(characteristicUUID: string): Promise<boolean>;
26
29
  subscribeSelected(characteristics: string[], callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
27
30
  discoverAllCharacteristics(): Promise<string[]>;
31
+ discoverSomeCharacteristics(characteristics: string[]): Promise<string[]>;
28
32
  subscribeAll(callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
29
- unsubscribeAll(): Promise<boolean>;
33
+ unsubscribeAll(connectionLost?: boolean): Promise<void>;
30
34
  read(characteristicUUID: string): Promise<Buffer>;
31
35
  write(characteristicUUID: string, data: Buffer, options?: BleWriteProps): Promise<Buffer>;
32
36
  protected getRawCharacteristic(uuid: string): BleRawCharacteristic;
@@ -19,6 +19,7 @@ class BlePeripheral {
19
19
  this.characteristics = {};
20
20
  this.subscribed = [];
21
21
  this.disconnecting = false;
22
+ this.onErrorHandler = this.onPeripheralError.bind(this);
22
23
  this.ble = interface_1.BleInterface.getInstance();
23
24
  }
24
25
  get services() {
@@ -29,31 +30,42 @@ class BlePeripheral {
29
30
  }
30
31
  connect() {
31
32
  return __awaiter(this, void 0, void 0, function* () {
32
- yield this.getPeripheral().connectAsync();
33
+ if (this.isConnected())
34
+ return true;
35
+ const peripheral = this.getPeripheral();
36
+ yield peripheral.connectAsync();
33
37
  this.ble.registerConnected(this);
38
+ peripheral.once('disconnect', () => { this.onPeripheralDisconnect(); });
39
+ peripheral.on('error', this.onErrorHandler);
34
40
  this.connected = true;
35
- return true;
41
+ return this.connected;
36
42
  });
37
43
  }
38
44
  disconnect() {
39
- return __awaiter(this, void 0, void 0, function* () {
45
+ return __awaiter(this, arguments, void 0, function* (connectionLost = false) {
40
46
  this.disconnecting = true;
41
47
  if (!this.isConnected())
42
48
  return true;
43
- yield this.unsubscribeAll();
49
+ yield this.unsubscribeAll(connectionLost);
44
50
  Object.keys(this.characteristics).forEach(uuid => {
45
51
  const c = this.characteristics[uuid];
46
52
  c.removeAllListeners();
47
53
  });
48
- if (!this.getPeripheral().disconnectAsync) {
49
- this.getPeripheral().disconnectAsync = () => {
50
- return new Promise((done) => { this.getPeripheral().disconnect(() => { done(); }); });
51
- };
54
+ const peripheral = this.getPeripheral();
55
+ if (peripheral) {
56
+ if (!connectionLost) {
57
+ if (!peripheral.disconnectAsync) {
58
+ peripheral.disconnectAsync = () => {
59
+ return new Promise((done) => { this.getPeripheral().disconnect(() => { done(); }); });
60
+ };
61
+ }
62
+ yield this.getPeripheral().disconnectAsync();
63
+ }
64
+ peripheral.removeAllListeners();
52
65
  }
53
- yield this.getPeripheral().disconnectAsync();
54
66
  this.connected = false;
55
67
  this.disconnecting = false;
56
- return true;
68
+ return !this.connected;
57
69
  });
58
70
  }
59
71
  isConnected() {
@@ -65,13 +77,29 @@ class BlePeripheral {
65
77
  onDisconnect(callback) {
66
78
  this.onDisconnectHandler = callback;
67
79
  }
80
+ onPeripheralDisconnect() {
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ this.logEvent({ message: 'disconnect' });
83
+ try {
84
+ yield this.disconnect(true);
85
+ }
86
+ catch (_a) { }
87
+ if (this.onDisconnectHandler)
88
+ this.onDisconnectHandler();
89
+ });
90
+ }
91
+ onPeripheralError(err) {
92
+ this.logEvent({ message: 'peripheral error', error: err.message });
93
+ }
68
94
  discoverServices() {
69
95
  return __awaiter(this, void 0, void 0, function* () {
70
96
  if (this.getPeripheral().discoverServicesAsync) {
97
+ this.logEvent({ message: 'discover services' });
71
98
  const services = yield this.getPeripheral().discoverServicesAsync([]);
72
99
  return services.map(s => s.uuid);
73
100
  }
74
101
  else {
102
+ this.logEvent({ message: 'discover services and characteristics' });
75
103
  const res = yield this.getPeripheral().discoverSomeServicesAndCharacteristicsAsync([], []);
76
104
  return res.services.map(s => s.uuid);
77
105
  }
@@ -92,8 +120,17 @@ class BlePeripheral {
92
120
  try {
93
121
  if (this.disconnecting || !this.connected)
94
122
  return false;
123
+ const onData = (data) => {
124
+ try {
125
+ callback(characteristicUUID, data);
126
+ }
127
+ catch (_a) { }
128
+ };
95
129
  const subscription = this.subscribed.find(s => s.uuid === characteristicUUID);
96
130
  if (subscription) {
131
+ const c = this.getRawCharacteristic(characteristicUUID);
132
+ if (c)
133
+ c.on('data', onData);
97
134
  return true;
98
135
  }
99
136
  const c = this.getRawCharacteristic(characteristicUUID);
@@ -114,12 +151,6 @@ class BlePeripheral {
114
151
  }
115
152
  else {
116
153
  if (callback) {
117
- const onData = (data) => {
118
- try {
119
- callback(characteristicUUID, data);
120
- }
121
- catch (_a) { }
122
- };
123
154
  this.subscribed.push({ uuid: characteristicUUID, callback: onData });
124
155
  c.on('data', onData);
125
156
  }
@@ -177,16 +208,16 @@ class BlePeripheral {
177
208
  yield this.discoverAllCharacteristics();
178
209
  }
179
210
  const retry = [];
180
- for (let i = 0; i < characteristics.length; i++) {
181
- const c = this.getRawCharacteristic(characteristics[i]);
211
+ for (const element of characteristics) {
212
+ const c = this.getRawCharacteristic(element);
182
213
  if (c === null || c === void 0 ? void 0 : c.properties.includes('notify')) {
183
214
  const success = yield this.subscribe(c.uuid, callback);
184
215
  if (!success)
185
216
  retry.push(c);
186
217
  }
187
218
  }
188
- for (let i = 0; i < retry.length; i++) {
189
- const c = retry[i];
219
+ for (const element of retry) {
220
+ const c = element;
190
221
  yield this.subscribe(c.uuid, callback);
191
222
  }
192
223
  return true;
@@ -214,6 +245,24 @@ class BlePeripheral {
214
245
  }
215
246
  });
216
247
  }
248
+ discoverSomeCharacteristics(characteristics) {
249
+ return __awaiter(this, void 0, void 0, function* () {
250
+ try {
251
+ const target = characteristics.map(c => (0, utils_1.fullUUID)(c));
252
+ const res = yield this.getPeripheral().discoverSomeServicesAndCharacteristicsAsync([], target);
253
+ const found = [];
254
+ res.characteristics.forEach(c => {
255
+ this.characteristics[(0, utils_1.beautifyUUID)(c.uuid)] = c;
256
+ found.push(c.uuid);
257
+ });
258
+ return found;
259
+ }
260
+ catch (err) {
261
+ this.logEvent({ message: 'Error', fn: 'discoverAllCharacteristics', error: err.message, stack: err.stack });
262
+ return [];
263
+ }
264
+ });
265
+ }
217
266
  subscribeAll(callback) {
218
267
  return __awaiter(this, void 0, void 0, function* () {
219
268
  const characteristics = yield this.discoverAllCharacteristics();
@@ -222,13 +271,16 @@ class BlePeripheral {
222
271
  });
223
272
  }
224
273
  unsubscribeAll() {
225
- return __awaiter(this, void 0, void 0, function* () {
274
+ return __awaiter(this, arguments, void 0, function* (connectionLost = false) {
275
+ if (connectionLost) {
276
+ this.subscribed = [];
277
+ return;
278
+ }
226
279
  const promises = [];
227
280
  this.subscribed.forEach(d => {
228
281
  promises.push(this.unsubscribe(d.uuid));
229
282
  });
230
283
  yield Promise.allSettled(promises);
231
- return true;
232
284
  });
233
285
  }
234
286
  read(characteristicUUID) {
@@ -280,6 +332,8 @@ class BlePeripheral {
280
332
  return this.characteristics[(0, utils_1.beautifyUUID)(uuid)];
281
333
  }
282
334
  logEvent(event) {
335
+ var _a;
336
+ event.peripheral = (_a = this.announcement) === null || _a === void 0 ? void 0 : _a.name;
283
337
  this.ble.logEvent(event);
284
338
  }
285
339
  }
@@ -20,7 +20,7 @@ export declare class TBleSensor extends EventEmitter implements IBleSensor {
20
20
  hasPeripheral(): boolean;
21
21
  startSensor(reconnect?: boolean): Promise<boolean>;
22
22
  protected getRequiredCharacteristics(): Array<string>;
23
- protected subscribe(): Promise<boolean>;
23
+ subscribe(): Promise<boolean>;
24
24
  stopSensor(): Promise<boolean>;
25
25
  reconnectSensor(): Promise<void>;
26
26
  reset(): void;
@@ -74,7 +74,7 @@ class TBleSensor extends events_1.default {
74
74
  return false;
75
75
  if (!reconnect)
76
76
  this.peripheral.onDisconnect(this.reconnectSensor.bind(this));
77
- return yield this.subscribe();
77
+ return true;
78
78
  });
79
79
  }
80
80
  getRequiredCharacteristics() {
@@ -101,11 +101,19 @@ class TBleSensor extends events_1.default {
101
101
  }
102
102
  reconnectSensor() {
103
103
  return __awaiter(this, void 0, void 0, function* () {
104
+ let connected = false;
105
+ let subscribed = false;
104
106
  let success = false;
105
107
  do {
106
- success = yield this.startSensor(true);
108
+ if (!connected) {
109
+ connected = yield this.startSensor(true);
110
+ }
111
+ if (connected && !subscribed) {
112
+ subscribed = yield this.subscribe();
113
+ }
114
+ success = connected && subscribed;
107
115
  if (!success) {
108
- yield (0, utils_1.sleep)(5000);
116
+ yield (0, utils_1.sleep)(1000);
109
117
  }
110
118
  } while (!success || this.stopRequested);
111
119
  });
@@ -119,10 +127,16 @@ class TBleSensor extends events_1.default {
119
127
  }
120
128
  read(characteristicUUID) {
121
129
  var _a;
130
+ if (!this.isConnected()) {
131
+ return Promise.reject(new Error('not connected'));
132
+ }
122
133
  return (_a = this.peripheral) === null || _a === void 0 ? void 0 : _a.read(characteristicUUID);
123
134
  }
124
135
  write(characteristicUUID, data, options) {
125
136
  var _a;
137
+ if (!this.isConnected()) {
138
+ return Promise.reject(new Error('not connected'));
139
+ }
126
140
  return (_a = this.peripheral) === null || _a === void 0 ? void 0 : _a.write(characteristicUUID, data, options);
127
141
  }
128
142
  onData(characteristic, data) {