@csllc/noble-ble
v2.2.0
Published
Wraps @abandonware/noble for compatibility with @csllc/blejs-types
Keywords
Readme
@csllc/noble-ble
Node.js BLE adapter that implements the @csllc/blejs-types Ble interface by wrapping @abandonware/noble, suitable for desktop (Windows, macOS, Linux) and Raspberry Pi applications.
Installation
npm install @csllc/noble-bleOptional peer dependency (required at runtime for actual BLE hardware):
npm install @abandonware/noble@abandonware/noble is an optional dependency. The package will install successfully without it; call isSupported() at runtime to check availability. If noble is not available, initialize() will throw.
Overview
NobleBleManager is a module-level singleton object implementing the full Ble interface. It wraps @abandonware/noble and handles:
- Lazy loading of noble (avoids hard failures on unsupported platforms)
- UUID normalization to lowercase without hyphens (required by noble)
- Promise-based interface over noble's callback/event style
- Case-insensitive UUID comparison in
findCharacteristics
Use this package whenever you need BLE from a Node.js process on a system that supports @abandonware/noble (typically Linux with a Bluetooth adapter, macOS, or Windows).
Usage
Initialize and scan for devices
import { NobleBleManager as Ble } from '@csllc/noble-ble';
import { serviceUuid } from '@csllc/cs1816';
// Check support before using (noble may not be available on all platforms)
const supported = await Ble.isSupported();
if (!supported) throw new Error('BLE not available');
// Initialize — waits for Bluetooth to reach 'poweredOn' state
await Ble.initialize({ logger: myLogger });
// Listen for discovered peripherals
Ble.on('discover', (peripheral) => {
console.log('Found:', peripheral.name, peripheral.id);
});
// Start scanning
await Ble.startScan([serviceUuid], null, { duplicates: false });
// Stop scanning
await Ble.stopScan();Connect and use characteristics
// Connect to a discovered peripheral
await Ble.connect(peripheral);
// Discover characteristics
const characteristics = await Ble.findCharacteristics(peripheral, serviceUuid, [
{
name: 'tx',
characteristic: '49535343-8841-43F4-A8D4-ECBE34729BB3',
required: true,
},
{
name: 'rx',
characteristic: '49535343-1E4D-4BD9-BA61-23C647249616',
required: true,
},
]);
const txChar = characteristics.get('tx')!;
// Subscribe to notifications
await Ble.subscribe(peripheral, txChar, (data: number[]) => {
console.log('Notification bytes:', data);
});
// Write bytes
await Ble.write(peripheral, txChar, [0x01, 0x02, 0x03]);
// Read bytes
const value = await Ble.read(peripheral, txChar);
console.log('Read value:', value);
// Unsubscribe
await Ble.unsubscribe(peripheral, txChar);
// Disconnect
await Ble.disconnect(peripheral);Read RSSI
const rssi = await Ble.rssi(peripheral);
console.log('Signal strength:', rssi, 'dBm');Access the underlying noble driver
const driver = Ble.driver();
if (driver) {
// driver is the raw @abandonware/noble instance
// Use only when the Ble interface does not expose what you need
}Clean up
await Ble.destroy();API Reference
NobleBleManager
The named export — a module-level singleton implementing the Ble interface from @csllc/blejs-types.
| Method | Returns | Description |
| -------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| isSupported() | Promise<boolean> | Returns true if @abandonware/noble can be loaded. Does not require Bluetooth to be powered on. |
| isAllowed() | Promise<boolean> | Same as isSupported() — noble does not have a separate permission model. |
| driver() | {} \| null | Returns the loaded noble instance, or null if not yet loaded or unavailable. |
| initialize(options?) | Promise<boolean> | Loads noble, registers state/discover/scanStop listeners, and waits for Bluetooth to enter 'poweredOn' state. Throws if Bluetooth is not available or not turned on. |
| enable() | Promise<boolean> | No-op on noble (returns true). Bluetooth must be enabled at the OS level. |
| checkState() | Promise<undefined> | No-op (returns undefined). Noble emits state changes automatically. |
| on(event, fn, context?) | void | Registers a listener on the internal event bus. |
| off(event, fn, context?) | void | Removes a listener from the internal event bus. |
| destroy() | Promise<undefined> | Removes noble event listeners and clears the internal event bus. |
| getKnownDevices(services) | Promise<BlePeripheral[]> | Always returns [] — noble does not maintain a cache of known devices. |
| startScan(services, cb, options?) | Promise<void> | Starts scanning. Normalizes service UUIDs to lowercase before passing to noble. Emits scanning: true. |
| stopScan() | Promise<void> | Stops scanning and removes the per-scan discover callback. |
| connect(peripheral) | Promise<void> | Connects to a peripheral using noble's connectAsync(). Emits connect. |
| disconnect(peripheral, options?) | Promise<boolean> | Disconnects using noble's disconnectAsync(). Emits disconnect. Returns false. |
| rssi(peripheral) | Promise<number> | Calls noble's updateRssiAsync() to measure current RSSI. |
| read(peripheral, characteristic) | Promise<number[]> | Reads a characteristic value via noble's readAsync(). Returns the bytes as number[]. |
| write(peripheral, characteristic, data) | Promise<void> | Writes bytes to a characteristic via noble's writeAsync() (with response). |
| subscribe(peripheral, characteristic, cb) | Promise<void> | Subscribes to notifications and calls cb with each received number[]. |
| unsubscribe(peripheral, characteristic) | Promise<void> | Unsubscribes from characteristic notifications. |
| findCharacteristics(peripheral, service, wanted) | Promise<Map<string, BleCharacteristic>> | Discovers the service, then discovers all characteristics and returns a map of name-to-characteristic for each requested UUID. Uses case-insensitive UUID comparison. Throws if a required characteristic is not found. |
Events
Listen for these via NobleBleManager.on(event, fn):
| Event | Arg | Description |
| ------------ | ------------------------ | -------------------------------------------------------------------------- |
| enable | boolean | Bluetooth adapter state changed. true when noble state is 'poweredOn'. |
| scanning | boolean | Scan started (true) or stopped (false). |
| discover | BlePeripheral | A peripheral was found during a scan. |
| connect | string (peripheral id) | A peripheral connected. |
| disconnect | string (peripheral id) | A peripheral disconnected. |
UUID handling
Noble normalizes all UUIDs to lowercase without hyphens internally. NobleBleManager applies the same normalization (uuid.toLowerCase().replace(/-/g, '')) to all UUIDs you pass in, so you can supply UUIDs in any case or hyphenated format.
Lazy loading
Noble is loaded via dynamic import() the first time isSupported() or initialize() is called. If @abandonware/noble is not installed or fails to import (e.g. on an unsupported platform), isSupported() returns false and initialize() throws an error instead of failing at require-time.
Logging
Pass a logger implementing the Logger interface to initialize():
await NobleBleManager.initialize({
logger: {
info: console.info,
error: console.error,
warn: console.warn,
trace: console.log,
},
});If the logger has a .child() method, a child logger named 'noble-ble' will be used for all output from this package.
