capacitor-community / bluetooth-le

Capacitor plugin for Bluetooth Low Energy
MIT License
285 stars 85 forks source link

Trouble detecting specific BLE device when using requestLEScan with targeted services #645

Closed urbilog closed 4 months ago

urbilog commented 7 months ago

Describe the bug Description: I'm encountering an issue while using the requestLEScan function in the @capacitor-community/bluetooth-le plugin. When I attempt to scan for a specific BLE device by targeting its service UUIDs using the services option, I'm unable to detect anything. However, when I leave the services option as an empty array, I can detect the desired device in the list of discovered devices. Additionally, I confirmed that the correct UUID is present in the result.rawAdvertisement?.buffer.

To Reproduce Steps to reproduce the behavior:

  1. Use the requestLEScan function with the services option targeting specific service UUIDs.
  2. Attempt to detect a specific BLE device.
  3. Notice that no devices are detected.
  4. Remove the specific service UUID targeting and rescan.
  5. Observe that the desired device is detected in the list of discovered devices.

Expected behavior When specifying the service UUIDs in the services option, I expect the requestLEScan function to detect the targeted BLE device.

Plugin version:

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Note: I've verified that the issue persists across multiple attempts and have reviewed the documentation for any potential misconfigurations. Any assistance or guidance on resolving this issue would be greatly appreciated.

eggbeard commented 6 months ago

Still present in ^6.0.0

peitschie commented 6 months ago

@urbilog are you able to confirm that the advertising packet has the requested service UUID in it?

In BLE, there is a distinction between the services the peripheral supports, and the services the peripheral advertises. What does the advertised services contain for one of these peripherals you're scanning for?

eggbeard commented 6 months ago

So I have something like this:

async BLEServiceTest(){
    await BleClient.initialize({ androidNeverForLocation: true });
    const isBonded = await BleClient.isBonded('48:A4:93:4B:19:B5');
    console.log('isBonded1', isBonded); //True if paired
    await BleClient.connect('48:A4:93:4B:19:B5');
    const services = await BleClient.getServices('48:A4:93:4B:19:B5'); //By Mac address
    console.log('Services of 48:A4:93:4B:19:B5 are:', services);

    // Of these services '38eb4a80-c570-11e3-9507-0002a5d5c51b' is the one I care about
    // This is a Zebra thermal printer
    // https://www.zebra.com/content/dam/zebra/software/en/application-notes/AppNote-BlueToothLE-v4.pdf
    const zebraDevice: BleDevice = await BleClient.requestDevice({
      services:['38eb4a80-c570-11e3-9507-0002a5d5c51b']
    });
    console.log('BleClient.requestDevice with Zebra Service:', zebraDevice);
  }

When connecting to the printer by mac address services are logged as: image

Note this includes '38eb4a80-c570-11e3-9507-0002a5d5c51b'. Is this a supported or an advertised service?

async BLEServiceTest2(){
    await BleClient.initialize({ androidNeverForLocation: true });

    const device: BleDevice = await BleClient.requestDevice();
    // Produces a long list that does include the device above
    console.log('BleClient.requestDevice with no options:', device);
  }

This does present UI for a long list of devices, but this is not really useful for an end user since they don't now about device ids and uuids. For example:

Screenshot_20240521_082830_Volt - SAA Mobile

If I have not already connected to the device then it does appear in this list, but it's often hard to find so really I want to filter to something more relevant.

So now I try something like:

const zebraDevice: BleDevice = await BleClient.requestDevice({
      services:['38eb4a80-c570-11e3-9507-0002a5d5c51b']
    });

Giving me: Screenshot_20240521_085108_Volt - SAA Mobile

Screenshot_20240521_085125_Volt - SAA Mobile

Is this the wrong way to do this?

Finally if I try:


  await BleClient.initialize({ androidNeverForLocation: true });

  const devices: BleDevice[] = await BleClient.getConnectedDevices(['38eb4a80-c570-11e3-9507-0002a5d5c51b']);
  devices.forEach(device => {
    console.log('Device:', device);
  });

that also returns nothing

image

peitschie commented 6 months ago

Hi @eggbeard

You're showing the list of services after connection. But, the filtering during a scan applies based on the advertising payload only. Most peripherals advertise only a small subset of the services they support.

I'd suggest looking at your peripheral's advertising payload (without connecting) in nrf Connect to see whether the service you want to filter by is included in the advertising packet.

eggbeard commented 6 months ago

This is the answer. I finally understand a little better. nrf Connect is very useful in understanding what is going on. It had not occurred to me that the advertising payload could be so different from the services list once connected.

pwespi commented 4 months ago

Thank you @peitschie for your help in debugging this. Seems to be resolved now.