@stoprocent/noble 1.19.0 → 2.0.0
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/README.md +393 -650
- package/examples/advertisement-discovery.js +57 -48
- package/examples/connect-address.js +59 -34
- package/examples/echo.js +59 -69
- package/examples/enter-exit.js +55 -49
- package/examples/multiple-bindings.js +53 -0
- package/examples/peripheral-explorer-async.js +39 -21
- package/examples/peripheral-explorer.ts +52 -0
- package/index.d.ts +249 -209
- package/index.js +4 -1
- package/jest.config.js +4 -0
- package/lib/characteristic.js +153 -127
- package/lib/{win/src/callbacks.h → common/include/Emit.h} +17 -14
- package/lib/common/include/Peripheral.h +31 -0
- package/lib/common/include/ThreadSafeCallback.h +95 -0
- package/lib/{win/src/callbacks.cc → common/src/Emit.cc} +111 -68
- package/lib/descriptor.js +57 -54
- package/lib/hci-socket/acl-stream.js +2 -4
- package/lib/hci-socket/bindings.js +96 -73
- package/lib/hci-socket/gap.js +2 -3
- package/lib/hci-socket/gatt.js +2 -5
- package/lib/hci-socket/hci.js +19 -7
- package/lib/hci-socket/signaling.js +2 -3
- package/lib/hci-socket/smp.js +2 -3
- package/lib/hci-socket/vs.js +1 -0
- package/lib/mac/binding.gyp +5 -7
- package/lib/mac/bindings.js +1 -3
- package/lib/mac/src/ble_manager.h +1 -8
- package/lib/mac/src/ble_manager.mm +87 -44
- package/lib/mac/src/napi_objc.h +1 -0
- package/lib/mac/src/napi_objc.mm +0 -6
- package/lib/mac/src/noble_mac.h +5 -3
- package/lib/mac/src/noble_mac.mm +99 -57
- package/lib/mac/src/objc_cpp.h +3 -2
- package/lib/mac/src/objc_cpp.mm +0 -6
- package/lib/noble.js +579 -488
- package/lib/peripheral.js +171 -174
- package/lib/resolve-bindings.js +37 -30
- package/lib/service.js +58 -55
- package/lib/win/binding.gyp +4 -11
- package/lib/win/bindings.js +1 -3
- package/lib/win/src/ble_manager.cc +291 -166
- package/lib/win/src/ble_manager.h +11 -13
- package/lib/win/src/napi_winrt.cc +1 -7
- package/lib/win/src/napi_winrt.h +1 -1
- package/lib/win/src/noble_winrt.cc +88 -61
- package/lib/win/src/noble_winrt.h +5 -3
- package/lib/win/src/notify_map.cc +0 -7
- package/lib/win/src/notify_map.h +1 -8
- package/lib/win/src/peripheral_winrt.cc +29 -11
- package/lib/win/src/peripheral_winrt.h +1 -1
- package/lib/win/src/radio_watcher.cc +79 -69
- package/lib/win/src/radio_watcher.h +30 -11
- package/lib/win/src/winrt_cpp.cc +1 -1
- package/lib/win/src/winrt_cpp.h +3 -0
- package/package.json +14 -17
- package/prebuilds/darwin-x64+arm64/@stoprocent+noble.node +0 -0
- package/prebuilds/win32-ia32/@stoprocent+noble.node +0 -0
- package/prebuilds/win32-x64/@stoprocent+noble.node +0 -0
- package/test/lib/characteristic.test.js +202 -322
- package/test/lib/descriptor.test.js +62 -95
- package/test/lib/hci-socket/acl-stream.test.js +112 -108
- package/test/lib/hci-socket/bindings.test.js +576 -365
- package/test/lib/hci-socket/hci.test.js +442 -473
- package/test/lib/hci-socket/signaling.test.js +45 -48
- package/test/lib/hci-socket/smp.test.js +144 -142
- package/test/lib/hci-socket/vs.test.js +193 -18
- package/test/lib/peripheral.test.js +492 -322
- package/test/lib/resolve-bindings.test.js +207 -82
- package/test/lib/service.test.js +79 -88
- package/test/noble.test.js +381 -1085
- package/.editorconfig +0 -11
- package/.nycrc.json +0 -4
- package/codecov.yml +0 -5
- package/examples/cache-gatt-discovery.js +0 -198
- package/examples/cache-gatt-reconnect.js +0 -164
- package/examples/ext-advertisement-discovery.js +0 -65
- package/examples/peripheral-explorer.js +0 -225
- package/examples/pizza/central.js +0 -194
- package/examples/pizza/pizza.js +0 -60
- package/examples/test/test.custom.js +0 -131
- package/examples/uart-bind-params.js +0 -28
- package/lib/distributed/bindings.js +0 -326
- package/lib/mac/src/callbacks.cc +0 -222
- package/lib/mac/src/callbacks.h +0 -84
- package/lib/mac/src/peripheral.h +0 -23
- package/lib/resolve-bindings-web.js +0 -9
- package/lib/webbluetooth/bindings.js +0 -368
- package/lib/websocket/bindings.js +0 -321
- package/lib/win/src/peripheral.h +0 -23
- package/test/lib/distributed/bindings.test.js +0 -918
- package/test/lib/webbluetooth/bindings.test.js +0 -190
- package/test/lib/websocket/bindings.test.js +0 -456
- package/test/mocha.setup.js +0 -0
- package/with-bindings.js +0 -5
- package/with-custom-binding.js +0 -6
- package/ws-slave.js +0 -404
|
@@ -1,65 +1,74 @@
|
|
|
1
1
|
const noble = require('../index');
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
noble.startScanning([], false);
|
|
6
|
-
} else {
|
|
7
|
-
noble.stopScanning();
|
|
8
|
-
}
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
noble.on('discover', function (peripheral) {
|
|
12
|
-
console.log(`${new Date()}`);
|
|
13
|
-
console.log(
|
|
14
|
-
`Peripheral discovered (${peripheral.id} with address <${peripheral.address}, ${peripheral.addressType}>, connectable: ${peripheral.connectable}, scannable: ${peripheral.scannable}, RSSI ${peripheral.rssi}:`
|
|
15
|
-
);
|
|
16
|
-
console.log('\thello my local name is:');
|
|
17
|
-
console.log(`\t\t${peripheral.advertisement.localName}`);
|
|
3
|
+
async function handleDiscovery (peripheral) {
|
|
4
|
+
console.log(`\n${new Date()}`);
|
|
18
5
|
console.log(
|
|
19
|
-
|
|
6
|
+
`Peripheral discovered (${peripheral.id}):
|
|
7
|
+
- Address: ${peripheral.address} (${peripheral.addressType})
|
|
8
|
+
- Connectable: ${peripheral.connectable}
|
|
9
|
+
- Scannable: ${peripheral.scannable}
|
|
10
|
+
- RSSI: ${peripheral.rssi}`
|
|
20
11
|
);
|
|
21
|
-
console.log(`\t\t${JSON.stringify(peripheral.advertisement.serviceUuids)}`);
|
|
22
|
-
const serviceData = peripheral.advertisement.serviceData;
|
|
23
12
|
|
|
13
|
+
// Local Name
|
|
14
|
+
if (peripheral.advertisement.localName) {
|
|
15
|
+
console.log(`Local Name: ${peripheral.advertisement.localName}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Service UUIDs
|
|
19
|
+
if (peripheral.advertisement.serviceUuids.length) {
|
|
20
|
+
console.log('Advertised Services:');
|
|
21
|
+
console.log(` ${peripheral.advertisement.serviceUuids.join(', ')}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Service Data
|
|
25
|
+
const serviceData = peripheral.advertisement.serviceData;
|
|
24
26
|
if (serviceData && serviceData.length) {
|
|
25
|
-
console.log('
|
|
26
|
-
|
|
27
|
-
console.log(
|
|
28
|
-
|
|
29
|
-
serviceData[i].data.toString('hex')
|
|
30
|
-
)}`
|
|
31
|
-
);
|
|
32
|
-
}
|
|
27
|
+
console.log('Service Data:');
|
|
28
|
+
serviceData.forEach(data => {
|
|
29
|
+
console.log(` ${data.uuid}: ${data.data.toString('hex')}`);
|
|
30
|
+
});
|
|
33
31
|
}
|
|
34
32
|
|
|
33
|
+
// Manufacturer Data
|
|
35
34
|
if (peripheral.advertisement.manufacturerData) {
|
|
36
|
-
console.log('
|
|
37
|
-
console.log(
|
|
38
|
-
`\t\t${JSON.stringify(
|
|
39
|
-
peripheral.advertisement.manufacturerData.toString('hex')
|
|
40
|
-
)}`
|
|
41
|
-
);
|
|
35
|
+
console.log('Manufacturer Data:');
|
|
36
|
+
console.log(` ${peripheral.advertisement.manufacturerData.toString('hex')}`);
|
|
42
37
|
}
|
|
43
38
|
|
|
39
|
+
// TX Power Level
|
|
44
40
|
if (peripheral.advertisement.txPowerLevel !== undefined) {
|
|
45
|
-
console.log(
|
|
46
|
-
console.log(`\t\t${peripheral.advertisement.txPowerLevel}`);
|
|
41
|
+
console.log(`TX Power Level: ${peripheral.advertisement.txPowerLevel}`);
|
|
47
42
|
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function main () {
|
|
46
|
+
try {
|
|
47
|
+
console.log('Waiting for Bluetooth adapter...');
|
|
48
|
+
await noble.waitForPoweredOnAsync();
|
|
49
|
+
console.log('Bluetooth adapter ready');
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
console.log('Starting scan for all devices...');
|
|
52
|
+
await noble.startScanningAsync([], false);
|
|
53
|
+
|
|
54
|
+
noble.on('discover', handleDiscovery);
|
|
55
|
+
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw new Error('Error:', error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
// Handle process termination
|
|
62
|
+
const cleanup = async () => {
|
|
63
|
+
console.log('\nCleaning up...');
|
|
64
|
+
await noble.stopScanningAsync();
|
|
65
|
+
noble.stop();
|
|
66
|
+
console.log('noble stopped');
|
|
67
|
+
};
|
|
56
68
|
|
|
57
|
-
process.on('
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
69
|
+
process.on('SIGINT', cleanup);
|
|
70
|
+
process.on('SIGQUIT', cleanup);
|
|
71
|
+
process.on('SIGTERM', cleanup);
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
noble.stopScanning(() => process.exit());
|
|
65
|
-
});
|
|
73
|
+
// Start the application
|
|
74
|
+
main().catch(console.error);
|
|
@@ -1,40 +1,65 @@
|
|
|
1
1
|
const noble = require('../index');
|
|
2
|
-
const direct = require('debug')('connection/direct');
|
|
3
|
-
const scan = require('debug')('connection/scan');
|
|
4
2
|
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
async function main () {
|
|
4
|
+
try {
|
|
5
|
+
// Wait for the BLE adapter to be ready
|
|
6
|
+
console.log('Waiting for powered on state');
|
|
7
|
+
await noble.waitForPoweredOnAsync();
|
|
8
|
+
console.log('Powered on');
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
console.log('sleeping for 2000ms');
|
|
21
|
-
await sleep(2000);
|
|
22
|
-
scan('connecting by scan');
|
|
23
|
-
await noble.startScanningAsync();
|
|
24
|
-
noble.on('discover', async peripheral => {
|
|
25
|
-
if (peripheral.uuid === uuid) {
|
|
26
|
-
await noble.stopScanningAsync();
|
|
27
|
-
await peripheral.connectAsync();
|
|
28
|
-
scan(`connected ${peripheral.uuid}`);
|
|
29
|
-
await peripheral.disconnectAsync();
|
|
30
|
-
scan('disconnected');
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
} catch (error) {
|
|
34
|
-
console.log(error);
|
|
35
|
-
}
|
|
10
|
+
// First attempt - direct connection
|
|
11
|
+
const uuid = '2561b846d6f83ee27580bca8ed6ec079'; // MacOS UUID
|
|
12
|
+
console.log('Attempting direct connection to:', uuid);
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const peripheral = await noble.connectAsync(uuid);
|
|
16
|
+
console.log('Direct connection successful to:', peripheral.id);
|
|
17
|
+
await peripheral.disconnectAsync();
|
|
18
|
+
console.log('Disconnected from direct connection');
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.log('Direct connection failed:', error.message);
|
|
36
21
|
}
|
|
37
|
-
|
|
22
|
+
|
|
23
|
+
// Wait before trying scan method
|
|
24
|
+
console.log('Waiting 2 seconds before scan attempt...');
|
|
25
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
26
|
+
|
|
27
|
+
// Second attempt - scan and connect
|
|
28
|
+
console.log('Starting scan for device');
|
|
29
|
+
await noble.startScanningAsync();
|
|
30
|
+
|
|
31
|
+
noble.on('discover', async (peripheral) => {
|
|
32
|
+
if (peripheral.id === uuid) {
|
|
33
|
+
console.log('Found device in scan:', peripheral.id);
|
|
34
|
+
await noble.stopScanningAsync();
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
await peripheral.connectAsync();
|
|
38
|
+
console.log('Scan connection successful to:', peripheral.id);
|
|
39
|
+
await peripheral.disconnectAsync();
|
|
40
|
+
console.log('Disconnected from scan connection');
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.log('Scan connection failed:', error.message);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('Main error:', error);
|
|
49
|
+
}
|
|
38
50
|
}
|
|
39
51
|
|
|
40
|
-
|
|
52
|
+
// Handle process termination
|
|
53
|
+
const cleanup = async () => {
|
|
54
|
+
console.log('Caught interrupt signal');
|
|
55
|
+
await noble.stopScanningAsync();
|
|
56
|
+
noble.stop();
|
|
57
|
+
console.log('noble stopped');
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
process.on('SIGINT', cleanup);
|
|
61
|
+
process.on('SIGQUIT', cleanup);
|
|
62
|
+
process.on('SIGTERM', cleanup);
|
|
63
|
+
|
|
64
|
+
// Start the application
|
|
65
|
+
main().catch(console.error);
|
package/examples/echo.js
CHANGED
|
@@ -11,94 +11,84 @@ const noble = require('..');
|
|
|
11
11
|
const ECHO_SERVICE_UUID = 'ec00';
|
|
12
12
|
const ECHO_CHARACTERISTIC_UUID = 'ec0e';
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
async function main () {
|
|
15
|
+
try {
|
|
16
|
+
// Wait for the BLE adapter to be ready
|
|
17
|
+
console.log('Waiting for powered on');
|
|
18
|
+
await noble.waitForPoweredOnAsync();
|
|
19
|
+
console.log('Powered on');
|
|
20
|
+
await noble.setAddress('11:22:33:44:55:66');
|
|
21
|
+
console.log('Set address');
|
|
22
|
+
await noble.startScanningAsync([ECHO_SERVICE_UUID], false);
|
|
16
23
|
console.log('Scanning');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
noble.stopScanning();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
throw new Error('Error initializing BLE:', error);
|
|
20
26
|
}
|
|
21
|
-
}
|
|
27
|
+
}
|
|
22
28
|
|
|
23
|
-
noble.on('discover', (peripheral) => {
|
|
29
|
+
noble.on('discover', async (peripheral) => {
|
|
24
30
|
// connect to the first peripheral that is scanned
|
|
25
|
-
noble.
|
|
31
|
+
await noble.stopScanningAsync();
|
|
26
32
|
const name = peripheral.advertisement.localName;
|
|
27
33
|
console.log(`Connecting to '${name}' ${peripheral.id}`);
|
|
28
34
|
connectAndSetUp(peripheral);
|
|
29
35
|
});
|
|
30
36
|
|
|
31
|
-
function connectAndSetUp (peripheral) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
console.error(error);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
37
|
+
async function connectAndSetUp (peripheral) {
|
|
38
|
+
try {
|
|
39
|
+
await peripheral.connectAsync();
|
|
38
40
|
console.log('Connected to', peripheral.id);
|
|
39
41
|
|
|
40
|
-
// specify the services and characteristics to discover
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
peripheral.discoverSomeServicesAndCharacteristics(
|
|
45
|
-
serviceUUIDs,
|
|
46
|
-
characteristicUUIDs,
|
|
47
|
-
onServicesAndCharacteristicsDiscovered
|
|
42
|
+
// // specify the services and characteristics to discover
|
|
43
|
+
const { characteristics } = await peripheral.discoverSomeServicesAndCharacteristicsAsync(
|
|
44
|
+
[ECHO_SERVICE_UUID],
|
|
45
|
+
[ECHO_CHARACTERISTIC_UUID]
|
|
48
46
|
);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
peripheral.on('disconnect', () => console.log('disconnected'));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function onServicesAndCharacteristicsDiscovered (
|
|
55
|
-
error,
|
|
56
|
-
services,
|
|
57
|
-
characteristics
|
|
58
|
-
) {
|
|
59
|
-
if (error) {
|
|
60
|
-
console.error(error);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
47
|
|
|
64
|
-
|
|
65
|
-
|
|
48
|
+
console.log('Discovered services and characteristics');
|
|
49
|
+
const echoCharacteristic = characteristics[0];
|
|
66
50
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
51
|
+
// data callback receives notifications
|
|
52
|
+
echoCharacteristic.on('read', (data, isNotification) => {
|
|
53
|
+
console.log(`Received: "${data}"`);
|
|
54
|
+
});
|
|
71
55
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.error('Error subscribing to echoCharacteristic');
|
|
76
|
-
} else {
|
|
56
|
+
// subscribe to be notified whenever the peripheral update the characteristic
|
|
57
|
+
try {
|
|
58
|
+
await echoCharacteristic.subscribeAsync();
|
|
77
59
|
console.log('Subscribed for echoCharacteristic notifications');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Error subscribing to echoCharacteristic:', error);
|
|
62
|
+
return;
|
|
78
63
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
64
|
+
|
|
65
|
+
// create an interval to send data to the service
|
|
66
|
+
let count = 0;
|
|
67
|
+
setInterval(async () => {
|
|
68
|
+
count++;
|
|
69
|
+
const message = Buffer.from(`hello, ble ${count}`, 'utf-8');
|
|
70
|
+
console.log(`Sending: '${message}'`);
|
|
71
|
+
await echoCharacteristic.writeAsync(message, false);
|
|
72
|
+
}, 2500);
|
|
73
|
+
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Error during connection setup:', error);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
peripheral.on('disconnect', () => console.log('disconnected'));
|
|
89
79
|
}
|
|
90
80
|
|
|
91
|
-
|
|
81
|
+
// Handle process termination
|
|
82
|
+
const cleanup = async () => {
|
|
92
83
|
console.log('Caught interrupt signal');
|
|
93
|
-
noble.
|
|
94
|
-
|
|
84
|
+
await noble.stopScanningAsync();
|
|
85
|
+
noble.stop();
|
|
86
|
+
console.log('noble stopped');
|
|
87
|
+
};
|
|
95
88
|
|
|
96
|
-
process.on('
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
});
|
|
89
|
+
process.on('SIGINT', cleanup);
|
|
90
|
+
process.on('SIGQUIT', cleanup);
|
|
91
|
+
process.on('SIGTERM', cleanup);
|
|
100
92
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
noble.stopScanning(() => process.exit());
|
|
104
|
-
});
|
|
93
|
+
// Start the application
|
|
94
|
+
main().catch(console.error);
|
package/examples/enter-exit.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
const noble = require('../index');
|
|
2
|
+
|
|
2
3
|
/*
|
|
3
4
|
Continuously scans for peripherals and prints out message when they enter/exit
|
|
4
5
|
|
|
@@ -7,38 +8,54 @@
|
|
|
7
8
|
|
|
8
9
|
based on code provided by: Mattias Ask (http://www.dittlof.com)
|
|
9
10
|
*/
|
|
10
|
-
const noble = require('../index');
|
|
11
11
|
|
|
12
|
-
const RSSI_THRESHOLD = -
|
|
12
|
+
const RSSI_THRESHOLD = -50;
|
|
13
13
|
const EXIT_GRACE_PERIOD = 2000; // milliseconds
|
|
14
14
|
|
|
15
|
-
const inRange =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
15
|
+
const inRange = {};
|
|
16
|
+
|
|
17
|
+
// Self-executing async function
|
|
18
|
+
(async function () {
|
|
19
|
+
try {
|
|
20
|
+
// Initialize noble
|
|
21
|
+
await noble.waitForPoweredOnAsync();
|
|
22
|
+
console.log('noble started');
|
|
23
|
+
|
|
24
|
+
// Start scanning
|
|
25
|
+
await noble.startScanningAsync([], true);
|
|
26
|
+
console.log('Scanning for peripherals...');
|
|
27
|
+
|
|
28
|
+
// Continuously discover peripherals
|
|
29
|
+
for await (const peripheral of noble.discoverAsync()) {
|
|
30
|
+
if (peripheral.rssi < RSSI_THRESHOLD) {
|
|
31
|
+
// ignore devices with weak signal
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const id = peripheral.id;
|
|
36
|
+
const entered = !inRange[id];
|
|
37
|
+
|
|
38
|
+
if (entered) {
|
|
39
|
+
inRange[id] = {
|
|
40
|
+
peripheral
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
console.log(
|
|
44
|
+
`"${peripheral.advertisement.localName}" entered (RSSI ${
|
|
45
|
+
peripheral.rssi
|
|
46
|
+
}) ${new Date()}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
inRange[id].lastSeen = Date.now();
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
throw new Error('Error:', error);
|
|
36
54
|
}
|
|
55
|
+
})();
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
setInterval(function () {
|
|
57
|
+
// Check for peripherals that have left range
|
|
58
|
+
setInterval(() => {
|
|
42
59
|
for (const id in inRange) {
|
|
43
60
|
if (inRange[id].lastSeen < Date.now() - EXIT_GRACE_PERIOD) {
|
|
44
61
|
const peripheral = inRange[id].peripheral;
|
|
@@ -54,25 +71,14 @@ setInterval(function () {
|
|
|
54
71
|
}
|
|
55
72
|
}, EXIT_GRACE_PERIOD / 2);
|
|
56
73
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
noble.startScanning([], true);
|
|
60
|
-
} else {
|
|
61
|
-
noble.stopScanning();
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
process.on('SIGINT', function () {
|
|
66
|
-
console.log('Caught interrupt signal');
|
|
67
|
-
noble.stopScanning(() => process.exit());
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
process.on('SIGQUIT', function () {
|
|
71
|
-
console.log('Caught interrupt signal');
|
|
72
|
-
noble.stopScanning(() => process.exit());
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
process.on('SIGTERM', function () {
|
|
74
|
+
// Handle process termination
|
|
75
|
+
const cleanup = async () => {
|
|
76
76
|
console.log('Caught interrupt signal');
|
|
77
|
-
noble.
|
|
78
|
-
|
|
77
|
+
await noble.stopScanningAsync();
|
|
78
|
+
noble.stop();
|
|
79
|
+
console.log('noble stopped');
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
process.on('SIGINT', cleanup);
|
|
83
|
+
process.on('SIGQUIT', cleanup);
|
|
84
|
+
process.on('SIGTERM', cleanup);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const { withBindings } = require('../index');
|
|
2
|
+
|
|
3
|
+
const nobleUartA = withBindings('hci', {
|
|
4
|
+
hciDriver: 'uart',
|
|
5
|
+
bindParams: {
|
|
6
|
+
uart: {
|
|
7
|
+
port: '/dev/tty.usbmodem1474201'
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const nobleUartB = withBindings('hci', {
|
|
13
|
+
hciDriver: 'uart',
|
|
14
|
+
bindParams: {
|
|
15
|
+
uart: {
|
|
16
|
+
port: '/dev/tty.usbmodem1474401'
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const nobleUartC = withBindings('default');
|
|
22
|
+
|
|
23
|
+
nobleUartA.on('discover', peripheral => {
|
|
24
|
+
console.log('UART A', peripheral.id);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
nobleUartB.on('discover', peripheral => {
|
|
28
|
+
console.log('UART B', peripheral.id);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
nobleUartC.on('discover', peripheral => {
|
|
32
|
+
console.log('UART C', peripheral.id);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
nobleUartA.on('stateChange', state => {
|
|
36
|
+
if (state === 'poweredOn') {
|
|
37
|
+
nobleUartA.setAddress('00:11:22:33:44:01');
|
|
38
|
+
nobleUartA.startScanning([], true);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
nobleUartB.on('stateChange', state => {
|
|
43
|
+
if (state === 'poweredOn') {
|
|
44
|
+
nobleUartB.setAddress('00:11:22:33:44:02');
|
|
45
|
+
nobleUartB.startScanning([], true);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
nobleUartC.on('stateChange', state => {
|
|
50
|
+
if (state === 'poweredOn') {
|
|
51
|
+
nobleUartC.startScanning([], true);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
const noble = require('../');
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
let directConnect = '0';
|
|
4
|
+
let peripheralIdOrAddress = 'cd:6b:86:03:39:40'.toLowerCase();
|
|
5
|
+
let addressType = 'random';
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
directConnect = process.argv[2].toLowerCase() || '0';
|
|
9
|
+
peripheralIdOrAddress = process.argv[3].toLowerCase() || 'cd:6b:86:03:39:40';
|
|
10
|
+
addressType = process.argv[4].toLowerCase() || 'random';
|
|
11
|
+
} catch (error) {
|
|
12
|
+
console.error('Error:', error);
|
|
13
|
+
}
|
|
6
14
|
|
|
7
15
|
const starTime = Date.now();
|
|
8
16
|
|
|
17
|
+
let peripheral;
|
|
9
18
|
async function main () {
|
|
10
19
|
try {
|
|
11
|
-
await noble.
|
|
20
|
+
await noble.waitForPoweredOnAsync();
|
|
21
|
+
|
|
22
|
+
// Cancel the connection after 5 seconds if it is still connecting
|
|
23
|
+
setTimeout(() => {
|
|
24
|
+
noble.cancelConnect(peripheralIdOrAddress);
|
|
25
|
+
}, 5000);
|
|
26
|
+
|
|
12
27
|
if (directConnect === '1') {
|
|
13
|
-
|
|
28
|
+
peripheral = await noble.connectAsync(peripheralIdOrAddress, { addressType });
|
|
14
29
|
await explore(peripheral);
|
|
15
30
|
} else {
|
|
16
|
-
await noble.startScanningAsync();
|
|
31
|
+
await noble.startScanningAsync([], false);
|
|
17
32
|
}
|
|
18
33
|
} catch (error) {
|
|
19
|
-
|
|
34
|
+
throw new Error('Error:', error);
|
|
20
35
|
}
|
|
21
36
|
}
|
|
22
37
|
|
|
@@ -28,6 +43,7 @@ noble.on('discover', async (peripheral) => {
|
|
|
28
43
|
await noble.stopScanningAsync();
|
|
29
44
|
|
|
30
45
|
console.log(`Peripheral with ID ${peripheral.id} found`);
|
|
46
|
+
|
|
31
47
|
const advertisement = peripheral.advertisement;
|
|
32
48
|
|
|
33
49
|
const localName = advertisement.localName;
|
|
@@ -70,14 +86,19 @@ noble.on('discover', async (peripheral) => {
|
|
|
70
86
|
const explore = async (peripheral) => {
|
|
71
87
|
console.log('Services and characteristics:');
|
|
72
88
|
|
|
73
|
-
peripheral.on('disconnect', () => {
|
|
74
|
-
|
|
89
|
+
peripheral.on('disconnect', (reason) => {
|
|
90
|
+
console.log('Disconnected', reason);
|
|
91
|
+
noble.stop();
|
|
92
|
+
console.log('noble stopped');
|
|
75
93
|
});
|
|
76
94
|
|
|
77
95
|
if (peripheral.state !== 'connected') {
|
|
78
96
|
await peripheral.connectAsync();
|
|
79
97
|
}
|
|
80
98
|
|
|
99
|
+
const rssi = await peripheral.updateRssiAsync();
|
|
100
|
+
console.log('RSSI', rssi);
|
|
101
|
+
|
|
81
102
|
const services = await peripheral.discoverServicesAsync([]);
|
|
82
103
|
|
|
83
104
|
for (const service of services) {
|
|
@@ -136,19 +157,16 @@ const explore = async (peripheral) => {
|
|
|
136
157
|
|
|
137
158
|
};
|
|
138
159
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
noble.stopScanning(() => process.exit());
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
process.on('SIGQUIT', function () {
|
|
160
|
+
// Handle process termination
|
|
161
|
+
const cleanup = async () => {
|
|
145
162
|
console.log('Caught interrupt signal');
|
|
146
|
-
noble.
|
|
147
|
-
|
|
163
|
+
await noble.stopScanningAsync();
|
|
164
|
+
noble.stop();
|
|
165
|
+
console.log('noble stopped');
|
|
166
|
+
};
|
|
148
167
|
|
|
149
|
-
process.on('
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
168
|
+
process.on('SIGINT', cleanup);
|
|
169
|
+
process.on('SIGQUIT', cleanup);
|
|
170
|
+
process.on('SIGTERM', cleanup);
|
|
153
171
|
|
|
154
172
|
main();
|