btleplug icon indicating copy to clipboard operation
btleplug copied to clipboard

Peripheral names are missing on Windows 11

Open rsclip opened this issue 2 years ago • 6 comments

Describe the bug When getting a list of peripherals after scanning, all names are None even though they should have names. Other properties are available, only local_name is missing.

Expected behavior All peripherals with names should have their names discovered in their properties.

Actual behavior All peripherals have their local_name property as None.

Additional context Using Windows 11 might be a problem. The code I'm using is:

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let manager = Manager::new().await?;

    // get adapter
    let adapters = manager.adapters().await?;
    let central = adapters.into_iter().nth(0).unwrap();

    // start scanning for devices
    central.start_scan(ScanFilter::default()).await?;
    time::sleep(Duration::from_secs(2)).await;

    // get a list of devices that have been discovered
    let devices = central.peripherals().await?;
    for device in devices {
        // print the address and name of each device
        let properties= device.properties()
            .await
            .unwrap()
            .unwrap();
        
        let names: Vec<String> = properties
            .local_name
            .iter()
            .map(|name| name.to_string())
            .collect();
        
        println!("{}: {:?}", device.address(), names);
    }

    Ok(())
}

rsclip avatar Sep 21 '22 23:09 rsclip

I'm seeing this too. In another library, where the device name seems to function, it looks like it checks in two places to see if it can find the local_name. It's in C++ so it's a different language, but possibly helpful to know the local_name could be in one of two locations?

https://github.com/woodemi/quick_blue/blob/master/quick_blue_windows/windows/quick_blue_windows_plugin.cpp#L342

  auto device = co_await BluetoothLEDevice::FromBluetoothAddressAsync(args.BluetoothAddress());
  auto name = device ? device.Name() : args.Advertisement().LocalName();

azimuthdeveloper avatar Oct 07 '22 04:10 azimuthdeveloper

I"ve got the same issue on Windows 10 with a similar code running as expected on macOS. I will give a look if I can find something to propose (I don't want to connect to the device at this point)

context I am trying to scan & find a polar device (heart rate belt) .. without any connection and I have the same issue as reported by @Cyclip.

macOS I have used packet logger + Wireshark to sniff the BT communication and found that:

  1. advertisement packet without the device name
  2. a second packet (scan response) with the advertisement

If I'm correct, it means that on macOS the CoreBluetooth implementation is doing an active scan .. and maybe by default WinRT is sets to perform passive scan (thus without local name). In the WinRT the public BluetoothLEScanningMode ScanningMode property of the watcher is set to Passive (0) by default.

note: on the windows crate we can make the change..

Struct windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcher
...
pub fn SetScanningMode(&self, value: BluetoothLEScanningMode) -> Result<()>

My bad.. it's already in active mode (ble/watcher.rs)

self.watcher
            .SetScanningMode(BluetoothLEScanningMode::Active)
            .unwrap();

Thus, why the SCAN_RESP advertising packet is not handled and the peripheral properties updated ?

jcaude avatar Dec 12 '23 07:12 jcaude

This is what I understand about this issue...

  1. For some/many devices the local name is broadcast through a SCAN_RESP packet, thus only available during active scans
  2. As soon as you add a scan filter, you filtered out the SCAN_RESP, since there isn't any of the filtered service UUIDs, thus the device local name. Oddly, in your sample code you don't have any scan filters other than the default.
  3. I add a drop() on the RW lock, I don't know if it is related .. but now it works and I got device names

BUT, I found another issue related to the manufacturer data.. this information is sent in the first advertisement packet and properly broadcast. But, when receiving the SCAN_RESP packet there isn't' any manufacturer data payload.. still the BluetoothLEAdvertisementReceivedEventArgs contains an empty IVector<BluetoothLEManufacturerData> vector, and the current implementation doesn't check for emptiness. As a result, an empty event is emitted, and we lost the real manufacturer data. Thus, I just enclosed this part of the code with:

if manufacturer_data.Size().unwrap() > 0 {
    ....
   <orig. code + drop(RW Lock)>
   ...
}

And now it works as one would expect. I hope it helps and maybe @qdot will make the so little modifications (my fork is now a real mess and I am too lazy to make the patch).

jcaude avatar Dec 18 '23 11:12 jcaude

Huh, interesting. Yeah, I'll try to take a look at cleaning up the manufacturer data thing, I think I've actually seen that too.

@jcaude I'll take a look at the patches in your branch and see what I can bring over, would definitely love to get both these bugs out of the way.

qdot avatar Dec 18 '23 17:12 qdot

Unsure if this is related but I'm having issues getting name and full manufacturer data from devices. On Mac The devices I'm trying to get the manufacturer advertisements from come back with two ids 0x4c and 0x165 on windows I get one or the other (windows is my primary target). I need to filter by the 0x165 manufacturer id but I can't do this consistently. Is there any. I'm using version 0.11.5.

ChristianPavilonis avatar Jan 23 '24 14:01 ChristianPavilonis

Unsure if this is related but I'm having issues getting name and full manufacturer data from devices. On Mac The devices I'm trying to get the manufacturer advertisements from come back with two ids 0x4c and 0x165 on windows I get one or the other (windows is my primary target). I need to filter by the 0x165 manufacturer id but I can't do this consistently. Is there any. I'm using version 0.11.5.

To get sure about the manufacturer content you should sniff the BT communications. I suggest using PacketLogger (as part of macOS dev tools) and Wireshark.

jcaude avatar Jan 24 '24 15:01 jcaude