I'm using the following code to connect to a Lego Powered Up Hub using node-ble on a Framework Laptop 13 AMD running Fedora 40.
Code to reproduce the issue
const debug = require('debug')('sample-code');
const {createBluetooth} = require('node-ble');
const {bluetooth, destroy} = createBluetooth();
function sleep(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}
async function main () {
const adapter = await bluetooth.defaultAdapter();
if (! await adapter.isDiscovering()) {
await adapter.startDiscovery();
}
const device = await adapter.waitDevice('9C:9A:C0:02:E8:69');
// Bind event listeners
device.on("connect", (e) => {
debug("Connected !");
});
device.on("disconnect", (e) => {
debug("Disconnected !");
});
// Connect to the device
await device.connect();
// Do some work here
sleep(2000);
// Disconnect from the device
await device.disconnect();
// Do some heavy computation here
for (i = 0; i < 1000000000; i++) {
i = i * 1;
}
// Cleanup
destroy();
return "End of main";
}
main()
.then(debug)
.catch(debug)
Run it with :
while sleep 1; do
DEBUG="sample-code" node index.js
echo
done
Expected behavior
The following message is expected to appear on the console, until Ctrl+C is pressed.
sample-code Connected ! +0ms
sample-code Disconnected ! +3s
sample-code End of main +2s
Current behavior
2 out of 5 disconnect events are lost.
$ while; sleep 1; do DEBUG="sample-code" node index.js; echo; done
sample-code Connected ! +0ms
sample-code Disconnected ! +3s
sample-code End of main +2s
sample-code Connected ! +0ms
sample-code Disconnected ! +3s
sample-code End of main +2s
sample-code Connected ! +0ms
sample-code End of main +5s
sample-code Connected ! +0ms
sample-code Disconnected ! +3s
sample-code End of main +2s
sample-code Connected ! +0ms
sample-code End of main +5s
sample-code Connected ! +0ms
^C
The removeListeners method is called right after the disconnect method is called. It leaves only a thin window where this.helper can send a disconnect event before the event listener are removed.
Depending on how your system is loaded / scheduled, the disconnect event might arrive after the event listeners have been removed.
Possible fix
Maybe remove all listeners after all disconnect events have been sent ?
It does not match at 100% the previous API contract.
If the device has been disconnected externally (power off, weak signal, etc), currently the event handlers receives a disconnected event and a connect event as soon as the device comes back.
With the suggested fix, only a disconnected event is delivered.
What was the case for removing listeners upon explicit disconnection ?
Environment
I'm using the following code to connect to a Lego Powered Up Hub using
node-ble
on a Framework Laptop 13 AMD running Fedora 40.Code to reproduce the issue
Run it with :
Expected behavior
The following message is expected to appear on the console, until Ctrl+C is pressed.
Current behavior
2 out of 5
disconnect
events are lost.Possible explanation
In
Device.js
, in thedisconnect
method :The
removeListeners
method is called right after thedisconnect
method is called. It leaves only a thin window wherethis.helper
can send adisconnect
event before the event listener are removed.Depending on how your system is loaded / scheduled, the
disconnect
event might arrive after the event listeners have been removed.Possible fix
Maybe remove all listeners after all
disconnect
events have been sent ?It does not match at 100% the previous API contract.
If the device has been disconnected externally (power off, weak signal, etc), currently the event handlers receives a
disconnected
event and aconnect
event as soon as the device comes back.With the suggested fix, only a
disconnected
event is delivered.What was the case for removing listeners upon explicit disconnection ?