btleplug
btleplug copied to clipboard
Peripheral names are missing on Windows 11
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(())
}
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();
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:
- advertisement packet without the device name
- 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 ?
This is what I understand about this issue...
- For some/many devices the local name is broadcast through a SCAN_RESP packet, thus only available during active scans
- 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.
- 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).
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.
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.
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
and0x165
on windows I get one or the other (windows is my primary target). I need to filter by the0x165
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.