incyclist-devices 1.4.43 → 1.4.46

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 (57) hide show
  1. package/lib/CyclingMode.js +1 -0
  2. package/lib/Device.d.ts +2 -0
  3. package/lib/Device.js +2 -0
  4. package/lib/DeviceProtocol.js +1 -0
  5. package/lib/DeviceSupport.js +25 -8
  6. package/lib/ant/AntAdapter.d.ts +1 -0
  7. package/lib/ant/AntAdapter.js +7 -0
  8. package/lib/ant/AntScanner.js +24 -7
  9. package/lib/ant/antfe/AntFEAdapter.js +7 -7
  10. package/lib/ant/anthrm/AntHrmAdapter.js +1 -1
  11. package/lib/ant/antpwr/pwr-adapter.js +1 -1
  12. package/lib/ant/utils.js +3 -1
  13. package/lib/ble/ble-device.d.ts +14 -5
  14. package/lib/ble/ble-device.js +138 -69
  15. package/lib/ble/ble-erg-mode.d.ts +24 -0
  16. package/lib/ble/ble-erg-mode.js +148 -0
  17. package/lib/ble/ble-interface.d.ts +35 -5
  18. package/lib/ble/ble-interface.js +242 -193
  19. package/lib/ble/ble-peripheral.d.ts +34 -0
  20. package/lib/ble/ble-peripheral.js +170 -0
  21. package/lib/ble/ble-st-mode.d.ts +24 -0
  22. package/lib/ble/ble-st-mode.js +148 -0
  23. package/lib/ble/ble.d.ts +29 -1
  24. package/lib/ble/ble.js +3 -1
  25. package/lib/ble/fm.d.ts +17 -2
  26. package/lib/ble/fm.js +148 -10
  27. package/lib/ble/hrm.d.ts +1 -2
  28. package/lib/ble/hrm.js +7 -8
  29. package/lib/ble/incyclist-protocol.js +32 -8
  30. package/lib/ble/pwr.d.ts +2 -2
  31. package/lib/ble/pwr.js +20 -8
  32. package/lib/calculations.js +1 -0
  33. package/lib/daum/DaumAdapter.d.ts +1 -0
  34. package/lib/daum/DaumAdapter.js +35 -13
  35. package/lib/daum/SmartTrainerCyclingMode.js +1 -0
  36. package/lib/daum/classic/DaumClassicAdapter.js +1 -1
  37. package/lib/daum/classic/DaumClassicProtocol.js +23 -7
  38. package/lib/daum/classic/bike.js +26 -26
  39. package/lib/daum/classic/utils.js +1 -0
  40. package/lib/daum/constants.js +1 -0
  41. package/lib/daum/premium/DaumPremiumAdapter.js +1 -1
  42. package/lib/daum/premium/DaumPremiumProtocol.js +23 -7
  43. package/lib/daum/premium/bike.js +18 -17
  44. package/lib/daum/premium/utils.js +1 -0
  45. package/lib/kettler/comms.d.ts +1 -0
  46. package/lib/kettler/comms.js +2 -1
  47. package/lib/kettler/ergo-racer/adapter.d.ts +1 -0
  48. package/lib/kettler/ergo-racer/adapter.js +31 -9
  49. package/lib/kettler/ergo-racer/protocol.d.ts +1 -1
  50. package/lib/kettler/ergo-racer/protocol.js +23 -7
  51. package/lib/modes/power-meter.js +1 -0
  52. package/lib/simulator/Simulator.d.ts +2 -1
  53. package/lib/simulator/Simulator.js +29 -7
  54. package/lib/types/route.js +1 -0
  55. package/lib/types/user.js +1 -0
  56. package/lib/utils.js +3 -1
  57. package/package.json +1 -1
@@ -8,24 +8,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const gd_eventlog_1 = require("gd-eventlog");
13
16
  const utils_1 = require("../utils");
14
17
  const ble_1 = require("./ble");
18
+ const ble_peripheral_1 = __importDefault(require("./ble-peripheral"));
15
19
  const CONNECT_TIMEOUT = 5000;
20
+ const DEFAULT_SCAN_TIMEOUT = 20000;
21
+ const BACKGROUND_SCAN_TIMEOUT = 30000;
22
+ const DEFAULT_SERVICES = ['1818', '180d', '1826'];
16
23
  class BleInterface extends ble_1.BleInterfaceClass {
17
24
  constructor(props = {}) {
18
25
  super(props);
19
26
  this.scanState = { isScanning: false, isConnecting: false, timeout: undefined, isBackgroundScan: false };
20
27
  this.connectState = { isConnecting: false, isConnected: false, isInitSuccess: false };
21
28
  this.devices = [];
22
- this.deviceCache = [];
23
29
  this.peripheralCache = [];
24
30
  if (props.logger)
25
31
  this.logger = props.logger;
26
- else if (props.log) {
27
- this.logger = new gd_eventlog_1.EventLogger('BLE');
28
- }
32
+ this.logger = new gd_eventlog_1.EventLogger('BLE');
29
33
  }
30
34
  static getInstance(props = {}) {
31
35
  if (!BleInterface._instance) {
@@ -71,8 +75,9 @@ class BleInterface extends ble_1.BleInterfaceClass {
71
75
  connect(props = {}) {
72
76
  const timeout = props.timeout || 2000;
73
77
  const runBackgroundScan = () => {
78
+ return;
74
79
  this.scanState.isBackgroundScan = true;
75
- this.scan({ timeout: 5000, isBackgroundScan: true })
80
+ this.scan({ timeout: BACKGROUND_SCAN_TIMEOUT, isBackgroundScan: true })
76
81
  .then(() => {
77
82
  this.scanState.isBackgroundScan = false;
78
83
  })
@@ -211,7 +216,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
211
216
  });
212
217
  };
213
218
  if (typeof services === 'string') {
214
- return get(deviceTypes, (s) => s === ble_1.uuid(services));
219
+ return get(deviceTypes, (s) => s === (0, ble_1.uuid)(services));
215
220
  }
216
221
  if (Array.isArray(services)) {
217
222
  return get(deviceTypes, s => services.map(ble_1.uuid).includes(s));
@@ -219,19 +224,24 @@ class BleInterface extends ble_1.BleInterfaceClass {
219
224
  return [];
220
225
  }
221
226
  getServicesFromDeviceTypes(deviceTypes) {
222
- if (!deviceTypes || !Array.isArray(deviceTypes) || deviceTypes.length === 0) {
223
- return [];
224
- }
225
- const services = [];
226
- deviceTypes.forEach(DeviceType => {
227
- if (DeviceType.services) {
228
- const dtServices = DeviceType.services;
229
- dtServices.forEach(s => {
230
- if (!services.find(s2 => s2 === s))
231
- services.push(s);
232
- });
227
+ let services = [];
228
+ try {
229
+ if (!deviceTypes || !Array.isArray(deviceTypes) || deviceTypes.length === 0) {
230
+ return [];
233
231
  }
234
- });
232
+ deviceTypes.forEach(DeviceType => {
233
+ if (DeviceType.services) {
234
+ const dtServices = DeviceType.services;
235
+ dtServices.forEach(s => {
236
+ if (!services.find(s2 => s2 === s))
237
+ services.push(s);
238
+ });
239
+ }
240
+ });
241
+ }
242
+ catch (err) {
243
+ console.log(err);
244
+ }
235
245
  return services;
236
246
  }
237
247
  getServicesFromDevice(device) {
@@ -261,15 +271,124 @@ class BleInterface extends ble_1.BleInterfaceClass {
261
271
  }, 100);
262
272
  });
263
273
  }
264
- connectDevice(requested, timeout = CONNECT_TIMEOUT) {
274
+ addPeripheralToCache(peripheral, props = {}) {
275
+ const info = this.peripheralCache.find(i => i.address === peripheral.address);
276
+ const connector = info && info.connector ? info.connector : new ble_peripheral_1.default(this, peripheral);
277
+ this.peripheralCache.push(Object.assign({ address: peripheral.address, ts: Date.now(), peripheral, connector }, props));
278
+ }
279
+ getConnector(peripheral) {
280
+ const info = this.peripheralCache.find(i => i.address === peripheral.address);
281
+ if (!info) {
282
+ const connector = new ble_peripheral_1.default(this, peripheral);
283
+ this.peripheralCache.push({ address: peripheral.address, ts: Date.now(), peripheral, connector });
284
+ return connector;
285
+ }
286
+ return info.connector;
287
+ }
288
+ findPeripheral(peripheral) {
289
+ 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);
290
+ return info ? info.peripheral : undefined;
291
+ }
292
+ getCharacteristics(peripheral) {
265
293
  return __awaiter(this, void 0, void 0, function* () {
266
- const { id, name, address, getProfile } = requested;
267
- const profile = getProfile && typeof (getProfile) === 'function' ? getProfile() : undefined;
294
+ let characteristics = undefined;
295
+ let chachedPeripheralInfo = this.peripheralCache.find(i => i.address === peripheral.address);
296
+ if (chachedPeripheralInfo && Date.now() - chachedPeripheralInfo.ts > 600000) {
297
+ chachedPeripheralInfo.ts = Date.now();
298
+ }
299
+ if (!chachedPeripheralInfo) {
300
+ this.addPeripheralToCache(peripheral);
301
+ chachedPeripheralInfo = this.peripheralCache.find(i => i.address === peripheral.address);
302
+ }
303
+ const connector = chachedPeripheralInfo.connector;
304
+ if (!chachedPeripheralInfo.characteristics) {
305
+ try {
306
+ chachedPeripheralInfo.state = { isConfigured: false, isLoading: true, isInterrupted: false };
307
+ yield connector.connect();
308
+ peripheral.state = connector.getState();
309
+ yield connector.initialize();
310
+ characteristics = connector.getCharachteristics();
311
+ this.logEvent({ message: 'characteristic info (+):', info: characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
312
+ chachedPeripheralInfo.characteristics = characteristics;
313
+ chachedPeripheralInfo.state = { isConfigured: true, isLoading: false, isInterrupted: false };
314
+ }
315
+ catch (err) {
316
+ console.log(err);
317
+ }
318
+ }
319
+ else {
320
+ characteristics = chachedPeripheralInfo.characteristics;
321
+ this.logEvent({ message: 'characteristic info (*):', info: characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
322
+ }
323
+ if (!characteristics)
324
+ this.logEvent({ message: 'characteristic info:', info: 'none' });
325
+ return characteristics;
326
+ });
327
+ }
328
+ getDeviceClasses(peripheral, props = {}) {
329
+ let DeviceClasses;
330
+ const { deviceTypes, profile } = props;
331
+ if ((!deviceTypes || deviceTypes.length === 0)) {
332
+ const classes = BleInterface.deviceClasses.map(c => c.Class);
333
+ DeviceClasses = this.getDevicesFromServices(classes, peripheral.advertisement.serviceUuids);
334
+ }
335
+ else {
336
+ DeviceClasses = this.getDevicesFromServices(deviceTypes, peripheral.advertisement.serviceUuids);
337
+ }
338
+ if (profile && DeviceClasses && DeviceClasses.length > 0) {
339
+ DeviceClasses = DeviceClasses.filter(C => {
340
+ const device = new C({ peripheral });
341
+ if (device.getProfile() !== profile)
342
+ return false;
343
+ return true;
344
+ });
345
+ }
346
+ return DeviceClasses;
347
+ }
348
+ createDevice(DeviceClass, peripheral, characteristics) {
349
+ const C = DeviceClass;
350
+ const device = new C({ peripheral });
351
+ const existingDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
352
+ if (existingDevice)
353
+ return existingDevice;
354
+ device.setInterface(this);
355
+ device.characteristics = characteristics;
356
+ return device;
357
+ }
358
+ connectDevice(requested, timeout = DEFAULT_SCAN_TIMEOUT + CONNECT_TIMEOUT) {
359
+ return __awaiter(this, void 0, void 0, function* () {
360
+ const { id, name, address } = requested;
361
+ const profile = requested instanceof ble_1.BleDeviceClass ?
362
+ (requested.getProfile && typeof (requested.getProfile) === 'function' ? requested.getProfile() : undefined) :
363
+ requested.profile;
268
364
  this.logEvent({ message: 'connectDevice', id, name, address, profile, isbusy: this.scanState.isConnecting });
269
365
  if (this.scanState.isConnecting) {
270
- yield this.waitForConnectFinished(10000);
366
+ yield this.waitForConnectFinished(CONNECT_TIMEOUT);
271
367
  }
272
368
  this.scanState.isConnecting = true;
369
+ 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));
370
+ if (existing) {
371
+ const connected = yield existing.device.connect();
372
+ this.scanState.isConnecting = false;
373
+ return existing.device;
374
+ }
375
+ const peripheralInfo = this.peripheralCache.find(i => (i.address === requested.address || (i.periphal && i.peripheral.id === requested.id)));
376
+ if (peripheralInfo) {
377
+ if (!peripheralInfo.characteristic) {
378
+ yield this.getCharacteristics(peripheralInfo.periphal);
379
+ const DeviceClasses = this.getDeviceClasses(peripheralInfo.peripheral, { profile });
380
+ if (!DeviceClasses || DeviceClasses.length === 0)
381
+ return;
382
+ const devices = DeviceClasses.map(C => this.createDevice(C, peripheralInfo.periphal, peripheralInfo.characteristics));
383
+ if (devices && devices.length > 0) {
384
+ for (let i = 0; i < devices.length; i++) {
385
+ const idx = this.devices.push({ device: devices[i], isConnected: false }) - 1;
386
+ yield devices[i].connect();
387
+ this.devices[idx].isConnected = true;
388
+ }
389
+ }
390
+ }
391
+ }
273
392
  let devices = [];
274
393
  let retry = false;
275
394
  let retryCount = 0;
@@ -278,7 +397,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
278
397
  this.logEvent({ message: 'retry connect device', id, name, address, profile, retryCount });
279
398
  }
280
399
  try {
281
- devices = yield this.scan({ timeout, device: requested });
400
+ devices = yield this.scan({ timeout: DEFAULT_SCAN_TIMEOUT, requested: requested });
282
401
  if (devices.length === 0) {
283
402
  retryCount++;
284
403
  retry = retryCount < 5;
@@ -286,7 +405,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
286
405
  }
287
406
  catch (err) {
288
407
  if (err.message === 'scanning already in progress') {
289
- yield utils_1.sleep(1000);
408
+ yield (0, utils_1.sleep)(1000);
290
409
  retryCount++;
291
410
  retry = retryCount < 5;
292
411
  continue;
@@ -331,26 +450,17 @@ class BleInterface extends ble_1.BleInterfaceClass {
331
450
  }, 100);
332
451
  });
333
452
  }
334
- addPeripheralToCache(peripheral) {
335
- try {
336
- this.logEvent({ message: 'adding device to cache', device: { address: peripheral.address, name: peripheral.advertisement ? peripheral.advertisement.localName : '' } });
337
- const existing = this.deviceCache.find(p => p.address === peripheral.address);
338
- if (!existing)
339
- this.deviceCache.push(peripheral);
340
- else {
341
- if (peripheral.advertisement && peripheral.advertisement.localName !== '' && existing.advertisement && existing.advertisement.localName === '')
342
- existing.advertisement.localName = peripheral.advertisement.localName;
343
- }
344
- }
345
- catch (err) {
346
- console.log('~~~ error', err);
347
- }
348
- }
349
453
  scan(props) {
350
454
  return __awaiter(this, void 0, void 0, function* () {
351
- const { timeout = 5000, deviceTypes = [], device } = props;
352
- const scanForDevice = (device !== null && device !== undefined);
353
- const services = this.getServicesFromDeviceTypes(deviceTypes);
455
+ const { timeout = DEFAULT_SCAN_TIMEOUT, deviceTypes = [], requested } = props;
456
+ let profile;
457
+ if (requested)
458
+ profile = requested instanceof ble_1.BleDeviceClass ?
459
+ (requested.getProfile && typeof (requested.getProfile) === 'function' ? requested.getProfile() : undefined) :
460
+ requested.profile;
461
+ const { id, address, name } = requested || {};
462
+ const scanForDevice = (requested !== null && requested !== undefined);
463
+ const services = (props.isBackgroundScan || !deviceTypes || deviceTypes.length === 0) ? DEFAULT_SERVICES : this.getServicesFromDeviceTypes(deviceTypes);
354
464
  const bleBinding = this.getBinding();
355
465
  if (!bleBinding)
356
466
  return Promise.reject(new Error('no binding defined'));
@@ -358,7 +468,11 @@ class BleInterface extends ble_1.BleInterfaceClass {
358
468
  yield this.connect();
359
469
  }
360
470
  const peripheralsProcessed = [];
361
- this.logEvent({ message: 'scan()', props, scanState: this.scanState, cache: this.deviceCache.map(p => ({ name: p.advertisement ? p.advertisement.localName : '', address: p.address })) });
471
+ const devicesProcessed = [];
472
+ this.logEvent({ message: 'scan()', props, scanState: this.scanState,
473
+ peripheralCache: this.peripheralCache.map(i => ({ address: i.address, ts: i.ts, name: i.peripheral ? i.peripheral.advertisement.localName : '' })),
474
+ deviceCache: this.devices.map(i => ({ address: i.device.address, profile: i.device.getProfile(), isConnected: i.isConnected }))
475
+ });
362
476
  if (!props.isBackgroundScan && this.scanState.isBackgroundScan) {
363
477
  yield this.stopScan();
364
478
  this.scanState.isBackgroundScan = false;
@@ -366,7 +480,6 @@ class BleInterface extends ble_1.BleInterfaceClass {
366
480
  let opStr;
367
481
  if (scanForDevice) {
368
482
  opStr = 'search device';
369
- const { id, address, name } = device;
370
483
  this.logEvent({ message: 'search device request', device: { id, address, name }, deviceTypes });
371
484
  }
372
485
  else {
@@ -387,158 +500,93 @@ class BleInterface extends ble_1.BleInterfaceClass {
387
500
  this.scanState.isScanning = true;
388
501
  if (props.isBackgroundScan)
389
502
  this.scanState.isBackgroundScan = true;
390
- if (scanForDevice && device instanceof ble_1.BleDeviceClass) {
503
+ if (scanForDevice) {
391
504
  if (this.devices && this.devices.length > 0) {
392
- const connectedDevices = this.devices.map(i => ({ name: i.device.name, address: i.device.address, isConnected: i.isConnected, connectState: i.device.getConnectState() }));
393
- const { name, address } = device;
394
- this.logEvent({ message: `${opStr}: check if already registered`, device: { name, address }, connectedDevices });
395
- const existing = this.devices.find(i => (i.device.address === device.address || i.device.name === device.name));
396
- if (existing) {
397
- const d = device;
398
- const linkedDevice = existing.device;
399
- d.peripheral = existing.device.peripheral;
400
- if (d.setInterface && typeof (d.setInterface) === 'function')
401
- d.setInterface(this);
402
- setTimeout(() => {
403
- let connectState = linkedDevice.getConnectState();
404
- this.logEvent({ message: `${opStr}: device already registered`, device: device.name, address: device.address, connectState });
405
- if (connectState.isConnecting) {
406
- const waitStart = Date.now();
407
- const waitTimeout = waitStart + timeout;
408
- const waitIv = setInterval(() => {
409
- try {
410
- connectState = linkedDevice.getConnectState();
411
- if (connectState.isConnecting && Date.now() > waitTimeout) {
412
- clearInterval(waitIv);
413
- this.scanState.isScanning = false;
414
- return resolve([]);
415
- }
416
- if (!connectState.isConnecting) {
417
- clearInterval(waitIv);
418
- this.scanState.isScanning = false;
419
- return resolve([device]);
420
- }
421
- }
422
- catch (err) {
423
- console.log('~~~ error', err);
424
- }
425
- }, 100);
426
- }
427
- else if (connectState.isConnected) {
428
- this.scanState.isScanning = false;
429
- resolve([device]);
430
- }
431
- else {
432
- this.scanState.isScanning = false;
433
- resolve([]);
434
- }
435
- }, 100);
436
- }
505
+ const knownDevices = this.devices.map(i => ({ name: i.device.name, address: i.device.address, isConnected: i.isConnected, connectState: i.device.getConnectState() }));
506
+ this.logEvent({ message: `${opStr}: check if already registered`, device: { name, address }, knownDevices });
507
+ const existing = this.devices.find(i => (i.device.address === address || i.device.name === name || i.device.id === id));
437
508
  }
438
509
  }
510
+ const onTimeout = () => {
511
+ if (!this.scanState.isScanning || !this.scanState.timeout)
512
+ return;
513
+ this.scanState.timeout = null;
514
+ 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}` : '') });
515
+ this.getBinding().removeAllListeners('discover');
516
+ this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name, address, profile } : undefined, });
517
+ bleBinding.stopScanning(() => {
518
+ this.scanState.isScanning = false;
519
+ if (scanForDevice) {
520
+ reject(new Error('device not found'));
521
+ return;
522
+ }
523
+ resolve(this.devices.map(i => i.device));
524
+ });
525
+ };
439
526
  const onPeripheralFound = (peripheral, fromCache = false) => __awaiter(this, void 0, void 0, function* () {
440
527
  if (fromCache)
441
528
  this.logEvent({ message: 'adding from Cache', peripheral: peripheral.address });
442
- if (!peripheral || !peripheral.advertisement)
529
+ if (!peripheral || !peripheral.advertisement || !peripheral.advertisement.serviceUuids || peripheral.advertisement.serviceUuids.length === 0)
443
530
  return;
444
- let existingPeripheral = this.peripheralCache.find(i => i.address === peripheral.address);
445
- if (existingPeripheral && Date.now() - existingPeripheral.ts > 600000) {
446
- existingPeripheral.ts = Date.now();
447
- }
448
- if (!existingPeripheral) {
449
- this.peripheralCache.push({ address: peripheral.address, ts: Date.now(), peripheral });
450
- existingPeripheral = this.peripheralCache.find(i => i.address === peripheral.address);
451
- }
452
- let shouldAddDevice = peripheralsProcessed.find(p => p === peripheral.address) === undefined;
453
- if (shouldAddDevice) {
454
- if (process.env.BLE_DEBUG)
455
- console.log('discovered', peripheral.id, peripheral.address, peripheral.advertisement.localName);
456
- peripheralsProcessed.push(peripheral.address);
457
- let characteristics;
458
- if (!existingPeripheral.characteristics) {
459
- try {
460
- if (existingPeripheral.peripheral && existingPeripheral.peripheral.state !== 'connected')
461
- yield peripheral.connectAsync();
462
- const res = yield peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
463
- this.logEvent({ message: 'characteristic info (+):', info: res.characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
464
- if (peripheral.disconnect && typeof (peripheral.disconnect) === 'function')
465
- peripheral.disconnect(() => { });
466
- existingPeripheral.characteristics = res.characteristics;
467
- characteristics = res.characteristics;
468
- }
469
- catch (err) {
470
- console.log(err);
471
- }
472
- }
473
- else {
474
- characteristics = existingPeripheral.characteristics;
475
- this.logEvent({ message: 'characteristic info (+):', info: characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
476
- }
477
- if (!fromCache)
478
- this.addPeripheralToCache(peripheral);
479
- let DeviceClasses;
480
- if (scanForDevice && (!deviceTypes || deviceTypes.length === 0)) {
481
- const classes = BleInterface.deviceClasses.map(c => c.Class);
482
- DeviceClasses = this.getDevicesFromServices(classes, peripheral.advertisement.serviceUuids);
531
+ const isPeripheralProcessed = peripheralsProcessed.find(p => p === peripheral.address) !== undefined;
532
+ if (isPeripheralProcessed)
533
+ return;
534
+ peripheralsProcessed.push(peripheral.address);
535
+ let chachedPeripheralInfo = this.peripheralCache.find(i => i.address === peripheral.address);
536
+ const str = fromCache ? 'added' : 'detected';
537
+ const characteristics = yield this.getCharacteristics(peripheral);
538
+ const DeviceClasses = this.getDeviceClasses(peripheral, { profile });
539
+ let cntFound = 0;
540
+ DeviceClasses.forEach((DeviceClass) => __awaiter(this, void 0, void 0, function* () {
541
+ if (!DeviceClass)
542
+ return;
543
+ if (scanForDevice && cntFound > 0)
544
+ return;
545
+ const d = this.createDevice(DeviceClass, peripheral, characteristics);
546
+ yield d.connect();
547
+ if (scanForDevice) {
548
+ if ((id && id !== '' && d.id === id) ||
549
+ (address && address !== '' && d.address === address) ||
550
+ (name && name !== '' && d.name === name))
551
+ cntFound++;
483
552
  }
484
- else {
485
- DeviceClasses = this.getDevicesFromServices(deviceTypes, peripheral.advertisement.serviceUuids);
553
+ else
554
+ cntFound++;
555
+ const existing = devicesProcessed.find(device => device.id === d.id && device.getProfile() === d.getProfile());
556
+ if (!scanForDevice && cntFound > 0 && !existing) {
557
+ this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
558
+ this.addDeviceToCache(d, peripheral.state === 'connected');
559
+ devicesProcessed.push(d);
560
+ this.emit('device', d);
561
+ return;
486
562
  }
487
- DeviceClasses.forEach(DeviceClass => {
488
- let cntFound = 0;
489
- if (!DeviceClass)
490
- return;
491
- if (scanForDevice && cntFound > 0)
492
- return;
493
- const C = DeviceClass;
494
- const d = new C({ peripheral });
495
- if (device && device.getProfile && device.getProfile() !== d.getProfile())
496
- return;
497
- d.setInterface(this);
498
- d.characteristics = characteristics;
499
- if (scanForDevice) {
500
- if ((device.id && device.id !== '' && d.id === device.id) ||
501
- (device.address && device.address !== '' && d.address === device.address) ||
502
- (device.name && device.name !== '' && d.name === device.name))
503
- cntFound++;
504
- }
505
- else
506
- cntFound++;
507
- const existing = this.devices.find(i => i.device.id === d.id && i.device.getProfile() === d.getProfile());
508
- if (!scanForDevice && cntFound > 0 && !existing) {
509
- this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
510
- this.devices.push({ device: d, isConnected: false });
511
- this.emit('device', d);
512
- }
513
- if (scanForDevice && cntFound > 0) {
514
- if (fromCache) {
515
- resolve([d]);
516
- return;
517
- }
563
+ if (scanForDevice && cntFound > 0) {
564
+ this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
565
+ this.addDeviceToCache(d, peripheral.state === 'connected');
566
+ devicesProcessed.push(d);
567
+ this.emit('device', d);
568
+ process.nextTick(() => {
518
569
  if (this.scanState.timeout) {
519
570
  clearTimeout(this.scanState.timeout);
520
571
  this.scanState.timeout = null;
521
- this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, });
522
- bleBinding.stopScanning(() => {
523
- this.getBinding().removeAllListeners('discover');
524
- this.scanState.isScanning = false;
525
- resolve([d]);
526
- });
527
572
  }
528
- else {
573
+ this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name, address, profile } : undefined, });
574
+ bleBinding.stopScanning(() => {
575
+ this.getBinding().removeAllListeners('discover');
576
+ this.scanState.isScanning = false;
529
577
  resolve([d]);
530
- }
531
- }
532
- });
533
- }
578
+ });
579
+ });
580
+ }
581
+ }));
534
582
  });
535
- this.logEvent({ message: `${opStr}: start scanning`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, timeout });
536
- this.deviceCache.forEach(peripheral => {
537
- onPeripheralFound(peripheral, true);
583
+ this.logEvent({ message: `${opStr}: start scanning`, requested: scanForDevice ? { name, address, profile } : undefined, timeout });
584
+ this.peripheralCache.forEach(i => {
585
+ onPeripheralFound(i.peripheral, true);
538
586
  });
539
587
  bleBinding.startScanning([], true, (err) => {
540
588
  if (err) {
541
- this.logEvent({ message: `${opStr} result: error`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, error: err.message });
589
+ this.logEvent({ message: `${opStr} result: error`, requested: scanForDevice ? { name, address, profile } : undefined, error: err.message });
542
590
  this.scanState.isScanning = false;
543
591
  return reject(err);
544
592
  }
@@ -546,20 +594,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
546
594
  onPeripheralFound(p);
547
595
  });
548
596
  });
549
- this.scanState.timeout = setTimeout(() => {
550
- this.scanState.timeout = null;
551
- this.logEvent({ message: `${opStr} result: devices found`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, devices: this.devices.map(i => i.device.name + (!i.device.name || i.device.name === '') ? `addr=${i.device.address}` : '') });
552
- this.getBinding().removeAllListeners('discover');
553
- this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, });
554
- bleBinding.stopScanning(() => {
555
- this.scanState.isScanning = false;
556
- if (scanForDevice) {
557
- reject(new Error('device not found'));
558
- return;
559
- }
560
- resolve(this.devices.map(i => i.device));
561
- });
562
- }, timeout);
597
+ this.scanState.timeout = setTimeout(onTimeout, timeout);
563
598
  });
564
599
  });
565
600
  }
@@ -570,6 +605,9 @@ class BleInterface extends ble_1.BleInterfaceClass {
570
605
  if (!this.getBinding())
571
606
  return Promise.reject(new Error('no binding defined'));
572
607
  this.getBinding().removeAllListeners('discover');
608
+ const ongoing = this.peripheralCache.filter(i => i.state.isLoading);
609
+ if (ongoing)
610
+ ongoing.forEach(i => { i.isInterrupted = true; });
573
611
  this.logEvent({ message: 'scan stop request' });
574
612
  return new Promise(resolve => {
575
613
  this.getBinding().stopScanning(() => {
@@ -583,19 +621,30 @@ class BleInterface extends ble_1.BleInterfaceClass {
583
621
  return this.scanState.isScanning;
584
622
  }
585
623
  addConnectedDevice(device) {
586
- const existigDevice = this.devices.find(i => i.device.id === device.id);
624
+ const existigDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
587
625
  if (existigDevice) {
588
626
  existigDevice.isConnected = true;
589
627
  return;
590
628
  }
591
629
  this.devices.push({ device, isConnected: true });
592
630
  }
631
+ addDeviceToCache(device, isConnected) {
632
+ const existigDevice = this.devices.find(i => i.device.id === device.id && i.device.getProfile() === device.getProfile());
633
+ if (existigDevice) {
634
+ return;
635
+ }
636
+ this.devices.push({ device, isConnected });
637
+ }
593
638
  findConnected(device) {
594
639
  const connected = this.devices.find(i => i.device.id === device.id && i.isConnected);
595
640
  if (connected)
596
641
  return connected.device;
597
642
  return undefined;
598
643
  }
644
+ findDeviceInCache(device) {
645
+ 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);
646
+ return existing ? existing.device : undefined;
647
+ }
599
648
  removeConnectedDevice(device) {
600
649
  const existigDevice = this.devices.find(i => i.device.id === device.id);
601
650
  if (existigDevice) {
@@ -0,0 +1,34 @@
1
+ import { BleCharacteristic, BlePeripheral } from "./ble";
2
+ import BleInterface from "./ble-interface";
3
+ export declare type ConnectorState = {
4
+ isConnected: boolean;
5
+ isConnecting: boolean;
6
+ isInitialized: boolean;
7
+ isInitializing: boolean;
8
+ isSubscribing: boolean;
9
+ subscribed?: string[];
10
+ };
11
+ export default class BlePeripheralConnector {
12
+ private state;
13
+ private services;
14
+ private characteristics;
15
+ private ble;
16
+ private peripheral;
17
+ private logger?;
18
+ private emitter;
19
+ constructor(ble: BleInterface, peripheral: BlePeripheral);
20
+ logEvent(event: any): void;
21
+ connect(): Promise<void>;
22
+ reconnect(): Promise<void>;
23
+ onDisconnect(): void;
24
+ initialize(enforce?: boolean): Promise<void>;
25
+ subscribeAll(callback: (characteristicUuid: string, data: any) => void): Promise<string[]>;
26
+ subscribe(characteristicUuid: string): Promise<boolean>;
27
+ onData(characteristicUuid: string, data: any): void;
28
+ on(characteristicUuid: string, callback: (characteristicUuid: string, data: any) => void): void;
29
+ off(characteristicUuid: string, callback: (characteristicUuid: string, data: any) => void): void;
30
+ removeAllListeners(characteristicUuid: string): void;
31
+ getState(): string;
32
+ getCharachteristics(): BleCharacteristic[];
33
+ getServices(): string[];
34
+ }