incyclist-devices 2.3.0 → 2.3.2

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 (81) 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 +83 -49
  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 +21 -10
  12. package/lib/ble/base/interface.js +157 -73
  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 +2 -1
  16. package/lib/ble/base/sensor.js +22 -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/factories/adapter-factory.d.ts +8 -6
  42. package/lib/ble/factories/adapter-factory.js +33 -0
  43. package/lib/ble/factories/types.d.ts +18 -0
  44. package/lib/ble/factories/types.js +2 -0
  45. package/lib/ble/fm/adapter.d.ts +4 -3
  46. package/lib/ble/fm/adapter.js +53 -48
  47. package/lib/ble/fm/comms.d.ts +1 -1
  48. package/lib/ble/fm/comms.js +3 -3
  49. package/lib/ble/fm/sensor.d.ts +1 -1
  50. package/lib/ble/fm/sensor.js +6 -5
  51. package/lib/ble/hr/comm.d.ts +1 -1
  52. package/lib/ble/hr/comm.js +2 -2
  53. package/lib/ble/index.js +2 -0
  54. package/lib/ble/tacx/adapter.d.ts +1 -1
  55. package/lib/ble/tacx/adapter.js +12 -10
  56. package/lib/ble/tacx/comms.d.ts +1 -1
  57. package/lib/ble/tacx/comms.js +2 -2
  58. package/lib/ble/tacx/sensor.js +9 -3
  59. package/lib/ble/types.d.ts +8 -2
  60. package/lib/ble/utils.d.ts +1 -0
  61. package/lib/ble/utils.js +15 -2
  62. package/lib/ble/wahoo/adapter.d.ts +1 -0
  63. package/lib/ble/wahoo/adapter.js +14 -0
  64. package/lib/ble/wahoo/comms.d.ts +1 -1
  65. package/lib/ble/wahoo/comms.js +2 -2
  66. package/lib/ble/wahoo/sensor.js +3 -6
  67. package/lib/direct-connect/base/interface.d.ts +2 -1
  68. package/lib/direct-connect/base/interface.js +20 -10
  69. package/lib/direct-connect/base/peripheral.d.ts +4 -4
  70. package/lib/direct-connect/base/peripheral.js +181 -68
  71. package/lib/direct-connect/bindings/types.d.ts +2 -1
  72. package/lib/direct-connect/messages/message.d.ts +1 -0
  73. package/lib/direct-connect/messages/message.js +16 -1
  74. package/lib/factories/adapters.js +0 -2
  75. package/lib/modes/ant-fe-adv-st-mode.d.ts +7 -1
  76. package/lib/modes/ant-fe-adv-st-mode.js +4 -3
  77. package/lib/types/adapter.d.ts +3 -0
  78. package/lib/types/interface.d.ts +1 -0
  79. package/lib/utils/task.d.ts +3 -0
  80. package/lib/utils/task.js +12 -0
  81. package/package.json +1 -1
@@ -1,10 +1,12 @@
1
1
  import EventEmitter from "events";
2
2
  import { DeviceSettings, InterfaceProps } from "../../types";
3
3
  import { EventLogger } from "gd-eventlog";
4
- import { BleBinding, BleInterfaceState, BlePeripheralAnnouncement, BlePeripheralInfo, BleRawPeripheral, BleScanProps, IBlePeripheral } from "../types";
4
+ import { BleBinding, BleDeviceSettings, BleInterfaceState, BlePeripheralAnnouncement, BleRawPeripheral, BleScanProps, IBlePeripheral } from "../types";
5
5
  import { IBleInterface } from '../../ble/types';
6
6
  import { InteruptableTask, TaskState } from "../../utils/task";
7
7
  import { InterfaceFactory } from "./types";
8
+ import { BleAdapterFactory } from "../factories";
9
+ import { TBleSensor } from "./sensor";
8
10
  interface Announcement {
9
11
  service: BlePeripheralAnnouncement;
10
12
  ts: number;
@@ -27,11 +29,14 @@ export declare class BleInterface extends EventEmitter implements IBleInterface<
27
29
  protected connectTask: InteruptableTask<TaskState, boolean>;
28
30
  protected scanTask: InteruptableTask<TaskState, void>;
29
31
  protected discoverTask: InteruptableTask<TaskState, void>;
30
- protected onDiscovered: (peripheral: BlePeripheralInfo) => void;
32
+ protected onDiscovered: (peripheral: BleRawPeripheral) => void;
31
33
  protected instanceId: number;
32
34
  protected connectedPeripherals: IBlePeripheral[];
35
+ protected connectAttemptCnt: number;
36
+ protected emitted: BlePeripheralAnnouncement[];
33
37
  static getInstance(props?: InterfaceProps): BleInterface;
34
38
  protected constructor(props: InterfaceProps);
39
+ setProps(props: InterfaceProps): void;
35
40
  getLogger(): EventLogger;
36
41
  setLogger(logger: EventLogger): void;
37
42
  getName(): string;
@@ -39,7 +44,7 @@ export declare class BleInterface extends EventEmitter implements IBleInterface<
39
44
  getBinding(): BleBinding;
40
45
  protected autoConnect(): void;
41
46
  connect(reconnect?: boolean): Promise<boolean>;
42
- disconnect(): Promise<boolean>;
47
+ disconnect(connectionLost?: boolean): Promise<boolean>;
43
48
  isConnected(): boolean;
44
49
  registerConnected(peripheral: IBlePeripheral): void;
45
50
  protected isConnecting(): boolean;
@@ -52,15 +57,17 @@ export declare class BleInterface extends EventEmitter implements IBleInterface<
52
57
  createPeripheral(announcement: BlePeripheralAnnouncement): IBlePeripheral;
53
58
  createPeripheralFromSettings(settings: DeviceSettings): IBlePeripheral;
54
59
  waitForPeripheral(settings: DeviceSettings): Promise<IBlePeripheral>;
55
- createDeviceSetting(service: BlePeripheralAnnouncement): DeviceSettings;
60
+ createDeviceSetting(service: BlePeripheralAnnouncement): BleDeviceSettings;
56
61
  protected reconnect(): Promise<void>;
57
62
  protected startPeripheralScan(retry?: boolean): Promise<void>;
58
63
  protected stopPeripheralScan(): Promise<void>;
64
+ protected emitDisconnectAllPeripherals(): void;
65
+ protected disconnectAllPeripherals(): Promise<void>;
59
66
  protected isDiscovering(): boolean;
60
67
  protected discoverPeripherals(): Promise<void>;
61
- pauseDiscovery(): Promise<void>;
62
- resumeDiscovery(): Promise<void>;
63
68
  protected onPeripheralFound(peripheral: BleRawPeripheral): void;
69
+ protected checkForWahooEnhancement(announcement: BlePeripheralAnnouncement): boolean;
70
+ protected processWahooAnnouncement(announcement: BlePeripheralAnnouncement): void;
64
71
  protected buildAnnouncement(peripheral: BleRawPeripheral): BlePeripheralAnnouncement;
65
72
  protected updateWithServices(announcement: BlePeripheralAnnouncement): Promise<BlePeripheralAnnouncement>;
66
73
  protected discoverServices(announcement: BlePeripheralAnnouncement): Promise<string[]>;
@@ -68,10 +75,8 @@ export declare class BleInterface extends EventEmitter implements IBleInterface<
68
75
  protected startScan(): Promise<unknown>;
69
76
  private emitCachedDevices;
70
77
  protected emitDevice(service: BlePeripheralAnnouncement): void;
71
- protected buildDeviceSettings(matching?: string[]): {
72
- interface: string;
73
- name: string;
74
- }[];
78
+ protected alreadyEmitted(service: BlePeripheralAnnouncement): boolean;
79
+ protected buildDeviceSettings(matching?: string[]): BleDeviceSettings[];
75
80
  protected addCompleting(service: BlePeripheralAnnouncement): void;
76
81
  protected addUnsupported(service: BlePeripheralAnnouncement): void;
77
82
  protected isKnownUnsupported(service: BlePeripheralAnnouncement): boolean;
@@ -84,7 +89,13 @@ export declare class BleInterface extends EventEmitter implements IBleInterface<
84
89
  setDebug(enabled: boolean): void;
85
90
  protected connectBle(): Promise<boolean>;
86
91
  protected waitForBleConnected(): Promise<boolean>;
92
+ protected onError(err: Error): void;
93
+ protected onConnected(): void;
94
+ protected onDisconnected(): Promise<void>;
87
95
  protected onBleStateChange(state: BleInterfaceState): void;
96
+ protected getAdapterFactory(): BleAdapterFactory<TBleSensor>;
97
+ protected getConnectTimeout(): number;
98
+ protected getExpectedServices(): string[];
88
99
  logEvent(event: any): void;
89
100
  logError(err: Error, fn: string, args?: any): void;
90
101
  }
@@ -20,7 +20,6 @@ const peripheral_1 = require("./peripheral");
20
20
  const utils_1 = require("../utils");
21
21
  const types_1 = require("./types");
22
22
  const factories_1 = require("../factories");
23
- const BLE_DEFAULT_SCAN_TIMEOUT = 30 * 1000;
24
23
  const BLE_EXPIRATION_TIMEOUT = 10 * 1000 * 60;
25
24
  const BLE_DEFAULT_CONNECT_TIMEOUT = 30 * 1000;
26
25
  let instanceCount = 0;
@@ -29,6 +28,7 @@ class BleInterface extends events_1.default {
29
28
  if (BleInterface._instance === undefined)
30
29
  BleInterface._instance = new BleInterface(props);
31
30
  else {
31
+ BleInterface._instance.setProps(props);
32
32
  if (props.binding) {
33
33
  BleInterface._instance.setBinding(props.binding);
34
34
  }
@@ -50,6 +50,8 @@ class BleInterface extends events_1.default {
50
50
  this.expectedServices = ['180d', '1818', '1826', '6e40fec1'];
51
51
  this.matching = [];
52
52
  this.connectedPeripherals = [];
53
+ this.connectAttemptCnt = 0;
54
+ this.emitted = [];
53
55
  this.instanceId = ++instanceCount;
54
56
  this.props = props;
55
57
  this.logEnabled = props.log || true;
@@ -60,9 +62,13 @@ class BleInterface extends events_1.default {
60
62
  }
61
63
  this.internalEvents = new events_1.default();
62
64
  this.onDiscovered = this.onPeripheralFound.bind(this);
63
- if (this.binding)
65
+ const { enabled = true } = props;
66
+ if (this.binding && enabled)
64
67
  this.autoConnect();
65
68
  }
69
+ setProps(props) {
70
+ this.props = props;
71
+ }
66
72
  getLogger() {
67
73
  return this.logger;
68
74
  }
@@ -73,7 +79,11 @@ class BleInterface extends events_1.default {
73
79
  return BleInterface.INTERFACE_NAME;
74
80
  }
75
81
  setBinding(binding) {
82
+ const prev = this.binding;
76
83
  this.binding = binding;
84
+ if (!prev && !this.isConnected() && this.props.enabled) {
85
+ this.autoConnect();
86
+ }
77
87
  }
78
88
  getBinding() {
79
89
  return this.binding;
@@ -88,46 +98,54 @@ class BleInterface extends events_1.default {
88
98
  return false;
89
99
  }
90
100
  if (this.isConnecting()) {
91
- this.logEvent({ message: 'connect - already connecting' });
101
+ this.logEvent({ message: 'BLE connect - already connecting' });
92
102
  return this.connectTask.getPromise();
93
103
  }
94
104
  if (this.isConnected())
95
105
  return true;
96
- this.logEvent({ message: 'Ble connect request' });
106
+ this.logEvent({ message: 'BLE connect request' });
97
107
  this.connectTask = new task_1.InteruptableTask(this.connectBle(), {
98
- timeout: BLE_DEFAULT_CONNECT_TIMEOUT,
99
- name: 'connect',
108
+ timeout: this.getConnectTimeout(),
109
+ name: 'BLE connect',
100
110
  errorOnTimeout: false,
101
111
  log: this.logEvent.bind(this),
102
112
  });
103
- const success = yield this.connectTask.run();
113
+ const success = yield this.connectTask.run().catch(() => false);
104
114
  if (success) {
105
115
  this.startPeripheralScan();
106
116
  }
107
- this.expectedServices = factories_1.BleAdapterFactory.getInstance('ble').getAllSupportedServices();
108
117
  return success;
109
118
  });
110
119
  }
111
- disconnect() {
120
+ disconnect(connectionLost) {
112
121
  return __awaiter(this, void 0, void 0, function* () {
122
+ var _a;
113
123
  if (!this.getBinding()) {
114
124
  return false;
115
125
  }
116
- if (!this.isConnected())
126
+ if (!this.isConnected() && !connectionLost)
117
127
  return true;
118
- this.logEvent({ message: 'disconnect request' });
128
+ if (!connectionLost)
129
+ this.logEvent({ message: 'disconnect request' });
130
+ this.emit('disconnect-request');
119
131
  yield this.stopPeripheralScan();
120
- const promises = this.connectedPeripherals.map(p => p.disconnect());
121
- yield Promise.allSettled(promises);
122
- this.connectedPeripherals = [];
123
- yield this.connectTask.stop();
132
+ if (connectionLost) {
133
+ this.emitDisconnectAllPeripherals();
134
+ }
135
+ else {
136
+ yield this.disconnectAllPeripherals();
137
+ }
138
+ if (this.isConnecting())
139
+ yield ((_a = this.connectTask) === null || _a === void 0 ? void 0 : _a.stop());
124
140
  this.getBinding().removeAllListeners();
141
+ this.connectAttemptCnt = 0;
142
+ this.emit('disconnect-done');
125
143
  return true;
126
144
  });
127
145
  }
128
146
  isConnected() {
129
147
  var _a;
130
- return ((_a = this.getBinding()) === null || _a === void 0 ? void 0 : _a.state) === 'poweredOn';
148
+ return this.connectAttemptCnt > 0 && ((_a = this.getBinding()) === null || _a === void 0 ? void 0 : _a.state) === 'poweredOn';
131
149
  }
132
150
  registerConnected(peripheral) {
133
151
  this.connectedPeripherals.push(peripheral);
@@ -145,7 +163,7 @@ class BleInterface extends events_1.default {
145
163
  .then(() => { return this.onScanDone(); })
146
164
  .catch(() => []);
147
165
  }
148
- this.logEvent({ message: 'starting scan ..' });
166
+ this.logEvent({ message: 'starting scan ..', interface: 'ble' });
149
167
  this.scanTask = new task_1.InteruptableTask(this.startScan(), {
150
168
  timeout: props.timeout,
151
169
  name: 'scan',
@@ -162,10 +180,13 @@ class BleInterface extends events_1.default {
162
180
  });
163
181
  }
164
182
  stopScan() {
165
- if (!this.isScanning())
166
- return Promise.resolve(true);
167
- this.logEvent({ message: 'stopping scan ...' });
168
- this.scanTask.stop();
183
+ return __awaiter(this, void 0, void 0, function* () {
184
+ if (!this.isScanning())
185
+ return true;
186
+ this.logEvent({ message: 'stopping scan ...', interface: 'ble' });
187
+ const res = yield this.scanTask.stop();
188
+ return (res === true);
189
+ });
169
190
  }
170
191
  onScanDone() {
171
192
  this.logEvent({ message: 'scan stopped' });
@@ -173,10 +194,14 @@ class BleInterface extends events_1.default {
173
194
  return this.buildDeviceSettings(this.matching);
174
195
  }
175
196
  pauseLogging() {
197
+ this.logEvent({ message: 'pausing logging' });
176
198
  this.logDisabled = true;
199
+ this.getBinding().pauseLogging();
177
200
  }
178
201
  resumeLogging() {
202
+ this.getBinding().resumeLogging();
179
203
  this.logDisabled = false;
204
+ this.logEvent({ message: 'resuming logging' });
180
205
  }
181
206
  isLoggingPaused() {
182
207
  return this.logDisabled;
@@ -195,11 +220,16 @@ class BleInterface extends events_1.default {
195
220
  if (peripheral)
196
221
  return Promise.resolve(peripheral);
197
222
  return new Promise((done) => {
223
+ const wasDiscovering = this.isDiscovering();
224
+ if (!wasDiscovering)
225
+ this.startPeripheralScan();
198
226
  const onDevice = (device) => {
199
227
  if (device.name === settings.name) {
200
228
  const peripheral = this.createPeripheralFromSettings(settings);
201
229
  if (peripheral) {
202
230
  this.off('device', onDevice);
231
+ if (!wasDiscovering)
232
+ this.stopPeripheralScan();
203
233
  done(peripheral);
204
234
  }
205
235
  }
@@ -208,8 +238,12 @@ class BleInterface extends events_1.default {
208
238
  });
209
239
  }
210
240
  createDeviceSetting(service) {
211
- const name = service.name;
212
- return { interface: BleInterface.INTERFACE_NAME, name };
241
+ const { peripheral } = service;
242
+ if (peripheral.address === undefined || peripheral.address === '')
243
+ peripheral.address = peripheral.id || peripheral.name;
244
+ const protocol = this.getAdapterFactory().getProtocol(service.serviceUUIDs);
245
+ const { id, name, address } = (0, utils_1.getPeripheralInfo)(peripheral);
246
+ return { interface: BleInterface.INTERFACE_NAME, protocol, id, name, address };
213
247
  }
214
248
  reconnect() {
215
249
  return __awaiter(this, void 0, void 0, function* () {
@@ -219,6 +253,7 @@ class BleInterface extends events_1.default {
219
253
  }
220
254
  startPeripheralScan() {
221
255
  return __awaiter(this, arguments, void 0, function* (retry = false) {
256
+ this.expectedServices = this.getExpectedServices();
222
257
  if (!retry)
223
258
  this.logEvent({ message: 'starting peripheral discovery ...' });
224
259
  if (!this.isConnected() || this.isDiscovering()) {
@@ -245,13 +280,28 @@ class BleInterface extends events_1.default {
245
280
  return;
246
281
  this.logEvent({ message: 'stopping peripheral discovery ...' });
247
282
  this.discoverTask.stop();
248
- this.getBinding().off('discover', this.onDiscovered);
283
+ const ble = this.getBinding();
284
+ ble.off('discover', this.onDiscovered);
249
285
  return new Promise(done => {
250
- this.getBinding().stopScanning(() => {
286
+ ble.stopScanning(() => {
251
287
  done();
252
288
  });
253
289
  });
254
290
  }
291
+ emitDisconnectAllPeripherals() {
292
+ this.connectedPeripherals.forEach(p => {
293
+ const peripheral = p.getPeripheral();
294
+ peripheral.emit('disconnect');
295
+ });
296
+ this.connectedPeripherals = [];
297
+ }
298
+ disconnectAllPeripherals() {
299
+ return __awaiter(this, void 0, void 0, function* () {
300
+ const promises = this.connectedPeripherals.map(p => p.disconnect());
301
+ yield Promise.allSettled(promises);
302
+ this.connectedPeripherals = [];
303
+ });
304
+ }
255
305
  isDiscovering() {
256
306
  var _a;
257
307
  return ((_a = this.discoverTask) === null || _a === void 0 ? void 0 : _a.isRunning()) === true;
@@ -275,21 +325,6 @@ class BleInterface extends events_1.default {
275
325
  });
276
326
  });
277
327
  }
278
- pauseDiscovery() {
279
- this.getBinding().off('discover', this.onDiscovered);
280
- return new Promise(done => {
281
- try {
282
- this.getBinding().stopScanning();
283
- done();
284
- }
285
- catch (err) {
286
- done();
287
- }
288
- });
289
- }
290
- resumeDiscovery() {
291
- return this.discoverPeripherals();
292
- }
293
328
  onPeripheralFound(peripheral) {
294
329
  if (!this.isConnected() || !this.isDiscovering())
295
330
  return;
@@ -303,24 +338,33 @@ class BleInterface extends events_1.default {
303
338
  return;
304
339
  }
305
340
  if (announcement.serviceUUIDs.length === 0) {
306
- if (this.isCompleting(announcement)) {
307
- return;
308
- }
309
- this.addCompleting(announcement);
310
- setTimeout(() => {
311
- if (this.find(announcement)) {
312
- this.removeCompleting(announcement);
313
- return;
314
- }
315
- this.updateWithServices(announcement)
316
- .then(() => {
317
- if (this.isSupportedPeripheral(announcement))
318
- this.addService(announcement);
319
- });
320
- }, 1000);
341
+ return;
342
+ }
343
+ const isWahoo = this.checkForWahooEnhancement(announcement);
344
+ if (isWahoo) {
345
+ this.processWahooAnnouncement(announcement);
346
+ return;
321
347
  }
322
348
  this.addService(announcement);
323
349
  }
350
+ checkForWahooEnhancement(announcement) {
351
+ if (announcement.name.includes('KICKR')) {
352
+ const supported = announcement.serviceUUIDs.map(s => (0, utils_1.beautifyUUID)(s));
353
+ if (supported.length === 1 && supported[0] === '1818')
354
+ return true;
355
+ }
356
+ return false;
357
+ }
358
+ processWahooAnnouncement(announcement) {
359
+ if (this.isCompleting(announcement)) {
360
+ return;
361
+ }
362
+ this.updateWithServices(announcement)
363
+ .then(() => {
364
+ if (this.isSupportedPeripheral(announcement))
365
+ this.addService(announcement);
366
+ });
367
+ }
324
368
  buildAnnouncement(peripheral) {
325
369
  var _a;
326
370
  return {
@@ -335,9 +379,10 @@ class BleInterface extends events_1.default {
335
379
  return __awaiter(this, void 0, void 0, function* () {
336
380
  if (!this.isConnected() || !this.isDiscovering())
337
381
  return;
382
+ this.addCompleting(announcement);
383
+ this.logEvent({ message: 'updateWithServices', peripheral: announcement.name });
338
384
  try {
339
- yield this.discoverServices(announcement);
340
- return announcement;
385
+ announcement.serviceUUIDs = yield this.discoverServices(announcement);
341
386
  }
342
387
  catch (err) {
343
388
  this.logError(err, 'updateWithServices');
@@ -350,15 +395,14 @@ class BleInterface extends events_1.default {
350
395
  const device = Object.assign({}, announcement);
351
396
  delete device.peripheral;
352
397
  const { peripheral } = announcement;
353
- let paused = false;
354
398
  try {
355
399
  peripheral.on('error', (err) => {
356
400
  peripheral.removeAllListeners();
357
- this.logEvent({ message: 'Device error', error: err.message });
401
+ this.logEvent({ message: 'peripheral error', error: err.message });
358
402
  });
359
403
  peripheral.on('disconnect', () => {
360
404
  peripheral.removeAllListeners();
361
- this.logEvent({ message: 'Device disconnected' });
405
+ this.logEvent({ message: 'peripheral disconnected' });
362
406
  });
363
407
  yield peripheral.connectAsync();
364
408
  if (peripheral.discoverServicesAsync !== undefined) {
@@ -369,15 +413,12 @@ class BleInterface extends events_1.default {
369
413
  const res = yield peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
370
414
  announcement.serviceUUIDs = res.services.map(s => s.uuid);
371
415
  }
372
- peripheral.removeAllListeners();
373
416
  }
374
417
  catch (err) {
375
418
  this.logEvent({ message: 'discover services failed', reason: err.message, device });
376
419
  }
377
- if (paused) {
378
- yield this.resumeDiscovery();
379
- }
380
- return device.serviceUUIDs;
420
+ peripheral === null || peripheral === void 0 ? void 0 : peripheral.removeAllListeners();
421
+ return announcement.serviceUUIDs;
381
422
  });
382
423
  }
383
424
  isScanning() {
@@ -386,6 +427,7 @@ class BleInterface extends events_1.default {
386
427
  }
387
428
  startScan() {
388
429
  this.logEvent({ message: 'scan started', scanning: this.isScanning() });
430
+ this.emitted = [];
389
431
  this.emitCachedDevices();
390
432
  return new Promise(() => {
391
433
  });
@@ -398,11 +440,22 @@ class BleInterface extends events_1.default {
398
440
  });
399
441
  }
400
442
  emitDevice(service) {
443
+ if (this.alreadyEmitted(service)) {
444
+ return;
445
+ }
401
446
  const settings = this.createDeviceSetting(service);
447
+ this.logEvent({ message: 'device found', settings });
402
448
  this.emit('device', settings, service);
449
+ this.emitted.push(service);
450
+ }
451
+ alreadyEmitted(service) {
452
+ return this.emitted.find(s => s.name === service.name || s.peripheral.address === service.peripheral.address) !== undefined;
403
453
  }
404
454
  buildDeviceSettings(matching = []) {
405
- return matching.map((name) => ({ interface: BleInterface.INTERFACE_NAME, name }));
455
+ return matching.map((name) => {
456
+ const announcement = this.services.find(s => s.service.name === name);
457
+ return this.createDeviceSetting(announcement.service);
458
+ });
406
459
  }
407
460
  addCompleting(service) {
408
461
  const existing = this.incompleteServices.find(s => s.name === service.name);
@@ -468,7 +521,7 @@ class BleInterface extends events_1.default {
468
521
  const expected = this.expectedServices.map(utils_1.parseUUID);
469
522
  const supported = (_b = found.filter(uuid => expected.includes(uuid))) !== null && _b !== void 0 ? _b : [];
470
523
  if (!supported.length) {
471
- this.logEvent({ message: 'service not supported', name: service.name, uuids: service.serviceUUIDs });
524
+ this.logEvent({ message: 'peripheral not supported', name: service.name, uuids: service.serviceUUIDs });
472
525
  this.addUnsupported(service);
473
526
  }
474
527
  return supported.length > 0;
@@ -484,8 +537,10 @@ class BleInterface extends events_1.default {
484
537
  }
485
538
  connectBle() {
486
539
  return __awaiter(this, void 0, void 0, function* () {
540
+ this.connectAttemptCnt++;
487
541
  const state = this.getBinding().state;
488
542
  if (state === 'poweredOn') {
543
+ this.logEvent({ message: 'BLE connected' });
489
544
  return true;
490
545
  }
491
546
  const res = yield this.waitForBleConnected();
@@ -500,10 +555,7 @@ class BleInterface extends events_1.default {
500
555
  });
501
556
  this.getBinding().on('stateChange', (state) => {
502
557
  if (state === 'poweredOn') {
503
- this.logEvent({ message: 'Ble connect result: success' });
504
- this.getBinding().removeAllListeners('stateChange');
505
- this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
506
- this.getBinding().on('error', console.log);
558
+ this.onConnected();
507
559
  return done(true);
508
560
  }
509
561
  else {
@@ -512,18 +564,50 @@ class BleInterface extends events_1.default {
512
564
  });
513
565
  });
514
566
  }
567
+ onError(err) {
568
+ this.logError(err, 'BLE connect');
569
+ }
570
+ onConnected() {
571
+ this.logEvent({ message: 'BLE connected' });
572
+ this.getBinding().removeAllListeners('error');
573
+ this.getBinding().removeAllListeners('stateChange');
574
+ this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
575
+ this.getBinding().on('error', this.onError.bind(this));
576
+ }
577
+ onDisconnected() {
578
+ return __awaiter(this, void 0, void 0, function* () {
579
+ this.logEvent({ message: 'BLE Disconnected' });
580
+ yield this.disconnect(true);
581
+ this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
582
+ this.getBinding().on('error', this.onError.bind(this));
583
+ });
584
+ }
515
585
  onBleStateChange(state) {
586
+ if (state !== 'poweredOn') {
587
+ this.onDisconnected();
588
+ }
589
+ else
590
+ this.onConnected();
591
+ }
592
+ getAdapterFactory() {
593
+ return factories_1.BleAdapterFactory.getInstance('ble');
594
+ }
595
+ getConnectTimeout() {
596
+ return BLE_DEFAULT_CONNECT_TIMEOUT;
597
+ }
598
+ getExpectedServices() {
599
+ return this.getAdapterFactory().getAllSupportedServices();
516
600
  }
517
601
  logEvent(event) {
518
602
  if (this.logDisabled && event.message !== 'Error')
519
603
  return;
520
- this.getLogger().logEvent(event);
604
+ this.getLogger().logEvent(Object.assign(Object.assign({}, event), { interface: 'ble' }));
521
605
  const emitPayload = Object.assign({}, event);
522
606
  delete emitPayload.ts;
523
607
  this.emit('log', emitPayload);
524
608
  const w = global.window;
525
609
  if (this.debug || (w === null || w === void 0 ? void 0 : w.SERVICE_DEBUG) || process.env.DEBUG)
526
- console.log(`~~~ ${this.logger.getName().toUpperCase()}-SVC`, event);
610
+ console.log(`~~~ ${this.logger.getName().toUpperCase()}-SVC`, Object.assign(Object.assign({}, event), { interface: 'ble' }));
527
611
  }
528
612
  logError(err, fn, args) {
529
613
  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;