deviceplug / btleplug

Rust Cross-Platform Host-Side Bluetooth LE Access Library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Device discovery not working on Windows

NuLL3rr0r opened this issue · comments

Describe the bug
I wrote an application in Linux which all works fine and when I ran my application on Windows for the first time I was able to discover the adapters but not the peripherals. Then I tried to keep things as simple as possible. So, I decided to just build and run the examples that come with btleplug on Windows. examples/discover_adapters_peripherals.rs is not working for me. It's like my application able to discover the adapters but not the peripherals. But, the interesting thing is examples/event_driven_discovery.rs works and is able to print the expected output.

The issue is it seems it's not able to get the peripherals list. And for the event-driven-discovery it just prints the ID how can I get the properties, services, etc, is not obvious in that example.

Expected behavior
The same code that runs on Linux should also run on Windows.

Actual behavior
I've already described it above. Just building and running the example examples/discover_adapters_peripherals.rs won't work but examples/event_driven_discovery.rs works.

Additional context

Nothing to add.

OK, I've noticed the different behaviors between Windows and Linux. The following code works on Linux as expected (we don't want to connect to the devices from btleplug, instead we just want to read the connected devices list and properties, whatever device the user of the operating system has connected to):

use btleplug::api::{Central, Manager as _, Peripheral as _};
use btleplug::platform::Manager;
use std::error::Error;
use tokio::time;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    pretty_env_logger::init();

    let manager = Manager::new().await?;

    // get the first bluetooth adapter
    let central = manager
        .adapters()
        .await?
        .into_iter()
        .nth(0)
        .expect("No adapters found");

    // start scanning for devices
    central
        .start_scan(btleplug::api::ScanFilter::default())
        .await?;

    // instead of waiting, you can use central.events() to get a stream which will
    // notify you of new devices
    time::sleep(time::Duration::from_secs(2)).await;

    // get all peripherals
    let peripherals = central.peripherals().await?;

    // iterate over all found peripherals
    for peripheral in peripherals {
        // check if the peripheral is connected
        if peripheral.is_connected().await? {
            println!("Connected to peripheral: {:?}", peripheral);

            // discover services and characteristics
            peripheral.discover_services().await?;

            // get the characteristics of the peripheral
            let characteristics = peripheral.characteristics();

            // print the characteristics
            for characteristic in characteristics {
                println!("Characteristic: {:?}", characteristic);
            }
        }
    }

    Ok(())
}

However, the above code does not work on Windows. Even if the device is connected from Windows. Instead we have to explicitly connect to the device from btleplug with the following code:

use btleplug::api::{Central, Manager as _, Peripheral as _};
use btleplug::platform::Manager;
use std::error::Error;
use tokio::time;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    pretty_env_logger::init();

    let manager = Manager::new().await?;

    // get the first bluetooth adapter
    let central = manager
        .adapters()
        .await?
        .into_iter()
        .nth(0)
        .expect("No adapters found");

    // start scanning for devices
    central
        .start_scan(btleplug::api::ScanFilter::default())
        .await?;

    // instead of waiting, you can use central.events() to get a stream which will
    // notify you of new devices
    time::sleep(time::Duration::from_secs(10)).await;

    // get all peripherals
    let peripherals = central.peripherals().await?;

    // iterate over all found peripherals
    for peripheral in peripherals {
        // try to connect to the peripheral
        if peripheral.connect().await.is_ok() {
            println!("Connected to peripheral: {:?}", peripheral);

            // discover services and characteristics
            peripheral.discover_services().await?;

            // get the characteristics of the peripheral
            let characteristics = peripheral.characteristics();

            // print the characteristics
            for characteristic in characteristics {
                println!("Characteristic: {:?}", characteristic);
            }
        } else {
            println!("Failed to connect to peripheral: {:?}", peripheral);
        }
    }

    Ok(())
}

The problem here is that I don't want to connect to 100 devices in order to be able to read their characteristics or services. This is very slow for our use case.

So, how can we workaround this issue on Windows?