deviceplug / btleplug

Rust Cross-Platform Host-Side Bluetooth LE Access Library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

can not find device already connect to computer

dongjian opened this issue · comments

Describe the bug

I have a keyboard that communicates through GATT. When he is not linked to the computer, it can be searched normally, but when it is linked to the computer, it cannot be found. But I can find the device normally (whether it is already connected to the computer or not) using "Bluetooth LE Explorer".

Expected behavior
device can be find normal

Actual behavior
can not find device when it connect to computer

I test both on Windows 10 and Mac 11.6.4

My test code

let manager = Manager::new().await.unwrap();
let adapter_list = manager.adapters().await.unwrap();

println!("adapter len  === {}", adapter_list.len());
let central = manager
    .adapters()
    .await
    .expect("Unable to fetch adapter list.")
    .into_iter()
    .nth(0)
    .expect("Unable to find adapters.");
let mut events = central.events().await.unwrap();
central.start_scan(ScanFilter::default()).await.unwrap();
loop {
    tokio::time::sleep(Duration::from_secs(2)).await;
    for p in central.peripherals().await.unwrap() {
        println!("{:?}",p.properties().await.unwrap().unwrap().local_name);
        if p.properties()
            .await
            .unwrap()
            .unwrap()
            .local_name
            .iter()
            .any(|name| name.contains("RY KB3 5.0"))
        {
            println!("FFFFIIIIINNNNNNNDDDDDDDDD");
        }
    }
}
commented

Does the keyboard still work as an actual keyboard? Is it bonded to your system? If so, this may be the operating system picking it up in the HID manager before anything else can get to it.

Does the keyboard still work as an actual keyboard? Is it bonded to your system? If so, this may be the operating system picking it up in the HID manager before anything else can get to it.

yes.keyboard work as an actual keyboard. but I can find the device use "Blue Tooth Le Explorer" OR in Chrome use the code below
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

commented

I'm also getting this issue on win10. If the device is already paired/connected, enumerating the peripherals on an adapter will only yield BT devices that are available for pairing but not yet connected. It seems silly to have to remove/unpair the device and then put it back in pairing mode and let btleplug do a scan, find the device and connect, instead of just being able to find an existing connection.

It may be, as you say, the OS picking up the HID manager before anything else can get to it but I have a similar C# based set of code that is able to connect to existing BT connections on the same device, and in theory, it should be using the same win dlls that the windows crate dependency is using.

commented

From the btleplug discord channel, recording here just in case a PR doesn't come in:

Ok, I think I got something that will work. If you used a
Windows::Devices::Enumeration::DeviceInformation::CreateWatcherWithKindAqsFilterAndAdditionalProperties()
with the hand written aql selector that fetches all BT LE protocol devices and pass None to the additional properties (since we can't create the necessary collection in rust) and provide the "kind" of AssociationEndpoint, we get a watcher than shows both connected and not connected advertising devices.

As I said above, the thing it sends to the handlers is a more generic DeviceInformation type that doesn't have any BT related information, like connections status, bt address, etc.. instead of the BluetoothLEAdvertisementReceivedEventArgs you are currently getting from the advertisement watcher. However, that doesn't matter at all as I now see you weren't getting anything useful from those args except the bluetooth_address and then using that to get a windows::Devices::Bluetooth::BluetoothLEDevice from BluetoothLEDevice.FromBluetoothAddressAsync() that you wrap in the BLEDevice struct. Luckily, one thing the DeviceInformation does have is an ID and BluetoothLEDevice also has a BluetoothLEDevice::FromIdAsync() .

So I think it would only take swapping the watcher, updating the handler types, and changing BLEDevice struct's new() to instead take the deviceId instead of BDaddr, then getting the BluetoothLEDevice from BluetoothLEDevice::FromIdAsync() instead and everything else should work exactly as it did with the other watcher.

The same problem =(
(Mac, Ventura 13.3)