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.
- package/lib/CyclingMode.js +1 -0
- package/lib/Device.d.ts +2 -0
- package/lib/Device.js +2 -0
- package/lib/DeviceProtocol.js +1 -0
- package/lib/DeviceSupport.js +25 -8
- package/lib/ant/AntAdapter.d.ts +1 -0
- package/lib/ant/AntAdapter.js +7 -0
- package/lib/ant/AntScanner.js +24 -7
- package/lib/ant/antfe/AntFEAdapter.js +7 -7
- package/lib/ant/anthrm/AntHrmAdapter.js +1 -1
- package/lib/ant/antpwr/pwr-adapter.js +1 -1
- package/lib/ant/utils.js +3 -1
- package/lib/ble/ble-device.d.ts +14 -5
- package/lib/ble/ble-device.js +138 -69
- package/lib/ble/ble-erg-mode.d.ts +24 -0
- package/lib/ble/ble-erg-mode.js +148 -0
- package/lib/ble/ble-interface.d.ts +35 -5
- package/lib/ble/ble-interface.js +237 -190
- package/lib/ble/ble-peripheral.d.ts +34 -0
- package/lib/ble/ble-peripheral.js +170 -0
- package/lib/ble/ble-st-mode.d.ts +24 -0
- package/lib/ble/ble-st-mode.js +148 -0
- package/lib/ble/ble.d.ts +29 -1
- package/lib/ble/ble.js +3 -1
- package/lib/ble/fm.d.ts +17 -2
- package/lib/ble/fm.js +155 -14
- package/lib/ble/hrm.d.ts +1 -2
- package/lib/ble/hrm.js +7 -8
- package/lib/ble/incyclist-protocol.js +32 -8
- package/lib/ble/pwr.d.ts +2 -2
- package/lib/ble/pwr.js +20 -8
- package/lib/calculations.js +1 -0
- package/lib/daum/DaumAdapter.d.ts +1 -0
- package/lib/daum/DaumAdapter.js +35 -13
- package/lib/daum/SmartTrainerCyclingMode.js +1 -0
- package/lib/daum/classic/DaumClassicAdapter.js +1 -1
- package/lib/daum/classic/DaumClassicProtocol.js +23 -7
- package/lib/daum/classic/bike.js +26 -26
- package/lib/daum/classic/utils.js +1 -0
- package/lib/daum/constants.js +1 -0
- package/lib/daum/premium/DaumPremiumAdapter.js +1 -1
- package/lib/daum/premium/DaumPremiumProtocol.js +23 -7
- package/lib/daum/premium/bike.js +18 -17
- package/lib/daum/premium/utils.js +1 -0
- package/lib/kettler/comms.d.ts +1 -0
- package/lib/kettler/comms.js +2 -1
- package/lib/kettler/ergo-racer/adapter.d.ts +1 -0
- package/lib/kettler/ergo-racer/adapter.js +31 -9
- package/lib/kettler/ergo-racer/protocol.d.ts +1 -1
- package/lib/kettler/ergo-racer/protocol.js +23 -7
- package/lib/modes/power-meter.js +1 -0
- package/lib/simulator/Simulator.d.ts +2 -1
- package/lib/simulator/Simulator.js +29 -7
- package/lib/types/route.js +1 -0
- package/lib/types/user.js +1 -0
- package/lib/utils.js +3 -1
- package/package.json +1 -1
package/lib/ble/ble-interface.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
|
269
|
-
const profile =
|
|
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,
|
|
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 = [],
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
|
|
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
|
|
503
|
+
if (scanForDevice) {
|
|
393
504
|
if (this.devices && this.devices.length > 0) {
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
this.
|
|
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
|
-
|
|
447
|
-
if (
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
}
|
|
454
|
-
let
|
|
455
|
-
|
|
456
|
-
if (
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
|
|
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
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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
|
-
|
|
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
|
|
538
|
-
this.
|
|
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
|
|
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
|
+
}
|