Code Monkey home page Code Monkey logo

node-ble's Introduction

node-ble's People

Contributors

altaircunhajr avatar chrvadala avatar derwehr avatar dmarku avatar lupol avatar mxc42 avatar pascalopitz avatar sunoo avatar tuxedoxt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-ble's Issues

HELP - const gattServer = await device.gatt()- don't work :/


1. const { createBluetooth } = require('node-ble')
2. const { TEST_DEVICE, TEST_SERVICE, TEST_CHARACTERISTIC, TEST_NOTIFY_SERVICE, TEST_NOTIFY_CHARACTERISTIC } = process.env
3. 
4. async function main () {
5.   const { bluetooth, destroy } = createBluetooth()
6. 
7.   // get bluetooth adapter
8.   const adapter = await bluetooth.defaultAdapter()
9.   await adapter.startDiscovery()
10.   console.log('discovering')
11. 
12.   // get device and connect
13.   const device = await adapter.waitDevice(TEST_DEVICE)
14.   console.log('got device', await device.getAddress(), await device.getName())
15.   await device.connect()
16.   console.log('connected')
17.   // console.log(device)
18.   console.log(await device.getRSSI())
19.   const gattServer = await device.gatt()
20.   console.log(gattServer)
21.   // read write characteristic
22.   const service1 = await gattServer.getPrimaryService("0000180f-0000-1000-8000-00805f9b34fb")
23.   // console.log(service1)
24.   const characteristic1 = await service1.getCharacteristic("00002a19-0000-1000-8000-00805f9b34fb")
25.   // await characteristic1.writeValue(Buffer.from('Hello world'))
26.   const buffer = await characteristic1.readValue()
27.   console.log('read', buffer, buffer.toString())
28. 
29.   destroy()
30. }
31. 
32. main()
33.   .then(console.log)
34.   .catch(console.error)
35. 

out:

discovering
got device EC:21:E5:43:94:CA BLESmart_00000044EC21E54394CA
connected
-43


I have trying to connect my blood pressure monitor to extract the data,
but in line 19 - (const gattServer = await device.gatt()) doesn't seem to work.
The code stay in line 19 and never get the service in line 22.
May some one help me? please!

Service in UUIDs list not accessible via GattServer getPrimaryService()

I'm trying to write to a MIDI characteristic of a MIDI service. The MIDI UUIDs are:

const midiServiceUUID = '03b80e5a-ede8-4b33-a751-6ce34ec4c700';
const midiCharacteristicUUID = '7772e5db38684112a1a9f2669d106bf3';

I can see the MIDI service UUID in the UUIDs property list:

> gattServer.helper.props().then(x => console.log(x))

> { Address: 'C7:26:DE:18:ED:28',
  AddressType: 'random',
  Name: 'MD-BT01',
  Alias: 'MD-BT01',
  Paired: true,
  Trusted: false,
  Blocked: false,
  LegacyPairing: false,
  RSSI: -91,
  Connected: true,
  UUIDs:
   [ '00001800-0000-1000-8000-00805f9b34fb',
     '00001801-0000-1000-8000-00805f9b34fb',
     '0000180a-0000-1000-8000-00805f9b34fb',
     '03b80e5a-ede8-4b33-a751-6ce34ec4c700' ], // <- midiServiceUUID
  Adapter: '/org/bluez/hci0',
  ServicesResolved: true }

However I can only see two service children nodes:

> gattServer.helper.children().then(x => console.log(x))

> [ 'service0008', 'service000c' ]

Trying to get to the MIDI service UUID fails:

> gattServer.getPrimaryService(midiServiceUUID).then(s => {
    console.log(s);
  }, (e) => console.log(e));

> Error: Service not available
    at GattServer.getPrimaryService (/home/pi/apps/mpr121_touch_midi/node_modules/node-ble/src/GattServer.js:41:11)

I can get two of the other service UUIDs:

> gattServer.getPrimaryService('00001801-0000-1000-8000-00805f9b34fb').then(s => {
...   s.helper.props().then(x => console.log(x));
... }, (e) => console.log(e));

> { UUID: '00001801-0000-1000-8000-00805f9b34fb',
  Device: '/org/bluez/hci0/dev_C7_26_DE_18_ED_28',
  Primary: true,
  Includes: [] }

> gattServer.getPrimaryService('0000180a-0000-1000-8000-00805f9b34fb').then(s => {
...   s.helper.props().then(x => console.log(x));
... }, (e) => console.log(e));

> { UUID: '0000180a-0000-1000-8000-00805f9b34fb',
  Device: '/org/bluez/hci0/dev_C7_26_DE_18_ED_28',
  Primary: true,
  Includes: [] }

Any ideas on how to access the MIDI Service UUID 03b80e5a-ede8-4b33-a751-6ce34ec4c700?

Operation failed with ATT error: 0x82

I was trying to write data to a GATT server but I got this error:

Operation failed with ATT error: 0x82

Do you have any idea what this means? I can write to it just fine with Chrome Web Bluetooth.

Receiving empty Buffer in characteristic.on()

When subscribing a characteristic it give an empty buffer.

Here is my code running on rpi4 with Debian Buster:

await characteristic.startNotifications()
characteristic.on('valuechanged', buffer => {
  console.log(buffer) // Show empty Buffer: <Buffer >
})

await characteristic.readValue() // Trigger the callback

Scanning multiple times causes "MaxListenersExceededWarning: Possible EventEmitter memory leak detected."

const {createBluetooth} = require('node-ble')
const {bluetooth, destroy} = createBluetooth()

async function main(){
  const adapter = await bluetooth.defaultAdapter()
  async function search(){

    if (! await adapter.isDiscovering()){
      await adapter.startDiscovery()
    }
    const devices = await adapter.devices()
    
    devices.forEach(async mac => {
      const device = await adapter.waitDevice(mac)
      let rssi;
      try {
        rssi = await device.getRSSI()
      } catch (error) {
        //console.error(error)
      }
      
      console.log(mac, rssi)
      device.disconnect()
    });
    //destroy()
    //await device.disconnect()
  }

setInterval(() => {
  search()
}, 5000);

}
main()

When I run this code it works for a minute and prints mac addresses and their RSSI value
Then i start getting warnings

(node:2234) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 {"path":"/org/bluez/hci0/dev_CC_98_8B_A7_XX_XX","interface":"org.freedesktop.DBus.Properties","member":"PropertiesChanged"} listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit

After about 10 minutes it crashes with the following error message

/home/compulab/projects/newNode-ble/node_modules/node-ble/src/Adapter.js:158
        reject(new Error('operation timed out'))
               ^

Error: operation timed out
    at Timeout._onTimeout (/home/compulab/projects/newNode-ble/node_modules/node-ble/src/Adapter.js:158:16)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7)

Node.js v18.15.0

I'm running Debian 11 with kernel version 5.15.5 on a board manufactured by Compulab
Any suggestions?

Device (properties) event listener leak

Hello,

using Adapter.getDevice followed by any property getter like Device.getName seems to leave PropertiesChanged event listeners.

Using device Device.disconnect (even when never having used Device.connect) removes listeners on Device.helper but not on Device.helper._propsProxy.

This is one of two issues I noticed while repeatedly trying to enumerate a devices and read some properties from them (in a heavy BLE traffic area).

Windows and Mac support?

Does this library support Mac and Windows, in addition to Linux?

If it does, are there any different setup instructions?

Characteristiic throwing error org.bluez.Error.InProgress

I have tested the readValue to a readable characteristic and it worked fine:

  const characteristic1 = await service1.getCharacteristic(TEST_CHARACTERISTIC_WRITE)
  const buffer = await characteristic1.readValue()
  console.log('read', buffer, buffer.toString())

But, when I try to execute writeValue in an writable characteristic with the following code, it is throwing the exception:

  const characteristic2 = await service1.getCharacteristic(TEST_CHARACTERISTIC_WRITE)
  
  await characteristic2.writeValue(Buffer.from('s'))

The error:

{ DBusError: In Progress
    at _methodReturnHandlers.(anonymous function) (/home/ica/git/ica/fecon_beta/node-ble/node_modules/dbus-next/lib/bus.js:337:27)
    at handleMessage (/home/ica/git/ica/fecon_beta/node-ble/node_modules/dbus-next/lib/bus.js:96:11)
    at EventEmitter.MessageBus.conn.on (/home/ica/git/ica/fecon_beta/node-ble/node_modules/dbus-next/lib/bus.js:146:9)
    at EventEmitter.emit (events.js:182:13)
    at /home/ica/git/ica/fecon_beta/node-ble/node_modules/dbus-next/lib/connection.js:116:14
    at Socket.<anonymous> (/home/ica/git/ica/fecon_beta/node-ble/node_modules/dbus-next/lib/message.js:63:9)
    at Socket.emit (events.js:182:13)
    at emitReadable_ (_stream_readable.js:540:12)
    at process._tickCallback (internal/process/next_tick.js:174:19)
  name: 'DBusError',
  type: 'org.bluez.Error.InProgress',
  text: 'In Progress',
  reply: 
   Message {
     type: 3,
     _sent: false,
     _serial: 2677,
     path: undefined,
     interface: undefined,
     member: undefined,
     errorName: 'org.bluez.Error.InProgress',
     replySerial: 37,
     destination: ':1.165',
     sender: ':1.12',
     signature: 's',
     body: [ 'In Progress' ],
     flags: 1 } }

Could someone help me to solve this? Any sugestion or idea?

Compatibility not specified

I had to dig through the closed issues tab to find out that this library is incompatible with windows, this should be specified on the readme to prevent people from wasting their morning like I did

Device dbus "match" leak

Hello,

using Device.getDevice repeatedly causes registered dbus "matches" to accumulate. I traced it until that _removeMatch (dbus-next) triggers on event listener removal but doesn't really send the RemoveMatch message. Now not sure if this is a bug of this library or of dbus-next or if there's a version solving it.

This is one of two issues I noticed while repeatedly trying to enumerate a devices and read some properties from them (in a heavy BLE traffic area).

Crash with uncaught exception of type Napi::Error

Hey,
When running my Node.js application that uses the @abandonware/noble library to interact with Bluetooth devices, the application crashes with the following error message:

libc++abi: terminating with uncaught exception of type Napi::Error
zsh: abort node getDTC.js

This occurs after successfully discovering a device and attempting to send a command to a characteristic.

/Relevant part of the code that leads to the crash

function sendCommand(characteristic, command) {
    const bufferCommand = Buffer.from(command, 'hex');
    characteristic.write(bufferCommand, false, (error) => {
            if (error) {
             console.error(Error writing command ${command} to characteristic ${characteristic.uuid}:, error);
              } else {
                console.log(Command ${command} sent to characteristic ${characteristic.uuid});
              }
    });
}

Any idea?

Get advertising data

Hi

I couldn't find any way to get access to the advertising data sent out by a device. It's the service data, I am especially interested in, but manufacturer data would be nice, as well.

I was looking for something like Device.getAdvertisingData(), but if there is a way to achieve this, please educate a fool. :-)

EDIT: I just noticed that pull request #61 might address my problem.

"noble: unknown peripheral c44f3371766b, 183b, 2aa1 read!" Characteristics

hello ,
I have trouble , i try to get characteristics from my BLE sensor:
const characteristicMagneticFlux = await peripheral.discoverSomeServicesAndCharacteristicsAsync(['183b'], ['2aa1']);

but when i add an other characteristics like this :
const characteristics2 = await peripheral.discoverSomeServicesAndCharacteristicsAsync(['183b'], ['2a19']);

I have an error like this

noble: unknown peripheral c44f3371766b, 183b, 2aa1 read! noble: unknown peripheral c44f3371766b, 183b, 2aa1 read!

Thanks for helping me.

How to create a peripheral?

Thank you so much for this project!

I was wondering if it is possible to create a ble peripheral that can advertise some static data?

Something similar to bleno's example.

bleno.startAdvertising(name, serviceUuids[, callback(error)]);

// or

bleno.startAdvertisingIBeacon(uuid, major, minor, measuredPower[, callback(error)]);

Can't discover service, and then 'org.bluez.Error.Failed' after a minute

I'm using RPi 4 (with node 14.9.0, BlueZ 5.50). I can discover the device, but not the service.

require('dotenv').config()

const { createBluetooth } = require('.')
const { TEST_DEVICE, TEST_SERVICE, TEST_CHARACTERISTIC, TEST_NOTIFY_SERVICE, TEST_NOTIFY_CHARACTERISTIC } = process.env

async function main () {
  const { bluetooth, destroy } = createBluetooth()

  // get bluetooth adapter
  const adapter = await bluetooth.defaultAdapter()
  await adapter.startDiscovery()
  console.log('discovering')

  // get device and connect
  const device = await adapter.waitDevice('D4:CA:6E:F1:84:BE')
  console.log('got device', await device.getAddress(), await device.getName())
  await device.connect()
  console.log('connected')

  const gattServer = await device.gatt()

  // read write characteristic
  const service1 = await gattServer.getPrimaryService('15172000-4947-11e9-8646-d663bd873d93')
  console.log('got primary service.')
  const characteristic1 = await service1.getCharacteristic('15172001-4947-11e9-8646-d663bd873d93')
  console.log('got control characteristic.')
  //await characteristic1.writeValue(Buffer.from('Hello world'))
  const buffer = await characteristic1.readValue()
  console.log('read', buffer, buffer.toString())

}

main()
  .then(console.log)
  .catch(console.error)

Console output

discovering
got device D4:CA:6E:F1:84:BE Xsens DOT
DBusError: Software caused connection abort
    at _methodReturnHandlers.<computed> (/home/pi/node-ble-master/node_modules/dbus-next/lib/bus.js:339:27)
    at handleMessage (/home/pi/node-ble-master/node_modules/dbus-next/lib/bus.js:98:11)
    at EventEmitter.<anonymous> (/home/pi/node-ble-master/node_modules/dbus-next/lib/bus.js:147:9)
    at EventEmitter.emit (events.js:314:20)
    at /home/pi/node-ble-master/node_modules/dbus-next/lib/connection.js:112:14
    at Socket.<anonymous> (/home/pi/node-ble-master/node_modules/dbus-next/lib/message.js:63:9)
    at Socket.emit (events.js:314:20)
    at emitReadable_ (_stream_readable.js:563:12)
    at processTicksAndRejections (internal/process/task_queues.js:79:21) {
  type: 'org.bluez.Error.Failed',
  text: 'Software caused connection abort',
  reply: Message {
    type: 3,
    _sent: false,
    _serial: 1494,
    path: undefined,
    interface: undefined,
    member: undefined,
    errorName: 'org.bluez.Error.Failed',
    replySerial: 13,
    destination: ':1.68',
    sender: ':1.22',
    signature: 's',
    body: [ 'Software caused connection abort' ],
    flags: 1
  }
}


Only able to write 20 bytes.

I'm using a, Raspberry Pi Zero when I try to write a string of 21 characters to a characteristic the application just hangs and hangs the receiving device as well. Where as if I send a string that 20 characters it sends perfectly.
So the weird thing is that if I use the gatttool console interface I can send significantly longer strings to that same characteristic.

Any ideas would be much appriciated,
Thanks

node-gyp error on Ubuntu 20.04

pascal@pascal-XPS-13-9370:$ npm i node-ble

> [email protected] install /home/pascal/Development/erg-mode/node_modules/abstract-socket
> node-gyp rebuild

make: Entering directory '/home/pascal/Development/erg-mode/node_modules/abstract-socket/build'
  CXX(target) Release/obj.target/bindings/src/abstract_socket.o
In file included from ../src/abstract_socket.cc:5:
../../nan/nan.h: In function ‘void Nan::AsyncQueueWorker(Nan::AsyncWorker*)’:
../../nan/nan.h:2294:62: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
 2294 |     , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
      |                                                              ^
In file included from ../../nan/nan.h:56,
                 from ../src/abstract_socket.cc:5:
../src/abstract_socket.cc: At global scope:
/home/pascal/.cache/node-gyp/13.11.0/include/node/node.h:618:43: warning: cast between incompatible function types from ‘void (*)(v8::Local<v8::Object>)’ to ‘node::addon_register_func’ {aka ‘void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’} [-Wcast-function-type]
  618 |       (node::addon_register_func) (regfunc),                          \
      |                                           ^
/home/pascal/.cache/node-gyp/13.11.0/include/node/node.h:652:3: note: in expansion of macro ‘NODE_MODULE_X’
  652 |   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
      |   ^~~~~~~~~~~~~
../src/abstract_socket.cc:181:1: note: in expansion of macro ‘NODE_MODULE’
  181 | NODE_MODULE(abstract_socket, Initialize)
      | ^~~~~~~~~~~
  SOLINK_MODULE(target) Release/obj.target/bindings.node
  COPY Release/bindings.node
make: Leaving directory '/home/pascal/Development/erg-mode/node_modules/abstract-socket/build'
npm WARN [email protected] No description
npm WARN [email protected] No repository field.

+ [email protected]
added 20 packages from 64 contributors and audited 508 packages in 13.424s

44 packages are looking for funding
  run `npm fund` for details

found 2 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details
pascal@pascal-XPS-13-9370:~/Development/erg-mode$ npm --version
6.13.7
pascal@pascal-XPS-13-9370:~/Development/erg-mode$ node --version
v13.11.0

Error: interface not found in proxy object: org.bluez.GattService1

So I'm currently trying to get some characteristic values from a device, but unfortunately I can't fix this error. Using bluetoothctl I can easily extract the characteristic values, but with the package things fail.

const { bluetooth, destroy } = createBluetooth()
const adapter = await bluetooth.defaultAdapter()

const device = await adapter.waitDevice(uuid);

if(! await device.isConnected()) {

  await device.connect();
}

console.log(await device.isConnected());
await device.gatt();
throw new Error(`interface not found in proxy object: ${name}`);
            ^

Error: interface not found in proxy object: org.bluez.GattService1

Moderate severity vulnerabilities found

Got alerts from npm audit of 7 moderate severity vulnerabilities when using this package:

# npm audit report

request  *
Severity: moderate
Server-Side Request Forgery in Request - https://github.com/advisories/GHSA-p8p7-x288-28g6
Depends on vulnerable versions of tough-cookie
No fix available
node_modules/request
  node-gyp  <=7.1.2
  Depends on vulnerable versions of request
  node_modules/node-gyp
    usocket  0.2.2 - 0.3.0
    Depends on vulnerable versions of node-gyp
    node_modules/usocket
      dbus-next  *
      Depends on vulnerable versions of usocket
      Depends on vulnerable versions of xml2js
      node_modules/dbus-next
        node-ble  >=0.0.2
        Depends on vulnerable versions of dbus-next
        node_modules/node-ble

tough-cookie  <4.1.3
Severity: moderate
tough-cookie Prototype Pollution vulnerability - https://github.com/advisories/GHSA-72xf-g2v4-qvf3
No fix available
node_modules/tough-cookie

xml2js  <0.5.0
Severity: moderate
xml2js is vulnerable to prototype pollution - https://github.com/advisories/GHSA-776f-qx25-q3cc
No fix available
node_modules/xml2js

7 moderate severity vulnerabilities

Confusing docs on pair vs connect

I'm not sure what the difference between pair and connect is. Will pair pair the device without connecting? Will connect internally call pair first if not already paired?

Docs on pair:

node-ble/docs/api.md

Lines 277 to 278 in eb20e9c

### device.pair()
This method will connect to the remote device

Doc on connect:

node-ble/docs/api.md

Lines 289 to 290 in eb20e9c

### device.connect()
Connect to remote device

Compatibility issue with Node.JS v16 and v17

Sometimes the test suite crashes with the following error (observed on NodeJS v17.0.1 and v16.13.0)

> [email protected] test:jest
> jest --testPathIgnorePatterns=e2e.spec.js

 PASS  test/Adapter.spec.js
 PASS  test/BusHelper.spec.js

 RUNS  test/GattCharacteristic.spec.js
node: ../deps/uv/src/unix/core.c:258: uv__finish_close: Assertion `handle->flags & UV_HANDLE_CLOSING' failed.
Aborted (core dumped)

How to get descriptors of characteristic

I'm transitioning from @abandonware/noble to node-ble.
I have the following code in noble to enable notifications:

let descriptors = characteristic.discoverDescriptorsAsync()
let descriptor = descriptors[0]

descriptor.once('valueWrite', this.sendConnectSequence.bind(this));
characteristic.on('data', this.onReceive.bind(this))
await descriptor.writeValueAsync(Buffer.from([0x01, 0x00]))

How do I achieve this with node-ble?
I currently have the characteristic and tried this:

await this.mepResponseChar.on('valuechanged', this.onMepResponse.bind(this))
await this.mepResponseChar.startNotifications()

but this isn't triggering any of the callbacks.
I'm assuming this because I need access to the descriptors?

Cannot intercept dev_disconnected() event

My use-case involves multiple devices which may sporadically disconnect, and I need to intercept the disconnection event - as it appears in the bluetooth logs:

src/adapter.c:dev_disconnected()

How can I assign a callback on this event using node-ble?
I mean, something similar to the callback for intercepting notifications (once registered to a Notifications characteristic), e.g.:

characteristic.on('valuechanged', buffer => {
  console.log(buffer);
});

Does the current version support this? If not, is there an easy way to add such a feature? It's an absolute must for noisy Bluetooth environments.

Throwing NotPermitted error when try to call startNotifications

Hello guys

I had try to call startNotifications and got this error:

DBusError: Write not permitted
    at _methodReturnHandlers.<computed> (/home/ricardo/Documentos/testes/scannerBlue/node_modules/dbus-next/lib/bus.js:339:27)
    at handleMessage (/home/ricardo/Documentos/testes/scannerBlue/node_modules/dbus-next/lib/bus.js:98:11)
    at EventEmitter.<anonymous> (/home/ricardo/Documentos/testes/scannerBlue/node_modules/dbus-next/lib/bus.js:147:9)
    at EventEmitter.emit (events.js:314:20)
    at /home/ricardo/Documentos/testes/scannerBlue/node_modules/dbus-next/lib/connection.js:112:14
    at Socket.<anonymous> (/home/ricardo/Documentos/testes/scannerBlue/node_modules/dbus-next/lib/message.js:63:9)
    at Socket.emit (events.js:314:20)
    at emitReadable_ (_stream_readable.js:567:12)
    at processTicksAndRejections (internal/process/task_queues.js:79:21) {
  type: 'org.bluez.Error.NotPermitted',
  text: 'Write not permitted',
  reply: Message {
    type: 3,
    _sent: false,
    _serial: 5364,
    path: undefined,
    interface: undefined,
    member: undefined,
    errorName: 'org.bluez.Error.NotPermitted',
    replySerial: 171,
    destination: ':1.401',
    sender: ':1.5',
    signature: 's',
    body: [ 'Write not permitted' ],
    flags: 1
  }
}

I'm using ubuntu 20.04, mi band 4 and node-ble 1.2.0.
Trying to get Heart Rate Measure.

This is the code I had use:

        await device.connect();
        const rssi = await device.getRSSI();
        const gattServer = await device.gatt();
        const service = await gattServer.getPrimaryService('0000180d-0000-1000-8000-00805f9b34fb');
        const characteristic = await service.getCharacteristic('00002a37-0000-1000-8000-00805f9b34fb');
        const flags = await characteristic.getFlags();
        characteristic.on('valuechanged', buffer => {
          console.log(buffer);
          device.disconnect();
        });

        await characteristic.startNotifications();

Can anyone tells me why it is throwing this error ?

Clarification of `node-ble.config` permissions/policy

The README has instructions about setting permissions here: https://github.com/chrvadala/node-ble#provide-permissions

In order to allow a connection with the DBus daemon, you have to set up right permissions.

Create the file /etc/dbus-1/system.d/node-ble.conf with the following content (customize with userid)

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
  <policy user="%userid%">
   <allow own="org.bluez"/>
    <allow send_destination="org.bluez"/>
    <allow send_interface="org.bluez.GattCharacteristic1"/>
    <allow send_interface="org.bluez.GattDescriptor1"/>
    <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
    <allow send_interface="org.freedesktop.DBus.Properties"/>
  </policy>
</busconfig>

I am adding node-ble to an electron app, which is using electron-forge to create a .deb package.
My plan to set up this file is for the deb installer to run a simple script during post-install:

#!/bin/bash
cp conf/node-ble.conf /etc/dbus-1/system.d/node-ble.conf

My issue is that I can't know at the time of packaging, what the username of whoever is installing the package will be.
Would it work to specify a permissions group instead of a username for the policy? And just require the user to be in that group?

...
<policy group="bluetooth">
  ...

How to get device name?

I experimented a bit and knowing the UUID of the device I can work with it.
As I found I can get the list of the UUIDs of the discovered devices.

How can I find out the name of the device belonging to the UUID?
Background: I like to connect to a special device who's name I will know but not its UUID.

A hint would be appreciated.

Thanks DrCWO

Event leaking. Any active notifications not removed prior to device disconnect leak.

When subscribing to a notify attribute on a BLE device with startNotifications() the created listener is not removed when a device.disconnect() is called.
This will cause the subsequent connect and subscription to have corrupt data in the valuedchanged event.

e.g.
`
const readNotify = await service.getCharacteristic('aUUid');

await readNotify .startNotifications();

readNotify.on('valuechanged',buffer=>{ buffer has some data});

await device.disconnect();

await device.connect();

await readNotify .startNotifications();

readNotify.on('valuechanged',buffer=>{ buffer has previous data and some new data});

`

Closer implementation of webBluetooth API

In order to closer follow method signatures of the web bluetooth API, i propose the following changes:

  • argument of writeValue, writeValueWithResponse and writeValueWithoutResponse should be of type BufferSource
  • return type of readValue should be Promise<DataView>

This would make it easier to switch between web and node implementations.
I could implement this if you're interested in merging.

DBuserror (Rapsberry Pi)

I'm trying to use it on a raspberry pi 3B, but I got an error from DBus

const {createBluetooth} = require('node-ble')

async function main () {
  const {bluetooth, destroy} = createBluetooth()
  const adapter = await bluetooth.defaultAdapter()
  const discovery =  await adapter.startDiscovery()
  console.log('discovering')
  console.log(await adapter.devices());

  const device = await adapter.waitDevice('04:EE:03:B1:47:DF')
  await device.connect()
  console.log('connected')

  const gattServer = await device.gatt()
  console.log(await gattServer.services());
}


main()
  .then(console.log)
  .catch(console.error)

busconfig (also tried with pi user)

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
  <policy user="root">
   <allow own="org.bluez"/>
    <allow send_destination="org.bluez"/>
    <allow send_interface="org.bluez.GattCharacteristic1"/>
    <allow send_interface="org.bluez.GattDescriptor1"/>
    <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
    <allow send_interface="org.freedesktop.DBus.Properties"/>
  </policy>
</busconfig>
discovering
[ '04:EE:03:B1:47:DF' ]
DBusError: Software caused connection abort
    at _methodReturnHandlers.<computed> (/home/pi/bergepi/node_modules/dbus-next/lib/bus.js:339:27)
    at handleMessage (/home/pi/bergepi/node_modules/dbus-next/lib/bus.js:98:11)
    at EventEmitter.<anonymous> (/home/pi/bergepi/node_modules/dbus-next/lib/bus.js:147:9)
    at EventEmitter.emit (events.js:315:20)
    at EventEmitter.emit (domain.js:482:12)
    at /home/pi/bergepi/node_modules/dbus-next/lib/connection.js:112:14
    at Socket.<anonymous> (/home/pi/bergepi/node_modules/dbus-next/lib/message.js:63:9)
    at Socket.emit (events.js:315:20)
    at Socket.EventEmitter.emit (domain.js:482:12)
    at emitReadable_ (_stream_readable.js:556:12) {
  type: 'org.bluez.Error.Failed',
  text: 'Software caused connection abort',
  reply: Message {
    type: 3,
    _sent: false,
    _serial: 58,
    path: undefined,
    interface: undefined,
    member: undefined,
    errorName: 'org.bluez.Error.Failed',
    replySerial: 12,
    destination: ':1.26',
    sender: ':1.13',
    signature: 's',
    body: [ 'Software caused connection abort' ],
    flags: 1
  }
}

BlueZ version 5.50

pi@raspberrypi:/etc/dbus-1/system.d $ bluetoothctl -v
bluetoothctl: 5.50

gatt.services() returns nothing

Here is my code where the gatt.services() function returns nothing:

const connectDevice = async (deviceName) => {
  const adapter = await bluetooth.defaultAdapter()
  
  if (! await adapter.isDiscovering())
    await adapter.startDiscovery()
  
  var devices = await adapter.devices()

  for (deviceMac of devices) {
    const device = await adapter.waitDevice(deviceMac)
    const name = await device.getAlias()
    if (name == deviceName) {
      console.log(deviceName + " found !!") // the device is found
      const gatt = await device.gatt()
      var services = await gatt.services();
      console.log(services) // give me nothing here
    } else {
      device.disconnect()
    }
  }

}

connectDevice("myDevice")

Also i'm running that on a raspberry pi 4 with sudo and nodeJS v10.21.0 from apt if ever that matters.

Device.removeAllListeners('disconnect') does not work

I try to implement reconnecting device after loosing bluetooth connection (for example because of leaving the bluetooth range). Therefore I register a listener with "Device.on('disconnect', ...)". One issue is if I call this after "Adapter.waitDevice(...)" promise on the received device, no events will be emitted. Therefore I call "Adapter.getDevice(...)" and register disconnect listener. Now the event is emitted. But for some reasons I like remove the "disconnect event listener" from Device, but this does not work.
I can see in your source, that the 'disconnect' - event is forwarded from BusHelper-propertiesChanged-event. Is this the reason that I can not unregister the listener for 'disconnect'-events on Device?

Unhandled getRSSI

(node:1883) UnhandledPromiseRejectionWarning: DBusError: No such property 'rssi'
    at _methodReturnHandlers.(anonymous function) (/root/bergepi/node_modules/dbus-next/lib/bus.js:339:27)
    at handleMessage (/root/bergepi/node_modules/dbus-next/lib/bus.js:98:11)
    at EventEmitter.MessageBus.conn.on (/root/bergepi/node_modules/dbus-next/lib/bus.js:147:9)
    at EventEmitter.emit (events.js:198:13)
    at EventEmitter.emit (domain.js:448:20)
    at /root/bergepi/node_modules/dbus-next/lib/connection.js:112:14
    at Socket.<anonymous> (/root/bergepi/node_modules/dbus-next/lib/message.js:63:9)
    at Socket.emit (events.js:198:13)
    at Socket.EventEmitter.emit (domain.js:448:20)
    at emitReadable_ (_stream_readable.js:555:12)
(node:1883) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 9)

Cannot get notifications from HCI service

Hi out there,
I got an issue I cannot solve by myself so some help would be appreciated. Here my configuration.

I am on a Raspberry with Raspbian. I have a Microsoft Surface Dial (which is a HCI device). The Surface Dial is paired with the Raspberry. I did this with bluetoothctl.

I like to get notifications directly from D-Bus so I disabled the HCI service in /lib/systemd/system/bluetooth.service by setting ExecStart=/usr/libexec/bluetooth/bluetoothd --noplugin=sap,input,hog to be able to access the HCI service via D-Bus.

In my first implementation I used RAW HCI to get the data but after a disconnect of the device it takes more than three seconds after touching the Surface Dial until the HCI-Service was available again. This is much to long as rotating the dial a sudden reaction must occur. This is why I tried to use D-Bus. So in this implementation here I get the connect event immediately but I was not able to get the data any more 👎

I used the code below to get notification from the HCI Report Characteristic of the Surface Dial but it failed:

var deviceUuid = '70:BC:10:87:C1:B8';
var genericServiceUuid = '1812';
var genericCharacteristicUuid = '2a4d';


async function startBleServer() {

	console.log('************************************** Start BLE-Server: ' + deviceUuid);

	var { createBluetooth } = require('node-ble');
	var { bluetooth, destroy } = createBluetooth();
	var adapter = await bluetooth.defaultAdapter();
	console.log('adapter: ');

	// discover surfache Dial
	if (! await adapter.isDiscovering()) {
		console.log('Start discovery: ');
		await adapter.startDiscovery()
	}

	console.log('Wait for device: ' + deviceUuid);
	var device = await adapter.waitDevice(deviceUuid);

	device.on('disconnect', function () {
		console.log('######## Ble >>>>> EVENT: ' + 'Device disconnected');
	})

	device.on('connect', function () {
		console.log('######## Ble >>>>> EVENT: ' + 'Device connected');
	})

	console.log('stop discovery');
	await adapter.stopDiscovery()

	console.log('discovered, wait till connected');
	await device.connect()


	console.log('connected, wait for GATT server');
	var gattServer = await device.gatt();
	console.log('gatt server ready!');

	// Get service UUIDs and search for service 1812
	var myServices = await gattServer.services();
	var hciServiceUuid = null;
	for (var i = 0; i < myServices.length; i++) {
		if (myServices[i].indexOf(genericServiceUuid + '-') >= 0) hciServiceUuid = myServices[i];
	}
	console.log('HCI service UUID: ' + hciServiceUuid);

	// If I found the UUID of the HCI-Service get the HCI service
	if (hciServiceUuid) {

		//********************* get hciService
		var hciService = await gattServer.getPrimaryService(hciServiceUuid);
		console.log('Serice ' + hciServiceUuid + ' discovered');

		// get the characteristic UUIDs
		var myCharacteristics = await hciService.characteristics();
		console.log('Got HCI characteristic UUIDs');

		// find Reprt Characteristi UUIDs suchen
		var reportCharacteristicUuid = null;
		for (var i = 0; i < myCharacteristics.length; i++) {
			if (myCharacteristics[i].indexOf(genericCharacteristicUuid + '-') >= 0) reportCharacteristicUuid = myCharacteristics[i];
		}
		console.log('HCI Characteristic UUID' + reportCharacteristicUuid);

		// get Report Characteristic 
		var reportCharacteristic = await hciService.getCharacteristic(reportCharacteristicUuid);
		console.log('Report Characteristics ' + reportCharacteristicUuid + ' found');

		// Setup callback for Notifications
		reportCharacteristic.on('valuechanged', buffer => {
			console.log('Data received');
			console.log(buffer)
		})
		console.log('callback set');

		await reportCharacteristic.startNotifications();
		console.log('Notification started');

	}
}

startBleServer();

Running this code anything worked fine at the beginning. The service and the characteristic were found. But trying to setup the notification I get an error message. See output below:

root@DrCWO:/home/pi# node xx_ble.js
************************************** Start BLE-Server: 70:BC:10:87:C1:B8
adapter:
Start discovery:
Wait for device: 70:BC:10:87:C1:B8
stop discovery
discovered, wait till connected
######## Ble >>>>> EVENT: Device connected
connected, wait for GATT server
gatt server ready!
HCI service UUID: 00001812-0000-1000-8000-00805f9b34fb
Serice 00001812-0000-1000-8000-00805f9b34fb discovered
Got HCI characteristic UUIDs
HCI Characteristic UUID00002a4d-0000-1000-8000-00805f9b34fb
Report Characteristics 00002a4d-0000-1000-8000-00805f9b34fb found
callback set
/home/pi/rooExtend/node_modules/dbus-next/lib/bus.js:343
            return reject(new DBusError(reply.errorName, reply.body[0], reply));
                          ^

DBusError: Operation is not supported
    at _methodReturnHandlers.<computed> (/home/pi/rooExtend/node_modules/dbus-next/lib/bus.js:343:27)
    at handleMessage (/home/pi/rooExtend/node_modules/dbus-next/lib/bus.js:101:11)
    at EventEmitter.<anonymous> (/home/pi/rooExtend/node_modules/dbus-next/lib/bus.js:151:9)
    at EventEmitter.emit (node:events:513:28)
    at /home/pi/rooExtend/node_modules/dbus-next/lib/connection.js:132:14
    at USocket.<anonymous> (/home/pi/rooExtend/node_modules/dbus-next/lib/message.js:65:9)
    at USocket.emit (node:events:513:28)
    at emitReadable_ (node:internal/streams/readable:590:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:81:21) {
  type: 'org.bluez.Error.NotSupported',
  text: 'Operation is not supported',
  reply: Message {
    type: 3,
    _sent: false,
    _serial: 3374,
    path: undefined,
    interface: undefined,
    member: undefined,
    errorName: 'org.bluez.Error.NotSupported',
    replySerial: 100,
    destination: ':1.3859',
    sender: ':1.3820',
    signature: 's',
    body: [ 'Operation is not supported' ],
    flags: 1
  }
}

Node.js v18.7.0

Any idea why I cannot start the notification?

Best DrCWO

Clean bluetooth cache command causes bluetooth errors on reboot

I'm on Ubuntu 22.04.

Running this command (from the Useful commands list)...

rm -r /var/lib/bluetooth/*

... prevents bluetooth from restarting after a reboot. All attempts to get the bluetooth service to start fail.

For example all suggestions in this question fail: https://askubuntu.com/questions/1403817/i-cant-turn-on-bluetooth-in-ubuntu-22-04-lts

The service status has a 226/NAMESPACE error message:

$ sudo systemctl status bluetooth.service
× bluetooth.service - Bluetooth service
     Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Sun 2024-04-21 19:08:23 CEST; 2min 11s ago
       Docs: man:bluetoothd(8)
   Main PID: 9746 (code=exited, status=226/NAMESPACE)
        CPU: 12ms

Apr 21 19:08:23 bo-didley systemd[1]: bluetooth.service: Scheduled restart job, restart counter is at 5.
Apr 21 19:08:23 bo-didley systemd[1]: Stopped Bluetooth service.
Apr 21 19:08:23 bo-didley systemd[1]: bluetooth.service: Start request repeated too quickly.
Apr 21 19:08:23 bo-didley systemd[1]: bluetooth.service: Failed with result 'exit-code'.
Apr 21 19:08:23 bo-didley systemd[1]: Failed to start Bluetooth service.

Hunting for that error brings up this rather strange answer which suggests running:

sudo install -dm700 /var/lib/bluetooth

This fixes the problem (after a further reboot). If that is the correct command to re-instate the cache, could I suggest adding it to the readme?

Filter by services

Hi @chrvadala,
Thank you for this project. Is there a way to discover devices by services? Is there a way to get the name of devices instead of the uuid when calling getDevices()?
Thanks

no avaliable adapter found

image

I want to get the connected bluetooth adapter name from my phone local host but I get "no available adapter found "

Interpret buffer of characteristic - encoding

I am implemented connecting heartrate sensor with another API (@ionic-nativ/bluetooth-le) successful. Now I try implementing connecting the same heartrate sensor with your API on Raspberry Pi. Connecting and start notification works well. But I don't know how I must interpret the incoming data. In "@ionic-native/bluetooth-le" there is a function "encodeStringToBytes(string): Uint8Array" (the incoming data are strings ). Then I can interpret the Uint8Array as described in Bluetooth specification.
Your interface deliver "Buffer". I don't know, how I must interpret this. Can you help me?

How to get list of devices??

Hi,
first thank you for making node-ble. Hope it will help me connecting to my devices 👍
I have a question but maybe it is also an issue, I don't know.

I like to start discovery and get the devices discovered so I can decide to which one I like to connect. In my example below I use myAdapter.devices() but is only returns an empty object. Any ideas?

I have bluetoothctl open at the same time and see that discovery starts. I also see the device announcing its UUID after some time but my code shows nothing.

Here my code:

'use strict';

async function main() {
	const { createBluetooth } = require('node-ble');
	const { bluetooth, destroy } = createBluetooth();
	var myAdapter = await bluetooth.defaultAdapter();

	console.log(myAdapter.adapter);

	if (! await myAdapter.isDiscovering()) {
		console.log ("startDiscovery");
		myAdapter.startDiscovery();
	}

	await myAdapter.isDiscovering();
	console.log ('isDiscovering');


	showDevices();

	function showDevices () {
		console.log (JSON.stringify(myAdapter.devices(), null,2));
		setTimeout (showDevices, 2000);
	}
}

main();

I can connect to one of my devices using its UUID (see working code blow). But before being able to do so I first have to find out the UUID which I expected to get with myAdapter.devices().

	const device = await adapter.waitDevice('70:BC:10:86:85:C5');
	await device.connect();

Support would be appreciated.
Best DrCWO

Listen for Beacons

Hi;

Very frustrated with noble so testing out your libraries.

I am able to discover my devices, but how would I use this to listen for beacon transmissions and read the device manufacturer's data ?

I don't see any method or property related to the manufacturer's data.

Id not want to connect to the device, but to simply read the raw data and decode it ?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.