A Node.js BLE (Bluetooth Low Energy) central module.
Want to implement a peripheral? Check out bleno.
Note: macOS / Mac OS X, Linux, FreeBSD and Windows are currently the only supported OSes.
// Read the battery level of the first found peripheral exposing the Battery Level characteristic
const noble = require('@abandonware/noble');
noble.on('stateChange', async (state) => {
if (state === 'poweredOn') {
await noble.startScanningAsync(['180f'], false);
}
});
noble.on('discover', async (peripheral) => {
await noble.stopScanningAsync();
await peripheral.connectAsync();
const {characteristics} = await peripheral.discoverSomeServicesAndCharacteristicsAsync(['180f'], ['2a19']);
const batteryLevel = (await characteristics[0].readAsync())[0];
console.log(`${peripheral.address} (${peripheral.advertisement.localName}): ${batteryLevel}%`);
await peripheral.disconnectAsync();
process.exit(0);
});
const noble = require('@abandonware/noble/with-custom-binding')({extended: true});
- Install Xcode
- On newer versions of OSX, allow bluetooth access on the terminal app: "System Preferences" —> "Security & Privacy" —> "Bluetooth" -> Add terminal app (see Sandboxed terminal)
- Kernel version 3.6 or above
libbluetooth-dev
needs to be installed. For instructions for specific distributions, see below.- To set the necessary privileges to run without sudo, see this section. This is required for all distributions (Raspbian, Ubuntu, Fedora, etc). You will not get any errors if running without sudo, but nothing will happen.
See the generic Linux notes above first.
sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
Make sure node
is on your PATH
. If it's not, some options:
- Symlink
nodejs
tonode
:sudo ln -s /usr/bin/nodejs /usr/bin/node
- Install Node.js using the NodeSource package
If you are having trouble connecting to BLE devices on a Raspberry Pi, you should disable the pnat
plugin. Add the following line at the bottom of /etc/bluetooth/main.conf
:
DisablePlugins=pnat
Then restart the system.
See Issue #425 · OpenWonderLabs/homebridge-switchbot.
See the generic Linux notes above first.
sudo yum install bluez bluez-libs bluez-libs-devel
See the generic Linux notes above first.
See Configure Intel Edison for Bluetooth LE (Smart) Development.
Make sure you have GNU Make:
sudo pkg install gmake
Disable automatic loading of the default Bluetooth stack by putting no-ubt.conf into /usr/local/etc/devd/no-ubt.conf
and restarting devd (sudo service devd restart
).
Unload ng_ubt
kernel module if already loaded:
sudo kldunload ng_ubt
Make sure you have read and write permissions on the /dev/usb/*
device that corresponds to your Bluetooth adapter.
node-gyp requirements for Windows
Install the required tools and configurations using Microsoft's windows-build-tools from an elevated PowerShell or cmd.exe (run as Administrator).
npm install --global --production windows-build-tools
node-bluetooth-hci-socket prerequisites
- Compatible Bluetooth 5.0 Zephyr HCI-USB adapter (you need to add BLUETOOTH_HCI_SOCKET_USB_VID and BLUETOOTH_HCI_SOCKET_USB_PID to the process env)
- Compatible Bluetooth 4.0 USB adapter
- WinUSB driver setup for Bluetooth 4.0 USB adapter, using Zadig tool
See @don's setup guide on Bluetooth LE with Node.js and Noble on Windows
Make sure your container runs with --network=host
options and all specific environment preriquisites are verified.
npm install @abandonware/noble
In Windows OS add your custom hci-usb dongle to the process env
set BLUETOOTH_HCI_SOCKET_USB_VID=xxx
set BLUETOOTH_HCI_SOCKET_USB_PID=xxx
const noble = require('@abandonware/noble');
All operations have two API variants – one expecting a callback, one returning a Promise (denoted by Async
suffix).
Additionally, there are events corresponding to each operation (and a few global events).
For example, in case of the "discover services" operation of Peripheral:
- There's a
discoverServices
method expecting a callback:peripheral.discoverServices((error, services) => { // callback - handle error and services });
- There's a
discoverServicesAsync
method returning a Promise:try { const services = await peripheral.discoverServicesAsync(); // handle services } catch (e) { // handle error }
- There's a
servicesDiscover
event emitted after services are discovered:peripheral.once('servicesDiscover', (services) => { // handle services });
API structure:
- Scanning and discovery
- Reset device
- Peripheral
- Connect
- Event: Connected
- Cancel a pending connection
- Disconnect
- Event: Disconnected
- Update RSSI
- Event: RSSI updated
- Discover services
- Discover all services and characteristics
- Discover some services and characteristics
- Event: Services discovered
- Read handle
- Event: Handle read
- Write handle
- Event: Handle written
- Service
- Characteristic
- Descriptor
noble.on('stateChange', callback(state));
state
can be one of:
unknown
resetting
unsupported
unauthorized
poweredOff
poweredOn
noble.startScanning(); // any service UUID, no duplicates
noble.startScanning([], true); // any service UUID, allow duplicates
var serviceUUIDs = ['<service UUID 1>', ...]; // default: [] => all
var allowDuplicates = falseOrTrue; // default: false
noble.startScanning(serviceUUIDs, allowDuplicates[, callback(error)]); // particular UUIDs
NOTE: noble.state
must be poweredOn
before scanning is started. noble.on('stateChange', callback(state));
can be used to listen for state change events.
noble.on('scanStart', callback);
The event is emitted when:
- Scanning is started
- Another application enables scanning
- Another application changes scanning settings
noble.stopScanning();
noble.on('scanStop', callback);