@stoprocent/noble 2.5.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/dbus/bindings.js
CHANGED
|
@@ -49,6 +49,13 @@ function loadDbus () {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
function normalizeId (id) {
|
|
53
|
+
// BlueZ emits MACs uppercase; noble's id form is colon-stripped lowercase.
|
|
54
|
+
// Accept either, plus mixed case, so external callers don't have to care.
|
|
55
|
+
if (id == null) return id;
|
|
56
|
+
return String(id).replace(/:/g, '').toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
|
|
52
59
|
function unwrapVariant (variant) {
|
|
53
60
|
if (variant && typeof variant === 'object' && 'value' in variant && 'signature' in variant) {
|
|
54
61
|
return variant.value;
|
|
@@ -485,6 +492,7 @@ class DbusBindings extends EventEmitter {
|
|
|
485
492
|
// ---- Connect / disconnect ----
|
|
486
493
|
|
|
487
494
|
connect (peripheralUuid, _parameters) {
|
|
495
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
488
496
|
this._connect(peripheralUuid).catch(err => {
|
|
489
497
|
this.emit('connect', peripheralUuid, err);
|
|
490
498
|
});
|
|
@@ -518,10 +526,11 @@ class DbusBindings extends EventEmitter {
|
|
|
518
526
|
}
|
|
519
527
|
|
|
520
528
|
cancelConnect (peripheralUuid, _parameters) {
|
|
521
|
-
this.disconnect(peripheralUuid);
|
|
529
|
+
this.disconnect(normalizeId(peripheralUuid));
|
|
522
530
|
}
|
|
523
531
|
|
|
524
532
|
disconnect (peripheralUuid) {
|
|
533
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
525
534
|
this._disconnect(peripheralUuid).catch(err => {
|
|
526
535
|
this.emit('warning', `disconnect failed: ${err.message}`);
|
|
527
536
|
});
|
|
@@ -540,6 +549,7 @@ class DbusBindings extends EventEmitter {
|
|
|
540
549
|
}
|
|
541
550
|
|
|
542
551
|
updateRssi (peripheralUuid) {
|
|
552
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
543
553
|
const device = this._devices.get(peripheralUuid);
|
|
544
554
|
if (!device || !device.path) {
|
|
545
555
|
this.emit('rssiUpdate', peripheralUuid, 0, new Error('unknown peripheral'));
|
|
@@ -596,6 +606,7 @@ class DbusBindings extends EventEmitter {
|
|
|
596
606
|
}
|
|
597
607
|
|
|
598
608
|
discoverServices (peripheralUuid, uuids) {
|
|
609
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
599
610
|
const wanted = (uuids || []).map(normalizeUuid);
|
|
600
611
|
const found = this._findServicesForDevice(peripheralUuid);
|
|
601
612
|
const filtered = wanted.length === 0 ? found : found.filter(s => wanted.includes(s.uuid));
|
|
@@ -605,11 +616,13 @@ class DbusBindings extends EventEmitter {
|
|
|
605
616
|
}
|
|
606
617
|
|
|
607
618
|
discoverIncludedServices (peripheralUuid, serviceUuid, _serviceUuids) {
|
|
619
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
608
620
|
// BlueZ does not expose included services directly via D-Bus.
|
|
609
621
|
this.emit('includedServicesDiscover', peripheralUuid, serviceUuid, []);
|
|
610
622
|
}
|
|
611
623
|
|
|
612
624
|
discoverCharacteristics (peripheralUuid, serviceUuid, characteristicUuids) {
|
|
625
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
613
626
|
const services = this._findServicesForDevice(peripheralUuid);
|
|
614
627
|
const service = services.find(s => s.uuid === normalizeUuid(serviceUuid));
|
|
615
628
|
if (!service) {
|
|
@@ -642,6 +655,7 @@ class DbusBindings extends EventEmitter {
|
|
|
642
655
|
}
|
|
643
656
|
|
|
644
657
|
read (peripheralUuid, serviceUuid, characteristicUuid) {
|
|
658
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
645
659
|
this._readChar(peripheralUuid, serviceUuid, characteristicUuid).catch(err => {
|
|
646
660
|
this.emit('read', peripheralUuid, serviceUuid, characteristicUuid, null, false, err);
|
|
647
661
|
});
|
|
@@ -658,6 +672,7 @@ class DbusBindings extends EventEmitter {
|
|
|
658
672
|
}
|
|
659
673
|
|
|
660
674
|
write (peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse) {
|
|
675
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
661
676
|
this._writeChar(peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse).catch(err => {
|
|
662
677
|
this.emit('write', peripheralUuid, serviceUuid, characteristicUuid, err);
|
|
663
678
|
});
|
|
@@ -676,11 +691,13 @@ class DbusBindings extends EventEmitter {
|
|
|
676
691
|
}
|
|
677
692
|
|
|
678
693
|
broadcast (peripheralUuid, serviceUuid, characteristicUuid, _broadcast) {
|
|
694
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
679
695
|
this.emit('warning', 'broadcast is not supported on the dbus backend');
|
|
680
696
|
this.emit('broadcast', peripheralUuid, serviceUuid, characteristicUuid, false);
|
|
681
697
|
}
|
|
682
698
|
|
|
683
699
|
notify (peripheralUuid, serviceUuid, characteristicUuid, notify) {
|
|
700
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
684
701
|
this._setNotify(peripheralUuid, serviceUuid, characteristicUuid, notify).catch(err => {
|
|
685
702
|
this.emit('notify', peripheralUuid, serviceUuid, characteristicUuid, false, err);
|
|
686
703
|
});
|
|
@@ -724,6 +741,7 @@ class DbusBindings extends EventEmitter {
|
|
|
724
741
|
}
|
|
725
742
|
|
|
726
743
|
discoverDescriptors (peripheralUuid, serviceUuid, characteristicUuid) {
|
|
744
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
727
745
|
const charPath = this._findCharacteristicPath(peripheralUuid, serviceUuid, characteristicUuid);
|
|
728
746
|
if (!charPath) {
|
|
729
747
|
this.emit('descriptorsDiscover', peripheralUuid, serviceUuid, characteristicUuid, [], new Error('characteristic not found'));
|
|
@@ -734,6 +752,7 @@ class DbusBindings extends EventEmitter {
|
|
|
734
752
|
}
|
|
735
753
|
|
|
736
754
|
readValue (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid) {
|
|
755
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
737
756
|
this._readDesc(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid).catch(err => {
|
|
738
757
|
this.emit('valueRead', peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, null, err);
|
|
739
758
|
});
|
|
@@ -750,6 +769,7 @@ class DbusBindings extends EventEmitter {
|
|
|
750
769
|
}
|
|
751
770
|
|
|
752
771
|
writeValue (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
|
|
772
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
753
773
|
this._writeDesc(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data).catch(err => {
|
|
754
774
|
this.emit('valueWrite', peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, err);
|
|
755
775
|
});
|
|
@@ -766,11 +786,13 @@ class DbusBindings extends EventEmitter {
|
|
|
766
786
|
}
|
|
767
787
|
|
|
768
788
|
readHandle (peripheralUuid, handle) {
|
|
789
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
769
790
|
const err = new Error('readHandle is not supported on the dbus backend (BlueZ exposes UUIDs only)');
|
|
770
791
|
this.emit('handleRead', peripheralUuid, handle, null, err);
|
|
771
792
|
}
|
|
772
793
|
|
|
773
794
|
writeHandle (peripheralUuid, handle, _data, _withoutResponse) {
|
|
795
|
+
peripheralUuid = normalizeId(peripheralUuid);
|
|
774
796
|
const err = new Error('writeHandle is not supported on the dbus backend (BlueZ exposes UUIDs only)');
|
|
775
797
|
this.emit('handleWrite', peripheralUuid, handle, err);
|
|
776
798
|
}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"name": "@stoprocent/noble",
|
|
8
8
|
"description": "A Node.js BLE (Bluetooth Low Energy) central library.",
|
|
9
|
-
"version": "2.5.
|
|
9
|
+
"version": "2.5.1",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/stoprocent/noble.git"
|
|
@@ -36,6 +36,14 @@
|
|
|
36
36
|
"optionalDependencies": {
|
|
37
37
|
"@stoprocent/bluetooth-hci-socket": "^2.2.6"
|
|
38
38
|
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"dbus-next": "^0.10.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"dbus-next": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
39
47
|
"devDependencies": {
|
|
40
48
|
"@babel/eslint-parser": "^7.27.0",
|
|
41
49
|
"@commitlint/cli": "^19.3.0",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -409,4 +409,75 @@ describe('dbus/bindings', () => {
|
|
|
409
409
|
const bindings = new DbusBindings();
|
|
410
410
|
expect(bindings.addressToId('AA:BB:CC:DD:EE:FF')).toBe('aabbccddeeff');
|
|
411
411
|
});
|
|
412
|
+
|
|
413
|
+
describe('peripheral id normalization on public methods', () => {
|
|
414
|
+
const tree = () => adapterTree({
|
|
415
|
+
'/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF': {
|
|
416
|
+
'org.bluez.Device1': { Address: 'AA:BB:CC:DD:EE:FF', AddressType: 'public', Connected: false }
|
|
417
|
+
},
|
|
418
|
+
'/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF/service0001': {
|
|
419
|
+
'org.bluez.GattService1': { UUID: '0000180d-0000-1000-8000-00805f9b34fb', Primary: true }
|
|
420
|
+
},
|
|
421
|
+
'/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF/service0001/char0002': {
|
|
422
|
+
'org.bluez.GattCharacteristic1': {
|
|
423
|
+
UUID: '00002a37-0000-1000-8000-00805f9b34fb',
|
|
424
|
+
Flags: ['read', 'notify']
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
const variants = [
|
|
430
|
+
['canonical id', 'aabbccddeeff'],
|
|
431
|
+
['uppercase id', 'AABBCCDDEEFF'],
|
|
432
|
+
['mixed-case id', 'AaBbCcDdEeFf'],
|
|
433
|
+
['colon MAC uppercase', 'AA:BB:CC:DD:EE:FF'],
|
|
434
|
+
['colon MAC lowercase', 'aa:bb:cc:dd:ee:ff'],
|
|
435
|
+
['colon MAC mixed', 'Aa:Bb:Cc:Dd:Ee:Ff']
|
|
436
|
+
];
|
|
437
|
+
|
|
438
|
+
test.each(variants)('discoverServices accepts %s and emits canonical id', async (_label, input) => {
|
|
439
|
+
resetState(tree());
|
|
440
|
+
const bindings = new DbusBindings();
|
|
441
|
+
bindings.start();
|
|
442
|
+
await flush();
|
|
443
|
+
|
|
444
|
+
const services = [];
|
|
445
|
+
bindings.on('servicesDiscover', (...a) => services.push(a));
|
|
446
|
+
|
|
447
|
+
bindings.discoverServices(input, []);
|
|
448
|
+
|
|
449
|
+
expect(services[0]).toEqual(['aabbccddeeff', ['180d']]);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test.each(variants)('read accepts %s and emits canonical id', async (_label, input) => {
|
|
453
|
+
resetState(tree());
|
|
454
|
+
const bindings = new DbusBindings();
|
|
455
|
+
bindings.start();
|
|
456
|
+
await flush();
|
|
457
|
+
|
|
458
|
+
const reads = [];
|
|
459
|
+
bindings.on('read', (...a) => reads.push(a));
|
|
460
|
+
|
|
461
|
+
bindings.read(input, '180d', '2a37');
|
|
462
|
+
await flush();
|
|
463
|
+
|
|
464
|
+
expect(reads.length).toBe(1);
|
|
465
|
+
expect(reads[0][0]).toBe('aabbccddeeff');
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
test.each(variants)('readHandle (unsupported) emits canonical id for %s', (_label, input) => {
|
|
469
|
+
resetState(tree());
|
|
470
|
+
const bindings = new DbusBindings();
|
|
471
|
+
const events = [];
|
|
472
|
+
bindings.on('handleRead', (...a) => events.push(a));
|
|
473
|
+
bindings.readHandle(input, 0x42);
|
|
474
|
+
expect(events[0][0]).toBe('aabbccddeeff');
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
test('null/undefined peripheralUuid does not throw', () => {
|
|
478
|
+
const bindings = new DbusBindings();
|
|
479
|
+
expect(() => bindings.discoverServices(undefined, [])).not.toThrow();
|
|
480
|
+
expect(() => bindings.discoverServices(null, [])).not.toThrow();
|
|
481
|
+
});
|
|
482
|
+
});
|
|
412
483
|
});
|