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.
- 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 +242 -193
- 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 +148 -10
- 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,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
|
-
|
|
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:
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
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
|
-
|
|
267
|
-
|
|
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(
|
|
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,
|
|
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 =
|
|
352
|
-
|
|
353
|
-
|
|
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
|
-
|
|
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
|
|
503
|
+
if (scanForDevice) {
|
|
391
504
|
if (this.devices && this.devices.length > 0) {
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
this.
|
|
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
|
-
|
|
445
|
-
if (
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
let
|
|
453
|
-
|
|
454
|
-
if (
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
-
|
|
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
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
|
|
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
|
|
536
|
-
this.
|
|
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
|
|
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
|
+
}
|