chrvadala / node-ble

Bluetooth Low Energy (BLE) library written with pure Node.js (no bindings) - baked by Bluez via DBus
https://www.npmjs.com/package/node-ble
MIT License
320 stars 47 forks source link

Cannot get notifications from HCI service #62

Open DrCWO opened 1 year ago

DrCWO commented 1 year ago

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

lesha369 commented 1 year ago

your connect is destroying when you get characteristics.
this problem in hardware bluetooth.

DrCWO commented 1 year ago

Hi Alexey and thank's for your reply. I still don't understand how to make it work. Using the default HCI-Driver in the kernel the hardware works but delayed after reconnect. I believe that the hardware is OK as the HCI-driver can use it. So I want to know what to do to make it work? Are you able to help with a solution?