incyclist-devices 1.4.44 → 1.4.47

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 +237 -190
  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 +155 -14
  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,26 +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;
16
20
  const DEFAULT_SCAN_TIMEOUT = 20000;
17
21
  const BACKGROUND_SCAN_TIMEOUT = 30000;
22
+ const DEFAULT_SERVICES = ['1818', '180d', '1826'];
18
23
  class BleInterface extends ble_1.BleInterfaceClass {
19
24
  constructor(props = {}) {
20
25
  super(props);
21
26
  this.scanState = { isScanning: false, isConnecting: false, timeout: undefined, isBackgroundScan: false };
22
27
  this.connectState = { isConnecting: false, isConnected: false, isInitSuccess: false };
23
28
  this.devices = [];
24
- this.deviceCache = [];
25
29
  this.peripheralCache = [];
26
30
  if (props.logger)
27
31
  this.logger = props.logger;
28
- else if (props.log) {
29
- this.logger = new gd_eventlog_1.EventLogger('BLE');
30
- }
32
+ this.logger = new gd_eventlog_1.EventLogger('BLE');
31
33
  }
32
34
  static getInstance(props = {}) {
33
35
  if (!BleInterface._instance) {
@@ -73,6 +75,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
73
75
  connect(props = {}) {
74
76
  const timeout = props.timeout || 2000;
75
77
  const runBackgroundScan = () => {
78
+ return;
76
79
  this.scanState.isBackgroundScan = true;
77
80
  this.scan({ timeout: BACKGROUND_SCAN_TIMEOUT, isBackgroundScan: true })
78
81
  .then(() => {
@@ -213,7 +216,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
213
216
  });
214
217
  };
215
218
  if (typeof services === 'string') {
216
- return get(deviceTypes, (s) => s === ble_1.uuid(services));
219
+ return get(deviceTypes, (s) => s === (0, ble_1.uuid)(services));
217
220
  }
218
221
  if (Array.isArray(services)) {
219
222
  return get(deviceTypes, s => services.map(ble_1.uuid).includes(s));
@@ -221,19 +224,24 @@ class BleInterface extends ble_1.BleInterfaceClass {
221
224
  return [];
222
225
  }
223
226
  getServicesFromDeviceTypes(deviceTypes) {
224
- if (!deviceTypes || !Array.isArray(deviceTypes) || deviceTypes.length === 0) {
225
- return [];
226
- }
227
- const services = [];
228
- deviceTypes.forEach(DeviceType => {
229
- if (DeviceType.services) {
230
- const dtServices = DeviceType.services;
231
- dtServices.forEach(s => {
232
- if (!services.find(s2 => s2 === s))
233
- services.push(s);
234
- });
227
+ let services = [];
228
+ try {
229
+ if (!deviceTypes || !Array.isArray(deviceTypes) || deviceTypes.length === 0) {
230
+ return [];
235
231
  }
236
- });
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
+ }
237
245
  return services;
238
246
  }
239
247
  getServicesFromDevice(device) {
@@ -263,15 +271,124 @@ class BleInterface extends ble_1.BleInterfaceClass {
263
271
  }, 100);
264
272
  });
265
273
  }
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) {
293
+ return __awaiter(this, void 0, void 0, function* () {
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
+ }
266
358
  connectDevice(requested, timeout = DEFAULT_SCAN_TIMEOUT + CONNECT_TIMEOUT) {
267
359
  return __awaiter(this, void 0, void 0, function* () {
268
- const { id, name, address, getProfile } = requested;
269
- const profile = getProfile && typeof (getProfile) === 'function' ? getProfile() : undefined;
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;
270
364
  this.logEvent({ message: 'connectDevice', id, name, address, profile, isbusy: this.scanState.isConnecting });
271
365
  if (this.scanState.isConnecting) {
272
366
  yield this.waitForConnectFinished(CONNECT_TIMEOUT);
273
367
  }
274
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
+ }
275
392
  let devices = [];
276
393
  let retry = false;
277
394
  let retryCount = 0;
@@ -280,7 +397,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
280
397
  this.logEvent({ message: 'retry connect device', id, name, address, profile, retryCount });
281
398
  }
282
399
  try {
283
- devices = yield this.scan({ timeout: DEFAULT_SCAN_TIMEOUT, device: requested });
400
+ devices = yield this.scan({ timeout: DEFAULT_SCAN_TIMEOUT, requested: requested });
284
401
  if (devices.length === 0) {
285
402
  retryCount++;
286
403
  retry = retryCount < 5;
@@ -288,7 +405,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
288
405
  }
289
406
  catch (err) {
290
407
  if (err.message === 'scanning already in progress') {
291
- yield utils_1.sleep(1000);
408
+ yield (0, utils_1.sleep)(1000);
292
409
  retryCount++;
293
410
  retry = retryCount < 5;
294
411
  continue;
@@ -333,26 +450,17 @@ class BleInterface extends ble_1.BleInterfaceClass {
333
450
  }, 100);
334
451
  });
335
452
  }
336
- addPeripheralToCache(peripheral) {
337
- try {
338
- this.logEvent({ message: 'adding device to cache', device: { address: peripheral.address, name: peripheral.advertisement ? peripheral.advertisement.localName : '' } });
339
- const existing = this.deviceCache.find(p => p.address === peripheral.address);
340
- if (!existing)
341
- this.deviceCache.push(peripheral);
342
- else {
343
- if (peripheral.advertisement && peripheral.advertisement.localName !== '' && existing.advertisement && existing.advertisement.localName === '')
344
- existing.advertisement.localName = peripheral.advertisement.localName;
345
- }
346
- }
347
- catch (err) {
348
- console.log('~~~ error', err);
349
- }
350
- }
351
453
  scan(props) {
352
454
  return __awaiter(this, void 0, void 0, function* () {
353
- const { timeout = DEFAULT_SCAN_TIMEOUT, deviceTypes = [], device } = props;
354
- const scanForDevice = (device !== null && device !== undefined);
355
- 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);
356
464
  const bleBinding = this.getBinding();
357
465
  if (!bleBinding)
358
466
  return Promise.reject(new Error('no binding defined'));
@@ -360,7 +468,11 @@ class BleInterface extends ble_1.BleInterfaceClass {
360
468
  yield this.connect();
361
469
  }
362
470
  const peripheralsProcessed = [];
363
- 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
+ });
364
476
  if (!props.isBackgroundScan && this.scanState.isBackgroundScan) {
365
477
  yield this.stopScan();
366
478
  this.scanState.isBackgroundScan = false;
@@ -368,7 +480,6 @@ class BleInterface extends ble_1.BleInterfaceClass {
368
480
  let opStr;
369
481
  if (scanForDevice) {
370
482
  opStr = 'search device';
371
- const { id, address, name } = device;
372
483
  this.logEvent({ message: 'search device request', device: { id, address, name }, deviceTypes });
373
484
  }
374
485
  else {
@@ -389,158 +500,93 @@ class BleInterface extends ble_1.BleInterfaceClass {
389
500
  this.scanState.isScanning = true;
390
501
  if (props.isBackgroundScan)
391
502
  this.scanState.isBackgroundScan = true;
392
- if (scanForDevice && device instanceof ble_1.BleDeviceClass) {
503
+ if (scanForDevice) {
393
504
  if (this.devices && this.devices.length > 0) {
394
- const connectedDevices = this.devices.map(i => ({ name: i.device.name, address: i.device.address, isConnected: i.isConnected, connectState: i.device.getConnectState() }));
395
- const { name, address } = device;
396
- this.logEvent({ message: `${opStr}: check if already registered`, device: { name, address }, connectedDevices });
397
- const existing = this.devices.find(i => (i.device.address === device.address || i.device.name === device.name));
398
- if (existing) {
399
- const d = device;
400
- const linkedDevice = existing.device;
401
- d.peripheral = existing.device.peripheral;
402
- if (d.setInterface && typeof (d.setInterface) === 'function')
403
- d.setInterface(this);
404
- setTimeout(() => {
405
- let connectState = linkedDevice.getConnectState();
406
- this.logEvent({ message: `${opStr}: device already registered`, device: device.name, address: device.address, connectState });
407
- if (connectState.isConnecting) {
408
- const waitStart = Date.now();
409
- const waitTimeout = waitStart + timeout;
410
- const waitIv = setInterval(() => {
411
- try {
412
- connectState = linkedDevice.getConnectState();
413
- if (connectState.isConnecting && Date.now() > waitTimeout) {
414
- clearInterval(waitIv);
415
- this.scanState.isScanning = false;
416
- return resolve([]);
417
- }
418
- if (!connectState.isConnecting) {
419
- clearInterval(waitIv);
420
- this.scanState.isScanning = false;
421
- return resolve([device]);
422
- }
423
- }
424
- catch (err) {
425
- console.log('~~~ error', err);
426
- }
427
- }, 100);
428
- }
429
- else if (connectState.isConnected) {
430
- this.scanState.isScanning = false;
431
- resolve([device]);
432
- }
433
- else {
434
- this.scanState.isScanning = false;
435
- resolve([]);
436
- }
437
- }, 100);
438
- }
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));
439
508
  }
440
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
+ };
441
526
  const onPeripheralFound = (peripheral, fromCache = false) => __awaiter(this, void 0, void 0, function* () {
442
527
  if (fromCache)
443
528
  this.logEvent({ message: 'adding from Cache', peripheral: peripheral.address });
444
- if (!peripheral || !peripheral.advertisement)
529
+ if (!peripheral || !peripheral.advertisement || !peripheral.advertisement.serviceUuids || peripheral.advertisement.serviceUuids.length === 0)
445
530
  return;
446
- let existingPeripheral = this.peripheralCache.find(i => i.address === peripheral.address);
447
- if (existingPeripheral && Date.now() - existingPeripheral.ts > 600000) {
448
- existingPeripheral.ts = Date.now();
449
- }
450
- if (!existingPeripheral) {
451
- this.peripheralCache.push({ address: peripheral.address, ts: Date.now(), peripheral });
452
- existingPeripheral = this.peripheralCache.find(i => i.address === peripheral.address);
453
- }
454
- let shouldAddDevice = peripheralsProcessed.find(p => p === peripheral.address) === undefined;
455
- if (shouldAddDevice) {
456
- if (process.env.BLE_DEBUG)
457
- console.log('discovered', peripheral.id, peripheral.address, peripheral.advertisement.localName);
458
- peripheralsProcessed.push(peripheral.address);
459
- let characteristics;
460
- if (!existingPeripheral.characteristics) {
461
- try {
462
- if (existingPeripheral.peripheral && existingPeripheral.peripheral.state !== 'connected')
463
- yield peripheral.connectAsync();
464
- const res = yield peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
465
- this.logEvent({ message: 'characteristic info (+):', info: res.characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
466
- if (peripheral.disconnect && typeof (peripheral.disconnect) === 'function')
467
- peripheral.disconnect(() => { });
468
- existingPeripheral.characteristics = res.characteristics;
469
- characteristics = res.characteristics;
470
- }
471
- catch (err) {
472
- console.log(err);
473
- }
474
- }
475
- else {
476
- characteristics = existingPeripheral.characteristics;
477
- this.logEvent({ message: 'characteristic info (+):', info: characteristics.map(c => `${peripheral.address} ${c.uuid} ${c.properties}`) });
478
- }
479
- if (!fromCache)
480
- this.addPeripheralToCache(peripheral);
481
- let DeviceClasses;
482
- if (scanForDevice && (!deviceTypes || deviceTypes.length === 0)) {
483
- const classes = BleInterface.deviceClasses.map(c => c.Class);
484
- 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++;
485
552
  }
486
- else {
487
- 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;
488
562
  }
489
- DeviceClasses.forEach(DeviceClass => {
490
- let cntFound = 0;
491
- if (!DeviceClass)
492
- return;
493
- if (scanForDevice && cntFound > 0)
494
- return;
495
- const C = DeviceClass;
496
- const d = new C({ peripheral });
497
- if (device && device.getProfile && device.getProfile() !== d.getProfile())
498
- return;
499
- d.setInterface(this);
500
- d.characteristics = characteristics;
501
- if (scanForDevice) {
502
- if ((device.id && device.id !== '' && d.id === device.id) ||
503
- (device.address && device.address !== '' && d.address === device.address) ||
504
- (device.name && device.name !== '' && d.name === device.name))
505
- cntFound++;
506
- }
507
- else
508
- cntFound++;
509
- const existing = this.devices.find(i => i.device.id === d.id && i.device.getProfile() === d.getProfile());
510
- if (!scanForDevice && cntFound > 0 && !existing) {
511
- this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
512
- this.devices.push({ device: d, isConnected: false });
513
- this.emit('device', d);
514
- }
515
- if (scanForDevice && cntFound > 0) {
516
- if (fromCache) {
517
- resolve([d]);
518
- return;
519
- }
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(() => {
520
569
  if (this.scanState.timeout) {
521
570
  clearTimeout(this.scanState.timeout);
522
571
  this.scanState.timeout = null;
523
- this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, });
524
- bleBinding.stopScanning(() => {
525
- this.getBinding().removeAllListeners('discover');
526
- this.scanState.isScanning = false;
527
- resolve([d]);
528
- });
529
572
  }
530
- 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;
531
577
  resolve([d]);
532
- }
533
- }
534
- });
535
- }
578
+ });
579
+ });
580
+ }
581
+ }));
536
582
  });
537
- this.logEvent({ message: `${opStr}: start scanning`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, timeout });
538
- this.deviceCache.forEach(peripheral => {
539
- 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);
540
586
  });
541
587
  bleBinding.startScanning([], true, (err) => {
542
588
  if (err) {
543
- 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 });
544
590
  this.scanState.isScanning = false;
545
591
  return reject(err);
546
592
  }
@@ -548,20 +594,7 @@ class BleInterface extends ble_1.BleInterfaceClass {
548
594
  onPeripheralFound(p);
549
595
  });
550
596
  });
551
- this.scanState.timeout = setTimeout(() => {
552
- this.scanState.timeout = null;
553
- 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}` : '') });
554
- this.getBinding().removeAllListeners('discover');
555
- this.logEvent({ message: `${opStr}: stop scanning`, requested: scanForDevice ? { name: device.name, address: device.address } : undefined, });
556
- bleBinding.stopScanning(() => {
557
- this.scanState.isScanning = false;
558
- if (scanForDevice) {
559
- reject(new Error('device not found'));
560
- return;
561
- }
562
- resolve(this.devices.map(i => i.device));
563
- });
564
- }, timeout);
597
+ this.scanState.timeout = setTimeout(onTimeout, timeout);
565
598
  });
566
599
  });
567
600
  }
@@ -572,6 +605,9 @@ class BleInterface extends ble_1.BleInterfaceClass {
572
605
  if (!this.getBinding())
573
606
  return Promise.reject(new Error('no binding defined'));
574
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; });
575
611
  this.logEvent({ message: 'scan stop request' });
576
612
  return new Promise(resolve => {
577
613
  this.getBinding().stopScanning(() => {
@@ -585,19 +621,30 @@ class BleInterface extends ble_1.BleInterfaceClass {
585
621
  return this.scanState.isScanning;
586
622
  }
587
623
  addConnectedDevice(device) {
588
- 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());
589
625
  if (existigDevice) {
590
626
  existigDevice.isConnected = true;
591
627
  return;
592
628
  }
593
629
  this.devices.push({ device, isConnected: true });
594
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
+ }
595
638
  findConnected(device) {
596
639
  const connected = this.devices.find(i => i.device.id === device.id && i.isConnected);
597
640
  if (connected)
598
641
  return connected.device;
599
642
  return undefined;
600
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
+ }
601
648
  removeConnectedDevice(device) {
602
649
  const existigDevice = this.devices.find(i => i.device.id === device.id);
603
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
+ }