incyclist-devices 2.0.0-beta.1 → 2.0.1

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 (114) hide show
  1. package/README.MD +238 -0
  2. package/lib/adapters.d.ts +1 -0
  3. package/lib/adapters.js +19 -0
  4. package/lib/antv2/adapter-factory.d.ts +8 -7
  5. package/lib/antv2/adapter-factory.js +4 -2
  6. package/lib/antv2/adapter.d.ts +3 -2
  7. package/lib/antv2/adapter.js +15 -4
  8. package/lib/antv2/ant-interface.d.ts +6 -2
  9. package/lib/antv2/ant-interface.js +27 -21
  10. package/lib/antv2/binding.d.ts +1 -1
  11. package/lib/antv2/binding.js +1 -1
  12. package/lib/antv2/fe/adapter.d.ts +12 -9
  13. package/lib/antv2/fe/adapter.js +67 -27
  14. package/lib/antv2/hr/adapter.d.ts +6 -5
  15. package/lib/antv2/hr/adapter.js +19 -16
  16. package/lib/antv2/index.d.ts +2 -2
  17. package/lib/antv2/pwr/adapter.d.ts +6 -4
  18. package/lib/antv2/pwr/adapter.js +24 -16
  19. package/lib/antv2/sensor-factory.d.ts +2 -2
  20. package/lib/antv2/types.d.ts +5 -2
  21. package/lib/antv2/types.js +3 -0
  22. package/lib/antv2/utils.d.ts +3 -0
  23. package/lib/antv2/utils.js +12 -1
  24. package/lib/base/adpater.d.ts +14 -2
  25. package/lib/base/adpater.js +43 -4
  26. package/lib/ble/adapter-factory.d.ts +18 -16
  27. package/lib/ble/adapter-factory.js +54 -45
  28. package/lib/ble/base/adapter.d.ts +53 -0
  29. package/lib/ble/{adapter.js → base/adapter.js} +111 -9
  30. package/lib/ble/base/comms-utils.d.ts +7 -0
  31. package/lib/ble/base/comms-utils.js +91 -0
  32. package/lib/ble/{ble-comms.d.ts → base/comms.d.ts} +27 -17
  33. package/lib/ble/{ble-comms.js → base/comms.js} +179 -53
  34. package/lib/ble/bindings/index.d.ts +2 -0
  35. package/lib/ble/bindings/index.js +8 -0
  36. package/lib/ble/bindings/linux.d.ts +15 -0
  37. package/lib/ble/bindings/linux.js +39 -0
  38. package/lib/ble/bindings/mock.d.ts +9 -0
  39. package/lib/ble/bindings/mock.js +108 -0
  40. package/lib/ble/bindings/types.d.ts +57 -0
  41. package/lib/ble/bindings/types.js +96 -0
  42. package/lib/ble/ble-interface.d.ts +34 -46
  43. package/lib/ble/ble-interface.js +242 -345
  44. package/lib/ble/ble-peripheral.d.ts +4 -2
  45. package/lib/ble/ble-peripheral.js +39 -8
  46. package/lib/ble/consts.d.ts +1 -0
  47. package/lib/ble/consts.js +2 -1
  48. package/lib/ble/cp/adapter.d.ts +1 -2
  49. package/lib/ble/cp/adapter.js +2 -15
  50. package/lib/ble/cp/comm.d.ts +8 -5
  51. package/lib/ble/cp/comm.js +12 -27
  52. package/lib/ble/elite/adapter.d.ts +1 -2
  53. package/lib/ble/elite/adapter.js +12 -19
  54. package/lib/ble/elite/comms.d.ts +8 -4
  55. package/lib/ble/elite/comms.js +12 -25
  56. package/lib/ble/fm/adapter.d.ts +3 -2
  57. package/lib/ble/fm/adapter.js +129 -70
  58. package/lib/ble/fm/comms.d.ts +8 -8
  59. package/lib/ble/fm/comms.js +33 -55
  60. package/lib/ble/fm/types.d.ts +5 -0
  61. package/lib/ble/hr/adapter.d.ts +1 -4
  62. package/lib/ble/hr/adapter.js +1 -18
  63. package/lib/ble/hr/comm.d.ts +6 -2
  64. package/lib/ble/hr/comm.js +6 -2
  65. package/lib/ble/hr/mock.d.ts +7 -0
  66. package/lib/ble/hr/mock.js +47 -0
  67. package/lib/ble/index.d.ts +2 -1
  68. package/lib/ble/index.js +5 -5
  69. package/lib/ble/peripheral-cache.d.ts +43 -0
  70. package/lib/ble/peripheral-cache.js +107 -0
  71. package/lib/ble/tacx/adapter.d.ts +1 -1
  72. package/lib/ble/tacx/adapter.js +20 -14
  73. package/lib/ble/tacx/comms.d.ts +6 -6
  74. package/lib/ble/tacx/comms.js +10 -43
  75. package/lib/ble/types.d.ts +54 -27
  76. package/lib/ble/types.js +0 -17
  77. package/lib/ble/utils.d.ts +15 -5
  78. package/lib/ble/utils.js +25 -66
  79. package/lib/ble/wahoo/adapter.d.ts +1 -1
  80. package/lib/ble/wahoo/adapter.js +12 -10
  81. package/lib/ble/wahoo/comms.d.ts +7 -6
  82. package/lib/ble/wahoo/comms.js +15 -17
  83. package/lib/index.d.ts +10 -7
  84. package/lib/index.js +21 -25
  85. package/lib/interfaces.d.ts +2 -1
  86. package/lib/interfaces.js +4 -0
  87. package/lib/modes/power-base.js +4 -0
  88. package/lib/serial/adapter.d.ts +5 -0
  89. package/lib/serial/adapter.js +19 -0
  90. package/lib/serial/bindings/tcp.d.ts +2 -1
  91. package/lib/serial/bindings/tcp.js +19 -5
  92. package/lib/serial/daum/DaumAdapter.d.ts +1 -1
  93. package/lib/serial/daum/DaumAdapter.js +16 -10
  94. package/lib/serial/daum/premium/adapter.d.ts +1 -0
  95. package/lib/serial/daum/premium/adapter.js +9 -2
  96. package/lib/serial/daum/premium/comms.js +10 -3
  97. package/lib/serial/daum/premium/mock.js +0 -1
  98. package/lib/serial/index.d.ts +3 -3
  99. package/lib/serial/index.js +2 -2
  100. package/lib/serial/kettler/ergo-racer/adapter.d.ts +1 -4
  101. package/lib/serial/kettler/ergo-racer/adapter.js +15 -39
  102. package/lib/serial/serial-interface.d.ts +3 -1
  103. package/lib/serial/serial-interface.js +43 -17
  104. package/lib/simulator/Simulator.d.ts +2 -0
  105. package/lib/simulator/Simulator.js +8 -5
  106. package/lib/types/adapter.d.ts +10 -3
  107. package/lib/types/device.d.ts +3 -0
  108. package/lib/types/interface.d.ts +7 -3
  109. package/package.json +3 -5
  110. package/lib/ble/adapter.d.ts +0 -41
  111. package/lib/ble/ble.d.ts +0 -57
  112. package/lib/ble/ble.js +0 -48
  113. package/lib/device.d.ts +0 -0
  114. package/lib/device.js +0 -0
@@ -13,15 +13,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const gd_eventlog_1 = require("gd-eventlog");
16
- const utils_1 = require("../utils/utils");
17
- const ble_1 = require("./ble");
18
- const ble_comms_1 = require("./ble-comms");
19
- const ble_peripheral_1 = __importDefault(require("./ble-peripheral"));
20
16
  const adapter_factory_1 = __importDefault(require("./adapter-factory"));
21
- const utils_2 = require("./utils");
22
- const CONNECT_TIMEOUT = 5000;
17
+ const utils_1 = require("./utils");
18
+ const comms_utils_1 = require("./base/comms-utils");
19
+ const peripheral_cache_1 = __importDefault(require("./peripheral-cache"));
20
+ const events_1 = __importDefault(require("events"));
21
+ const utils_2 = require("../utils/utils");
23
22
  const DEFAULT_SCAN_TIMEOUT = 20000;
24
- class BleInterface extends ble_1.BleInterfaceClass {
23
+ class BleInterface extends events_1.default {
25
24
  static getInstance(props = {}) {
26
25
  if (!BleInterface._instance) {
27
26
  BleInterface._instance = new BleInterface(props);
@@ -40,14 +39,38 @@ class BleInterface extends ble_1.BleInterfaceClass {
40
39
  return BleInterface._instance;
41
40
  }
42
41
  constructor(props = {}) {
43
- super(props);
42
+ super();
44
43
  this.scanState = { isScanning: false, isConnecting: false, timeout: undefined, isBackgroundScan: false };
45
44
  this.connectState = { isConnecting: false, isConnected: false, isInitSuccess: false };
46
- this.devices = [];
47
- this.peripheralCache = [];
45
+ this.props = props;
46
+ if (props.binding)
47
+ this.setBinding(props.binding);
48
+ this.peripheralCache = new peripheral_cache_1.default();
49
+ this.connectedDevices = [];
48
50
  if (props.logger)
49
51
  this.logger = props.logger;
50
- this.logger = new gd_eventlog_1.EventLogger('BLE');
52
+ else
53
+ this.logger = new gd_eventlog_1.EventLogger('BLE');
54
+ }
55
+ getBinding() { return this.binding; }
56
+ setBinding(binding) { if (binding)
57
+ this.binding = binding; }
58
+ getName() {
59
+ return 'ble';
60
+ }
61
+ startConnectSensor() {
62
+ this.sensorIsConnecting = true;
63
+ }
64
+ stopConnectSensor() {
65
+ this.sensorIsConnecting = false;
66
+ }
67
+ waitForSensorConnectionFinish() {
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ while (this.sensorIsConnecting && this.connectState.isConnected) {
70
+ yield (0, utils_2.sleep)(100);
71
+ }
72
+ return;
73
+ });
51
74
  }
52
75
  getAdapterFactory() {
53
76
  return adapter_factory_1.default.getInstance();
@@ -61,7 +84,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
61
84
  }
62
85
  }
63
86
  onStateChange(state) {
64
- if (state !== ble_1.BleState.POWERED_ON) {
87
+ if (state !== 'poweredOn') {
65
88
  this.connectState.isConnected = false;
66
89
  }
67
90
  else {
@@ -71,8 +94,8 @@ class BleInterface extends ble_1.BleInterfaceClass {
71
94
  onError(err) {
72
95
  this.logEvent({ message: 'error', error: err.message, stack: err.stack });
73
96
  }
74
- connect(props = {}) {
75
- const timeout = props.timeout || 2000;
97
+ connect(to) {
98
+ const timeout = this.props.timeout || to || 2000;
76
99
  return new Promise((resolve, reject) => {
77
100
  if (this.connectState.isConnected) {
78
101
  return resolve(true);
@@ -85,34 +108,11 @@ class BleInterface extends ble_1.BleInterfaceClass {
85
108
  this.connectState.isConnecting = false;
86
109
  this.connectState.timeout = null;
87
110
  this.logEvent({ message: 'Ble connect result: timeout' });
88
- reject(new Error('timeout'));
111
+ resolve(false);
89
112
  }, timeout);
90
113
  try {
91
- if (!this.connectState.isInitSuccess) {
92
- const binding = this.getBinding()._bindings;
93
- if (binding) {
94
- const binding_init_original = binding.init.bind(binding);
95
- const self = this;
96
- binding.on('error', (err) => { this.getBinding().emit('error', err); });
97
- binding.init = function () {
98
- try {
99
- binding_init_original();
100
- self.connectState.isInitSuccess = true;
101
- }
102
- catch (err) {
103
- self.connectState.isInitSuccess = false;
104
- self.connectState.isConnected = false;
105
- self.connectState.isConnecting = false;
106
- self.logEvent({ message: 'connect result: error', error: err.message });
107
- return reject(new Error(err.message));
108
- }
109
- };
110
- }
111
- else {
112
- }
113
- }
114
114
  const state = this.getBinding().state;
115
- if (state === ble_1.BleState.POWERED_ON) {
115
+ if (state === 'poweredOn') {
116
116
  clearTimeout(this.connectState.timeout);
117
117
  this.connectState.timeout = null;
118
118
  this.getBinding().removeAllListeners('stateChange');
@@ -132,7 +132,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
132
132
  return reject(err);
133
133
  });
134
134
  this.getBinding().on('stateChange', (state) => {
135
- if (state === ble_1.BleState.POWERED_ON) {
135
+ if (state === 'poweredOn') {
136
136
  clearTimeout(this.connectState.timeout);
137
137
  this.connectState.timeout = null;
138
138
  this.getBinding().removeAllListeners('stateChange');
@@ -170,11 +170,11 @@ class BleInterface extends ble_1.BleInterfaceClass {
170
170
  if (this.scanState.isScanning) {
171
171
  yield this.stopScan();
172
172
  }
173
- const connectedDevices = this.devices.filter(d => d.isConnected);
173
+ const devices = this.getAdapterFactory().getAllInstances();
174
+ const connectedDevices = devices.filter(d => d.isConnected());
174
175
  for (let i = 0; i < connectedDevices.length; i++) {
175
176
  const d = connectedDevices[i];
176
- const device = d.device;
177
- yield device.disconnect();
177
+ yield d.close();
178
178
  }
179
179
  this.connectState.isConnected = false;
180
180
  this.connectState.isConnecting = false;
@@ -205,39 +205,18 @@ class BleInterface extends ble_1.BleInterfaceClass {
205
205
  }, 100);
206
206
  });
207
207
  }
208
- addPeripheralToCache(peripheral, props = {}) {
209
- const info = this.peripheralCache.find(i => i.address === peripheral.address);
210
- const connector = info && info.connector ? info.connector : new ble_peripheral_1.default(this, peripheral);
211
- this.peripheralCache.push(Object.assign({ address: peripheral.address, ts: Date.now(), peripheral, connector }, props));
212
- }
213
208
  onDisconnect(peripheral) {
214
- const idx = this.peripheralCache.findIndex(i => i.address === peripheral.address);
215
- if (idx !== -1)
216
- this.peripheralCache.splice(idx, 1);
217
- }
218
- getConnector(peripheral) {
219
- const info = this.peripheralCache.find(i => i.address === peripheral.address);
220
- if (!info) {
221
- const connector = new ble_peripheral_1.default(this, peripheral);
222
- this.peripheralCache.push({ address: peripheral.address, ts: Date.now(), peripheral, connector });
223
- return connector;
224
- }
225
- return info.connector;
226
- }
227
- findPeripheral(peripheral) {
228
- const info = this.peripheralCache.find(i => i.address === peripheral.address || peripheral.address === i.peripheral.address || peripheral.name === i.peripheral.name || peripheral.id === i.peripheral.id);
229
- return info ? info.peripheral : undefined;
209
+ this.peripheralCache.remove(peripheral);
230
210
  }
231
211
  getCharacteristics(peripheral) {
232
212
  return __awaiter(this, void 0, void 0, function* () {
233
213
  let characteristics = undefined;
234
- let chachedPeripheralInfo = this.peripheralCache.find(i => i.address === peripheral.address);
214
+ let chachedPeripheralInfo = this.peripheralCache.find({ peripheral });
235
215
  if (chachedPeripheralInfo && Date.now() - chachedPeripheralInfo.ts > 600000) {
236
216
  chachedPeripheralInfo.ts = Date.now();
237
217
  }
238
218
  if (!chachedPeripheralInfo) {
239
- this.addPeripheralToCache(peripheral);
240
- chachedPeripheralInfo = this.peripheralCache.find(i => i.address === peripheral.address);
219
+ chachedPeripheralInfo = this.peripheralCache.add({ address: peripheral.address, ts: Date.now(), peripheral });
241
220
  }
242
221
  const connector = chachedPeripheralInfo.connector;
243
222
  if (!chachedPeripheralInfo.characteristics) {
@@ -247,130 +226,23 @@ class BleInterface extends ble_1.BleInterfaceClass {
247
226
  peripheral.state = connector.getState();
248
227
  yield connector.initialize();
249
228
  characteristics = connector.getCharachteristics();
250
- this.logEvent({ message: 'characteristic info (+):', info: characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
229
+ this.logEvent({ message: 'characteristic info (+):', address: peripheral.address, info: characteristics.map(utils_1.getCharachteristicsInfo) });
251
230
  chachedPeripheralInfo.characteristics = characteristics;
252
231
  chachedPeripheralInfo.state = { isConfigured: true, isLoading: false, isInterrupted: false };
253
232
  }
254
233
  catch (err) {
255
- console.log(err);
234
+ console.log('~~ ERROR', err);
256
235
  }
257
236
  }
258
237
  else {
259
238
  characteristics = chachedPeripheralInfo.characteristics;
260
- this.logEvent({ message: 'characteristic info (*):', info: characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
239
+ this.logEvent({ message: 'characteristic info (*):', address: peripheral.address, info: characteristics.map(utils_1.getCharachteristicsInfo) });
261
240
  }
262
241
  if (!characteristics)
263
242
  this.logEvent({ message: 'characteristic info:', info: 'none' });
264
243
  return characteristics;
265
244
  });
266
245
  }
267
- createDeviceComms(DeviceClass, peripheral, characteristics) {
268
- try {
269
- const C = DeviceClass;
270
- const device = new C({ peripheral });
271
- const cids = characteristics ? characteristics.map(c => (0, utils_2.uuid)(c.uuid)) : [];
272
- this.logEvent({ message: 'trying to create device', peripheral: peripheral.address, characteristics: cids, profile: device.getProfile() });
273
- const existingDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
274
- if (existingDevice)
275
- return existingDevice.device;
276
- device.setInterface(this);
277
- if (characteristics && device.isMatching(cids)) {
278
- device.characteristics = characteristics;
279
- device.setCharacteristicUUIDs(characteristics.map(c => c.uuid));
280
- return device;
281
- }
282
- else {
283
- this.logEvent({ message: 'failed to create device', peripheral: peripheral.address, profile: device.getProfile() });
284
- }
285
- }
286
- catch (err) {
287
- this.logEvent({ message: 'error', fn: '', error: err.message || err, stack: err.stack });
288
- }
289
- }
290
- connectDevice(requested, timeout = DEFAULT_SCAN_TIMEOUT + CONNECT_TIMEOUT) {
291
- return __awaiter(this, void 0, void 0, function* () {
292
- const { id, name, address } = requested;
293
- const profile = requested instanceof ble_comms_1.BleComms ?
294
- (requested.getProfile && typeof (requested.getProfile) === 'function' ? requested.getProfile() : undefined) :
295
- requested.profile;
296
- this.logEvent({ message: 'connectDevice', id, name, address, profile, isbusy: this.scanState.isConnecting });
297
- if (this.scanState.isConnecting) {
298
- yield this.waitForConnectFinished(CONNECT_TIMEOUT);
299
- }
300
- this.scanState.isConnecting = true;
301
- const existing = this.devices.find(i => (!profile || i.device.getProfile() === profile) && (i.device.address === requested.address || i.device.id === requested.id || i.device.name === requested.name));
302
- if (existing) {
303
- this.logEvent({ message: 'connect existing device' });
304
- yield existing.device.connect();
305
- this.scanState.isConnecting = false;
306
- return existing.device;
307
- }
308
- const peripheralInfo = this.peripheralCache.find(i => (i.address === requested.address || (i.periphal && i.peripheral.id === requested.id)));
309
- if (peripheralInfo) {
310
- if (!peripheralInfo.characteristic) {
311
- yield this.getCharacteristics(peripheralInfo.periphal);
312
- const DeviceClasses = this.getAdapterFactory().getDeviceClasses(peripheralInfo.peripheral, { profile });
313
- if (!DeviceClasses || DeviceClasses.length === 0)
314
- return;
315
- const devices = DeviceClasses.map(C => this.createDeviceComms(C, peripheralInfo.periphal, peripheralInfo.characteristics));
316
- if (devices && devices.length > 0) {
317
- for (let i = 0; i < devices.length; i++) {
318
- const idx = this.devices.push({ device: devices[i], isConnected: false }) - 1;
319
- if (!devices[i].isConnected())
320
- yield devices[i].connect();
321
- this.devices[idx].isConnected = true;
322
- }
323
- }
324
- }
325
- const connectedDevice = this.devices.find(d => d.isConnected);
326
- if (connectedDevice)
327
- return connectedDevice.device;
328
- }
329
- let devices = [];
330
- let retry = false;
331
- let retryCount = 0;
332
- do {
333
- if (retryCount > 0) {
334
- this.logEvent({ message: 'retry connect device', id, name, address, profile, retryCount });
335
- }
336
- try {
337
- devices = yield this.scan({ timeout: DEFAULT_SCAN_TIMEOUT, requested: requested });
338
- if (devices.length === 0) {
339
- retryCount++;
340
- retry = retryCount < 5;
341
- }
342
- }
343
- catch (err) {
344
- if (err.message === 'scanning already in progress') {
345
- yield (0, utils_1.sleep)(1000);
346
- retryCount++;
347
- retry = retryCount < 5;
348
- continue;
349
- }
350
- this.scanState.isConnecting = false;
351
- throw err;
352
- }
353
- } while (devices.length === 0 && retry);
354
- if (devices.length === 0) {
355
- this.logEvent({ message: 'connectDevice failure', id, name, address, profile, error: 'device not found' });
356
- this.scanState.isConnecting = false;
357
- throw new Error('device not found');
358
- }
359
- if (devices[0]) {
360
- this.logEvent({ message: 'connectDevice connecting', id, name, address, profile });
361
- const connected = yield devices[0].connect();
362
- this.scanState.isConnecting = false;
363
- if (connected) {
364
- this.logEvent({ message: 'connectDevice success', id, name, address, profile });
365
- return devices[0];
366
- }
367
- else {
368
- this.logEvent({ message: 'connectDevice failure', id, name, address, profile });
369
- throw new Error('connect failed');
370
- }
371
- }
372
- });
373
- }
374
246
  waitForScanFinished(timeout) {
375
247
  const waitStart = Date.now();
376
248
  const waitTimeout = waitStart + timeout;
@@ -387,174 +259,222 @@ class BleInterface extends ble_1.BleInterfaceClass {
387
259
  }, 100);
388
260
  });
389
261
  }
390
- scan(props) {
262
+ onPeripheralFound(p, callback, props = {}) {
391
263
  return __awaiter(this, void 0, void 0, function* () {
392
- const { timeout = DEFAULT_SCAN_TIMEOUT, deviceTypes = [], requested } = props;
393
- let profile;
394
- if (requested)
395
- profile = requested instanceof ble_comms_1.BleComms ?
396
- (requested.getProfile && typeof (requested.getProfile) === 'function' ? requested.getProfile() : undefined) :
397
- requested.profile;
398
- const { id, address, name } = requested || {};
399
- const scanForDevice = (requested !== null && requested !== undefined);
400
- const services = (!deviceTypes || deviceTypes.length === 0) ? this.getAdapterFactory().getAllSupportedServices() : (0, utils_2.getServicesFromDeviceTypes)(deviceTypes);
401
- const bleBinding = this.getBinding();
402
- if (!bleBinding)
403
- return Promise.reject(new Error('no binding defined'));
404
- if (!this.isConnected()) {
405
- yield this.connect();
264
+ let peripheral = p;
265
+ if (!peripheral || !peripheral.advertisement || !peripheral.advertisement.localName) {
266
+ return;
267
+ }
268
+ const scanForDevice = (props.comms !== undefined) || (props.request !== undefined && props.request !== null);
269
+ const request = props.comms ? props.comms.getSettings() : props.request;
270
+ if (scanForDevice && this.scanState.peripherals.size > 0) {
271
+ return;
272
+ }
273
+ if (!this.scanState.peripherals)
274
+ this.scanState.peripherals = new Map();
275
+ if (peripheral.address === undefined || peripheral.address === '')
276
+ peripheral.address = peripheral.id || peripheral.name;
277
+ const isPeripheralProcessed = this.scanState.peripherals.get(peripheral.address) !== undefined;
278
+ if (isPeripheralProcessed) {
279
+ return;
406
280
  }
407
- const peripheralsProcessed = [];
408
- const devicesProcessed = [];
409
- this.logEvent({ message: 'scan()', props: { timeout }, scanState: this.scanState,
410
- peripheralCache: this.peripheralCache.map(i => ({ address: i.address, ts: i.ts, name: i.peripheral ? i.peripheral.advertisement.localName : '' })),
411
- deviceCache: this.devices.map(i => ({ address: i.device.address, profile: i.device.getProfile(), isConnected: i.isConnected }))
412
- });
413
- let opStr;
414
281
  if (scanForDevice) {
415
- opStr = 'search device';
416
- this.logEvent({ message: 'search device request', services, device: { id, address, name }, deviceTypes });
282
+ let found = false;
283
+ found =
284
+ (request.name && peripheral.advertisement && request.name === peripheral.advertisement.localName) ||
285
+ (request.address && request.address === peripheral.address);
286
+ if (!found) {
287
+ return;
288
+ }
289
+ this.logEvent({ message: 'search device: found device', peripheral: (0, utils_1.getPeripheralInfo)(peripheral), scanForDevice, callback: callback !== undefined });
290
+ this.scanState.peripherals.set(peripheral.address, peripheral);
291
+ const characteristics = yield this.getCharacteristics(peripheral);
292
+ callback(peripheral, characteristics);
293
+ return;
417
294
  }
418
295
  else {
419
- opStr = 'scan';
420
- const supported = adapter_factory_1.default.getInstance().getAllAdapters().map(i => i.protocol);
421
- this.logEvent({ message: 'scan start', services, supported });
296
+ this.logEvent({ message: 'BLE scan: found device', peripheral: (0, utils_1.getPeripheralInfo)(peripheral), scanForDevice, callback: callback !== undefined });
297
+ this.scanState.peripherals.set(peripheral.address, peripheral);
298
+ const { protocolFilter } = props;
299
+ const connector = this.peripheralCache.getConnector(p);
300
+ const characteristics = yield this.getCharacteristics(p);
301
+ const announcedServices = connector.getServices();
302
+ const services = announcedServices ? announcedServices.map(utils_1.uuid) : undefined;
303
+ peripheral = connector.getPeripheral();
304
+ const DeviceClasses = this.getAdapterFactory().getDeviceClasses(peripheral, { services }) || [];
305
+ const MatchingClasses = protocolFilter && DeviceClasses ? DeviceClasses.filter(C => protocolFilter.includes(C.protocol)) : DeviceClasses;
306
+ const DeviceClass = (0, comms_utils_1.getBestDeviceMatch)(MatchingClasses.filter(C => C.isMatching(characteristics.map(c => c.uuid))));
307
+ this.logEvent({ message: 'BLE scan: device connected', peripheral: (0, utils_1.getPeripheralInfo)(peripheral), services, protocols: DeviceClasses.map(c => c.protocol) });
308
+ if (!DeviceClass)
309
+ return callback(null);
310
+ const { id, name, address } = (0, utils_1.getPeripheralInfo)(peripheral);
311
+ const settings = { protocol: DeviceClass.protocol, interface: 'ble', id, name: peripheral.name || name, address: peripheral.address || address };
312
+ callback(settings, characteristics);
313
+ }
314
+ });
315
+ }
316
+ scanForDevice(comms, props) {
317
+ return __awaiter(this, void 0, void 0, function* () {
318
+ const { timeout = DEFAULT_SCAN_TIMEOUT } = props;
319
+ const request = comms.getSettings();
320
+ const { protocol } = request;
321
+ const ble = this.getBinding();
322
+ if (!this.isConnected()) {
323
+ yield this.connect();
422
324
  }
325
+ const device = adapter_factory_1.default.getInstance().createInstance(request);
326
+ if (device.isConnected())
327
+ return device.getComms().peripheral;
328
+ let opStr;
329
+ opStr = 'search device';
330
+ this.logEvent({ message: 'search device request', request });
423
331
  if (this.scanState.isScanning) {
424
332
  try {
425
333
  this.logEvent({ message: `${opStr}: waiting for previous scan to finish` });
426
334
  yield this.waitForScanFinished(timeout);
427
335
  }
428
336
  catch (err) {
429
- this.logEvent({ message: `${opStr} result: already scanning` });
430
- return Promise.reject(err);
337
+ this.logEvent({ message: `${opStr} result: already scanning`, error: err.message });
338
+ throw (err);
431
339
  }
432
340
  }
433
341
  return new Promise((resolve, reject) => {
434
342
  this.scanState.isScanning = true;
435
- if (scanForDevice) {
436
- if (this.devices && this.devices.length > 0) {
437
- const knownDevices = this.devices.map(i => ({ name: i.device.name, address: i.device.address, isConnected: i.isConnected, connectState: i.device.getConnectState() }));
438
- this.logEvent({ message: `${opStr}: check if already registered`, device: { name, address }, knownDevices });
439
- const existing = this.devices.find(i => (i.device.address === address || i.device.name === name || i.device.id === id));
440
- if (existing)
441
- this.logEvent({ message: `${opStr}: device already registered`, device: { name, address } });
442
- }
443
- }
343
+ this.scanState.peripherals = new Map();
444
344
  const onTimeout = () => {
445
345
  if (!this.scanState.isScanning || !this.scanState.timeout)
446
346
  return;
447
347
  this.scanState.timeout = null;
448
- this.logEvent({ message: `${opStr} result: devices found`, requested: scanForDevice ? { name, address, profile } : undefined, devices: this.devices.map(i => i.device.name + (!i.device.name || i.device.name === '') ? `addr=${i.device.address}` : '') });
449
- this.getBinding().removeAllListeners('discover');
450
- this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name, address, profile } : undefined, });
451
- bleBinding.stopScanning(() => {
348
+ this.logEvent({ message: `${opStr} result: timeout`, request });
349
+ ble.removeAllListeners('discover');
350
+ this.logEvent({ message: `${opStr}: stop scanning`, request });
351
+ ble.stopScanning(() => {
452
352
  this.scanState.isScanning = false;
453
- if (scanForDevice) {
454
- reject(new Error('device not found'));
455
- return;
456
- }
457
- resolve(this.devices.map(i => i.device));
353
+ reject(new Error('device not found'));
354
+ return;
458
355
  });
459
356
  };
460
- const onPeripheralFound = (peripheral, fromCache = false) => __awaiter(this, void 0, void 0, function* () {
461
- if (!peripheral || !peripheral.advertisement || !peripheral.advertisement.localName || !peripheral.advertisement.serviceUuids)
462
- return;
463
- if (fromCache) {
464
- this.logEvent({ message: 'adding from Cache', peripheral: peripheral.address });
465
- }
466
- else {
467
- const { id, name, address, advertisement = {} } = peripheral;
468
- this.logEvent({ message: 'BLE scan: found device', peripheral: { id, name: advertisement.localName, address, services: advertisement.serviceUuids } });
469
- }
470
- if (peripheral.address === undefined || peripheral.address === '')
471
- peripheral.address = peripheral.id;
472
- const isPeripheralProcessed = peripheralsProcessed.find(p => p === peripheral.address) !== undefined;
473
- if (isPeripheralProcessed)
474
- return;
475
- peripheralsProcessed.push(peripheral.address);
476
- if (scanForDevice && requested.name && requested.name !== peripheral.advertisement.localName)
477
- return;
478
- const connector = this.getConnector(peripheral);
479
- const characteristics = yield this.getCharacteristics(peripheral);
480
- const connectedServices = connector.getServices();
481
- const services = connectedServices ? connectedServices.map(cs => cs.uuid) : undefined;
482
- const connectedPeripheral = connector.getPeripheral();
483
- const { id, name, address, advertisement = {} } = connectedPeripheral;
484
- const DeviceClasses = this.getAdapterFactory().getDeviceClasses(connectedPeripheral, { profile, services }) || [];
485
- this.logEvent({ message: 'BLE scan: device connected', peripheral: { id, name, address, services: advertisement.serviceUuids }, services, classes: DeviceClasses.map(c => c.prototype.constructor.name) });
486
- let cntFound = 0;
487
- const DeviceClass = (0, utils_2.getBestDeviceMatch)(DeviceClasses);
488
- if (!DeviceClass)
489
- return;
490
- if (scanForDevice && cntFound > 0)
491
- return;
492
- const d = this.createDeviceComms(DeviceClass, peripheral, characteristics);
493
- if (!d) {
494
- this.logEvent({ message: `${opStr}: could not create device `, DeviceClass });
495
- return;
496
- }
497
- try {
498
- this.logEvent({ message: `${opStr}: connecting `, device: d.name, profile: d.getProfile(), address: d.address });
499
- yield d.connect();
500
- }
501
- catch (err) {
502
- this.logEvent({ message: 'error', fn: 'onPeripheralFound()', error: err.message || err, stack: err.stack });
503
- }
504
- if (scanForDevice) {
505
- if ((id && id !== '' && d.id === id) ||
506
- (address && address !== '' && d.address === address) ||
507
- (name && name !== '' && d.name === name))
508
- cntFound++;
509
- }
510
- else
511
- cntFound++;
512
- const existing = devicesProcessed.find(device => device.id === d.id && device.getProfile() === d.getProfile());
513
- if (!scanForDevice && cntFound > 0 && !existing) {
514
- this.logEvent({ message: `${opStr}: device found`, device: d.name, profile: d.getProfile(), address: d.address, services: d.services.join(',') });
515
- this.addDeviceToCache(d, peripheral.state === 'connected');
516
- devicesProcessed.push(d);
517
- this.emit('device', d);
518
- return;
357
+ this.logEvent({ message: `${opStr}: start scanning`, request, timeout });
358
+ let services = [];
359
+ if (protocol !== 'tacx') {
360
+ services = (device.getComms().getServices()) || [];
361
+ }
362
+ ble.startScanning(services, false, (err) => {
363
+ if (err) {
364
+ this.logEvent({ message: `${opStr} result: error`, request, error: err.message });
365
+ this.scanState.isScanning = false;
366
+ return reject(err);
519
367
  }
520
- if (scanForDevice && cntFound > 0) {
521
- this.logEvent({ message: `${opStr}: device found`, device: d.name, profile: d.getProfile(), address: d.address, services: d.services.join(',') });
522
- this.addDeviceToCache(d, peripheral.state === 'connected');
523
- devicesProcessed.push(d);
524
- this.emit('device', d);
525
- process.nextTick(() => {
526
- if (this.scanState.timeout) {
527
- clearTimeout(this.scanState.timeout);
528
- this.scanState.timeout = null;
529
- }
530
- this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name, address, profile } : undefined, });
531
- bleBinding.stopScanning(() => {
532
- this.getBinding().removeAllListeners('discover');
533
- this.scanState.isScanning = false;
534
- resolve([d]);
368
+ ble.on('discover', (p) => {
369
+ this.onPeripheralFound(p, (peripheral, characteristics) => {
370
+ device.getComms().characteristics = characteristics;
371
+ process.nextTick(() => {
372
+ if (this.scanState.timeout) {
373
+ clearTimeout(this.scanState.timeout);
374
+ this.scanState.timeout = null;
375
+ }
376
+ this.logEvent({ message: `${opStr}: stop scanning`, request });
377
+ ble.stopScanning(() => {
378
+ ble.removeAllListeners('discover');
379
+ this.scanState.isScanning = false;
380
+ resolve(peripheral);
381
+ });
535
382
  });
536
- });
383
+ }, { comms });
384
+ });
385
+ const cachedItem = this.peripheralCache.find(request);
386
+ if (cachedItem) {
387
+ this.logEvent({ message: `${opStr}: adding peripheral from cache `, peripheral: (0, utils_1.getPeripheralInfo)(cachedItem.peripheral) });
388
+ ble.emit('discover', cachedItem.peripheral);
537
389
  }
538
390
  });
539
- this.logEvent({ message: `${opStr}: start scanning`, requested: scanForDevice ? { name, address, profile } : undefined, timeout });
540
- let services = [];
541
- if (scanForDevice && name && !name.toLowerCase().startsWith('tacx')) {
542
- if (props.requested instanceof ble_comms_1.BleComms) {
543
- const device = props.requested;
544
- services = (device.getServices()) || [];
545
- }
391
+ this.scanState.timeout = setTimeout(onTimeout, timeout);
392
+ });
393
+ });
394
+ }
395
+ scan(props = {}) {
396
+ return __awaiter(this, void 0, void 0, function* () {
397
+ const { timeout = DEFAULT_SCAN_TIMEOUT, protocol, protocols } = props;
398
+ const requestedProtocols = protocols || [];
399
+ if (protocol && !requestedProtocols.find(p => p === protocol))
400
+ requestedProtocols.push(protocol);
401
+ const protocolFilter = requestedProtocols.length > 0 ? requestedProtocols : null;
402
+ const services = protocolFilter === null ? this.getAdapterFactory().getAllSupportedServices() : (0, comms_utils_1.getServicesFromProtocols)(protocolFilter);
403
+ const ble = this.getBinding();
404
+ const opStr = 'scan';
405
+ if (this.scanState.isScanning) {
406
+ try {
407
+ this.logEvent({ message: `${opStr}: waiting for previous scan to finish` });
408
+ yield this.waitForScanFinished(timeout);
546
409
  }
547
- bleBinding.startScanning(services, false, (err) => {
410
+ catch (err) {
411
+ this.logEvent({ message: `${opStr} result: already scanning` });
412
+ throw (err);
413
+ }
414
+ }
415
+ this.scanState.isScanning = true;
416
+ const tsStart = Date.now();
417
+ const tsTimeoutExpired = tsStart + timeout;
418
+ while (!this.isConnected() && this.scanState.isScanning && Date.now() < tsTimeoutExpired) {
419
+ const connected = yield this.connect();
420
+ if (!connected)
421
+ yield (0, utils_2.sleep)(1000);
422
+ }
423
+ if (Date.now() > tsTimeoutExpired) {
424
+ return [];
425
+ }
426
+ if (!this.scanState.isScanning) {
427
+ return [];
428
+ }
429
+ const adjustedScanTimeout = tsStart - Date.now() + timeout;
430
+ const supported = adapter_factory_1.default.getInstance().getAll().map(i => i.protocol);
431
+ this.logEvent({ message: 'scan start', services, supported });
432
+ return new Promise((resolve, reject) => {
433
+ this.scanState.peripherals = new Map();
434
+ const detected = [];
435
+ const requested = protocolFilter;
436
+ const onTimeout = () => {
437
+ if (!this.scanState.isScanning || !this.scanState.timeout)
438
+ return;
439
+ this.scanState.timeout = null;
440
+ const devices = detected.map(d => {
441
+ const { id, name, address, protocol } = d;
442
+ return { id, name, address, protocol };
443
+ });
444
+ this.logEvent({ message: `${opStr} result: timeout, devices found`, requested, devices });
445
+ ble.removeAllListeners('discover');
446
+ this.logEvent({ message: `${opStr}: stop scanning`, requested });
447
+ ble.stopScanning(() => {
448
+ this.scanState.isScanning = false;
449
+ resolve(detected);
450
+ });
451
+ };
452
+ this.logEvent({ message: `${opStr}: start scanning`, requested, timeout });
453
+ this.scanState.timeout = setTimeout(onTimeout, adjustedScanTimeout);
454
+ ble.startScanning(protocolFilter ? services : [], false, (err) => {
548
455
  if (err) {
549
- this.logEvent({ message: `${opStr} result: error`, requested: scanForDevice ? { name, address, profile } : undefined, error: err.message });
456
+ this.logEvent({ message: `${opStr} result: error`, requested, error: err.message });
550
457
  this.scanState.isScanning = false;
551
458
  return reject(err);
552
459
  }
553
- bleBinding.on('discover', (p) => {
554
- onPeripheralFound(p);
460
+ ble.on('discover', (p) => {
461
+ this.onPeripheralFound(p, (deviceSettings, characteristics) => {
462
+ if (deviceSettings) {
463
+ detected.push(deviceSettings);
464
+ const device = this.getAdapterFactory().createInstance(deviceSettings);
465
+ device.getComms().characteristics = characteristics;
466
+ this.emit('device', deviceSettings);
467
+ }
468
+ }, { protocolFilter });
555
469
  });
470
+ const cachedItems = this.peripheralCache.filter(protocolFilter ? services : []);
471
+ if (cachedItems && cachedItems.length > 0) {
472
+ cachedItems.map(c => c.peripheral).forEach(peripheral => {
473
+ this.logEvent({ message: `${opStr}: adding peripheral from cache `, peripheral: (0, utils_1.getPeripheralInfo)(peripheral) });
474
+ ble.emit('discover', peripheral);
475
+ });
476
+ }
556
477
  });
557
- this.scanState.timeout = setTimeout(onTimeout, timeout);
558
478
  });
559
479
  });
560
480
  }
@@ -565,13 +485,12 @@ class BleInterface extends ble_1.BleInterfaceClass {
565
485
  this.logEvent({ message: 'scan stop result: not scanning' });
566
486
  return true;
567
487
  }
568
- if (!this.getBinding())
488
+ const ble = this.getBinding();
489
+ if (!ble)
569
490
  throw new Error('no binding defined');
570
- this.getBinding().removeAllListeners('discover');
571
- const ongoing = this.peripheralCache.filter(i => i.state && i.state.isLoading);
572
- if (ongoing)
573
- ongoing.forEach(i => { i.isInterrupted = true; });
574
- yield this.getBinding().stopScanning();
491
+ ble.removeAllListeners('discover');
492
+ this.peripheralCache.handleStopScan();
493
+ ble.stopScanning();
575
494
  this.scanState.isScanning = false;
576
495
  this.logEvent({ message: 'scan stop result: success' });
577
496
  return true;
@@ -581,36 +500,14 @@ class BleInterface extends ble_1.BleInterfaceClass {
581
500
  return this.scanState.isScanning === true;
582
501
  }
583
502
  addConnectedDevice(device) {
584
- const existigDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
585
- if (existigDevice) {
586
- existigDevice.isConnected = true;
587
- return;
588
- }
589
- this.devices.push({ device, isConnected: true });
590
- }
591
- addDeviceToCache(device, isConnected) {
592
- const existigDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
593
- if (existigDevice) {
594
- return;
595
- }
596
- this.devices.push({ device, isConnected });
597
- }
598
- findConnected(device) {
599
- const connected = this.devices.find(i => i.device.id === device.id && i.isConnected);
600
- if (connected)
601
- return connected.device;
602
- return undefined;
603
- }
604
- findDeviceInCache(device) {
605
- const existing = this.devices.find(i => (i.device.id === device.id || i.device.address === device.address || i.device.name === device.name) && i.device.getProfile() === device.profile);
606
- return existing ? existing.device : undefined;
503
+ const idx = this.connectedDevices.findIndex(d => d.isSame(device));
504
+ if (idx === -1)
505
+ this.connectedDevices.push(device);
607
506
  }
608
507
  removeConnectedDevice(device) {
609
- const existigDevice = this.devices.find(i => i.device.id === device.id);
610
- if (existigDevice) {
611
- existigDevice.isConnected = false;
612
- return;
613
- }
508
+ const idx = this.connectedDevices.findIndex(d => d.isSame(device));
509
+ if (idx !== -1)
510
+ this.connectedDevices.splice(idx);
614
511
  }
615
512
  }
616
513
  exports.default = BleInterface;