Struct Adapter

Source
pub struct Adapter(/* private fields */);
Expand description

The system’s Bluetooth adapter interface.

The default adapter for the system may be accessed with the Adapter::default() method.

Implementations§

Source§

impl Adapter

Source

pub async fn default() -> Option<Self>

Creates an interface to the default Bluetooth adapter for the system

Examples found in repository?
examples/scan.rs (line 22)
9async fn main() -> Result<(), Box<dyn Error>> {
10    use tracing_subscriber::prelude::*;
11    use tracing_subscriber::{fmt, EnvFilter};
12
13    tracing_subscriber::registry()
14        .with(fmt::layer())
15        .with(
16            EnvFilter::builder()
17                .with_default_directive(LevelFilter::INFO.into())
18                .from_env_lossy(),
19        )
20        .init();
21
22    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
23    adapter.wait_available().await?;
24
25    info!("starting scan");
26    let mut scan = adapter.scan(&[]).await?;
27    info!("scan started");
28    while let Some(discovered_device) = scan.next().await {
29        info!(
30            "{}{}: {:?}",
31            discovered_device.device.name().as_deref().unwrap_or("(unknown)"),
32            discovered_device
33                .rssi
34                .map(|x| format!(" ({}dBm)", x))
35                .unwrap_or_default(),
36            discovered_device.adv_data.services
37        );
38    }
39
40    Ok(())
41}
More examples
Hide additional examples
examples/connect.rs (line 23)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
24    adapter.wait_available().await?;
25
26    let discovered_device = {
27        info!("starting scan");
28        let services = &[btuuid::services::USER_DATA];
29        let mut scan = adapter.scan(services).await?;
30        info!("scan started");
31        scan.next().await.ok_or("scan terminated")?
32    };
33
34    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
35    adapter.connect_device(&discovered_device.device).await?;
36    info!("connected!");
37
38    tokio::time::sleep(Duration::from_secs(30)).await;
39
40    adapter.disconnect_device(&discovered_device.device).await?;
41    info!("disconnected!");
42
43    Ok(())
44}
examples/pair.rs (line 85)
72async fn main() -> Result<(), Box<dyn Error>> {
73    use tracing_subscriber::prelude::*;
74    use tracing_subscriber::{fmt, EnvFilter};
75
76    tracing_subscriber::registry()
77        .with(fmt::layer())
78        .with(
79            EnvFilter::builder()
80                .with_default_directive(LevelFilter::INFO.into())
81                .from_env_lossy(),
82        )
83        .init();
84
85    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
86    adapter.wait_available().await?;
87
88    let discovered_device = {
89        info!("starting scan");
90        let mut scan = adapter.scan(&[btuuid::services::HUMAN_INTERFACE_DEVICE]).await?;
91        info!("scan started");
92        scan.next().await.ok_or("scan terminated")?
93    };
94
95    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
96    let device = discovered_device.device;
97
98    adapter.connect_device(&device).await?;
99    info!("connected!");
100
101    device.pair_with_agent(&StdioPairingAgent).await?;
102    info!("paired!");
103
104    adapter.disconnect_device(&device).await?;
105    info!("disconnected!");
106
107    Ok(())
108}
examples/reconnect.rs (line 24)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let device_id = {
24        let adapter = Adapter::default().await.unwrap();
25        adapter.wait_available().await?;
26
27        info!("looking for device");
28        let device = adapter
29            .discover_devices(&[btuuid::services::BATTERY])
30            .await?
31            .next()
32            .await
33            .ok_or("Failed to discover device")??;
34        info!(
35            "found device: {} ({:?})",
36            device.name().as_deref().unwrap_or("(unknown)"),
37            device.id()
38        );
39
40        device.id()
41    };
42
43    info!("Time passes...");
44    tokio::time::sleep(Duration::from_secs(5)).await;
45
46    {
47        let adapter = Adapter::default().await.unwrap();
48        adapter.wait_available().await?;
49
50        info!("re-opening previously found device");
51        let device = adapter.open_device(&device_id).await?;
52        info!(
53            "re-opened device: {} ({:?})",
54            device.name().as_deref().unwrap_or("(unknown)"),
55            device.id()
56        );
57    }
58
59    Ok(())
60}
examples/connected.rs (line 21)
8async fn main() -> Result<(), Box<dyn Error>> {
9    use tracing_subscriber::prelude::*;
10    use tracing_subscriber::{fmt, EnvFilter};
11
12    tracing_subscriber::registry()
13        .with(fmt::layer())
14        .with(
15            EnvFilter::builder()
16                .with_default_directive(LevelFilter::INFO.into())
17                .from_env_lossy(),
18        )
19        .init();
20
21    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
22    adapter.wait_available().await?;
23
24    info!("getting connected devices");
25    let devices = adapter.connected_devices().await?;
26    for device in devices {
27        info!("found {:?}", device);
28        adapter.connect_device(&device).await?;
29        let services = device.services().await?;
30        for service in services {
31            info!("  {:?}", service);
32            let characteristics = service.characteristics().await?;
33            for characteristic in characteristics {
34                info!("    {:?}", characteristic);
35                let props = characteristic.properties().await?;
36                info!("      props: {:?}", props);
37                if props.read {
38                    info!("      value: {:?}", characteristic.read().await);
39                }
40                if props.write_without_response {
41                    info!("      max_write_len: {:?}", characteristic.max_write_len());
42                }
43
44                let descriptors = characteristic.descriptors().await?;
45                for descriptor in descriptors {
46                    info!("      {:?}: {:?}", descriptor, descriptor.read().await);
47                }
48            }
49        }
50    }
51    info!("done");
52
53    Ok(())
54}
examples/blinky.rs (line 27)
14async fn main() -> Result<(), Box<dyn Error>> {
15    use tracing_subscriber::prelude::*;
16    use tracing_subscriber::{fmt, EnvFilter};
17
18    tracing_subscriber::registry()
19        .with(fmt::layer())
20        .with(
21            EnvFilter::builder()
22                .with_default_directive(LevelFilter::INFO.into())
23                .from_env_lossy(),
24        )
25        .init();
26
27    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
28    adapter.wait_available().await?;
29
30    info!("looking for device");
31    let device = adapter
32        .discover_devices(&[NORDIC_LED_AND_BUTTON_SERVICE])
33        .await?
34        .next()
35        .await
36        .ok_or("Failed to discover device")??;
37    info!(
38        "found device: {} ({:?})",
39        device.name().as_deref().unwrap_or("(unknown)"),
40        device.id()
41    );
42
43    adapter.connect_device(&device).await?;
44    info!("connected!");
45
46    let service = match device
47        .discover_services_with_uuid(NORDIC_LED_AND_BUTTON_SERVICE)
48        .await?
49        .first()
50    {
51        Some(service) => service.clone(),
52        None => return Err("service not found".into()),
53    };
54    info!("found LED and button service");
55
56    let characteristics = service.characteristics().await?;
57    info!("discovered characteristics");
58
59    let button_characteristic = characteristics
60        .iter()
61        .find(|x| x.uuid() == BLINKY_BUTTON_STATE_CHARACTERISTIC)
62        .ok_or("button characteristic not found")?;
63
64    let button_fut = async {
65        info!("enabling button notifications");
66        let mut updates = button_characteristic.notify().await?;
67        info!("waiting for button changes");
68        while let Some(val) = updates.next().await {
69            info!("Button state changed: {:?}", val?);
70        }
71        Ok(())
72    };
73
74    let led_characteristic = characteristics
75        .iter()
76        .find(|x| x.uuid() == BLINKY_LED_STATE_CHARACTERISTIC)
77        .ok_or("led characteristic not found")?;
78
79    let blink_fut = async {
80        info!("blinking LED");
81        tokio::time::sleep(Duration::from_secs(1)).await;
82        loop {
83            led_characteristic.write(&[0x01]).await?;
84            info!("LED on");
85            tokio::time::sleep(Duration::from_secs(1)).await;
86            led_characteristic.write(&[0x00]).await?;
87            info!("LED off");
88            tokio::time::sleep(Duration::from_secs(1)).await;
89        }
90    };
91
92    type R = Result<(), Box<dyn Error>>;
93    let button_fut = async move {
94        let res: R = button_fut.await;
95        error!("Button task exited: {:?}", res);
96    };
97    let blink_fut = async move {
98        let res: R = blink_fut.await;
99        error!("Blink task exited: {:?}", res);
100    };
101
102    future::zip(blink_fut, button_fut).await;
103
104    Ok(())
105}
Source

pub async fn events( &self, ) -> Result<impl Stream<Item = Result<AdapterEvent>> + Send + Unpin + '_>

A stream of AdapterEvent which allows the application to identify when the adapter is enabled or disabled.

Source

pub async fn wait_available(&self) -> Result<()>

Asynchronously blocks until the adapter is available

Examples found in repository?
examples/scan.rs (line 23)
9async fn main() -> Result<(), Box<dyn Error>> {
10    use tracing_subscriber::prelude::*;
11    use tracing_subscriber::{fmt, EnvFilter};
12
13    tracing_subscriber::registry()
14        .with(fmt::layer())
15        .with(
16            EnvFilter::builder()
17                .with_default_directive(LevelFilter::INFO.into())
18                .from_env_lossy(),
19        )
20        .init();
21
22    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
23    adapter.wait_available().await?;
24
25    info!("starting scan");
26    let mut scan = adapter.scan(&[]).await?;
27    info!("scan started");
28    while let Some(discovered_device) = scan.next().await {
29        info!(
30            "{}{}: {:?}",
31            discovered_device.device.name().as_deref().unwrap_or("(unknown)"),
32            discovered_device
33                .rssi
34                .map(|x| format!(" ({}dBm)", x))
35                .unwrap_or_default(),
36            discovered_device.adv_data.services
37        );
38    }
39
40    Ok(())
41}
More examples
Hide additional examples
examples/connect.rs (line 24)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
24    adapter.wait_available().await?;
25
26    let discovered_device = {
27        info!("starting scan");
28        let services = &[btuuid::services::USER_DATA];
29        let mut scan = adapter.scan(services).await?;
30        info!("scan started");
31        scan.next().await.ok_or("scan terminated")?
32    };
33
34    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
35    adapter.connect_device(&discovered_device.device).await?;
36    info!("connected!");
37
38    tokio::time::sleep(Duration::from_secs(30)).await;
39
40    adapter.disconnect_device(&discovered_device.device).await?;
41    info!("disconnected!");
42
43    Ok(())
44}
examples/pair.rs (line 86)
72async fn main() -> Result<(), Box<dyn Error>> {
73    use tracing_subscriber::prelude::*;
74    use tracing_subscriber::{fmt, EnvFilter};
75
76    tracing_subscriber::registry()
77        .with(fmt::layer())
78        .with(
79            EnvFilter::builder()
80                .with_default_directive(LevelFilter::INFO.into())
81                .from_env_lossy(),
82        )
83        .init();
84
85    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
86    adapter.wait_available().await?;
87
88    let discovered_device = {
89        info!("starting scan");
90        let mut scan = adapter.scan(&[btuuid::services::HUMAN_INTERFACE_DEVICE]).await?;
91        info!("scan started");
92        scan.next().await.ok_or("scan terminated")?
93    };
94
95    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
96    let device = discovered_device.device;
97
98    adapter.connect_device(&device).await?;
99    info!("connected!");
100
101    device.pair_with_agent(&StdioPairingAgent).await?;
102    info!("paired!");
103
104    adapter.disconnect_device(&device).await?;
105    info!("disconnected!");
106
107    Ok(())
108}
examples/reconnect.rs (line 25)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let device_id = {
24        let adapter = Adapter::default().await.unwrap();
25        adapter.wait_available().await?;
26
27        info!("looking for device");
28        let device = adapter
29            .discover_devices(&[btuuid::services::BATTERY])
30            .await?
31            .next()
32            .await
33            .ok_or("Failed to discover device")??;
34        info!(
35            "found device: {} ({:?})",
36            device.name().as_deref().unwrap_or("(unknown)"),
37            device.id()
38        );
39
40        device.id()
41    };
42
43    info!("Time passes...");
44    tokio::time::sleep(Duration::from_secs(5)).await;
45
46    {
47        let adapter = Adapter::default().await.unwrap();
48        adapter.wait_available().await?;
49
50        info!("re-opening previously found device");
51        let device = adapter.open_device(&device_id).await?;
52        info!(
53            "re-opened device: {} ({:?})",
54            device.name().as_deref().unwrap_or("(unknown)"),
55            device.id()
56        );
57    }
58
59    Ok(())
60}
examples/connected.rs (line 22)
8async fn main() -> Result<(), Box<dyn Error>> {
9    use tracing_subscriber::prelude::*;
10    use tracing_subscriber::{fmt, EnvFilter};
11
12    tracing_subscriber::registry()
13        .with(fmt::layer())
14        .with(
15            EnvFilter::builder()
16                .with_default_directive(LevelFilter::INFO.into())
17                .from_env_lossy(),
18        )
19        .init();
20
21    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
22    adapter.wait_available().await?;
23
24    info!("getting connected devices");
25    let devices = adapter.connected_devices().await?;
26    for device in devices {
27        info!("found {:?}", device);
28        adapter.connect_device(&device).await?;
29        let services = device.services().await?;
30        for service in services {
31            info!("  {:?}", service);
32            let characteristics = service.characteristics().await?;
33            for characteristic in characteristics {
34                info!("    {:?}", characteristic);
35                let props = characteristic.properties().await?;
36                info!("      props: {:?}", props);
37                if props.read {
38                    info!("      value: {:?}", characteristic.read().await);
39                }
40                if props.write_without_response {
41                    info!("      max_write_len: {:?}", characteristic.max_write_len());
42                }
43
44                let descriptors = characteristic.descriptors().await?;
45                for descriptor in descriptors {
46                    info!("      {:?}: {:?}", descriptor, descriptor.read().await);
47                }
48            }
49        }
50    }
51    info!("done");
52
53    Ok(())
54}
examples/blinky.rs (line 28)
14async fn main() -> Result<(), Box<dyn Error>> {
15    use tracing_subscriber::prelude::*;
16    use tracing_subscriber::{fmt, EnvFilter};
17
18    tracing_subscriber::registry()
19        .with(fmt::layer())
20        .with(
21            EnvFilter::builder()
22                .with_default_directive(LevelFilter::INFO.into())
23                .from_env_lossy(),
24        )
25        .init();
26
27    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
28    adapter.wait_available().await?;
29
30    info!("looking for device");
31    let device = adapter
32        .discover_devices(&[NORDIC_LED_AND_BUTTON_SERVICE])
33        .await?
34        .next()
35        .await
36        .ok_or("Failed to discover device")??;
37    info!(
38        "found device: {} ({:?})",
39        device.name().as_deref().unwrap_or("(unknown)"),
40        device.id()
41    );
42
43    adapter.connect_device(&device).await?;
44    info!("connected!");
45
46    let service = match device
47        .discover_services_with_uuid(NORDIC_LED_AND_BUTTON_SERVICE)
48        .await?
49        .first()
50    {
51        Some(service) => service.clone(),
52        None => return Err("service not found".into()),
53    };
54    info!("found LED and button service");
55
56    let characteristics = service.characteristics().await?;
57    info!("discovered characteristics");
58
59    let button_characteristic = characteristics
60        .iter()
61        .find(|x| x.uuid() == BLINKY_BUTTON_STATE_CHARACTERISTIC)
62        .ok_or("button characteristic not found")?;
63
64    let button_fut = async {
65        info!("enabling button notifications");
66        let mut updates = button_characteristic.notify().await?;
67        info!("waiting for button changes");
68        while let Some(val) = updates.next().await {
69            info!("Button state changed: {:?}", val?);
70        }
71        Ok(())
72    };
73
74    let led_characteristic = characteristics
75        .iter()
76        .find(|x| x.uuid() == BLINKY_LED_STATE_CHARACTERISTIC)
77        .ok_or("led characteristic not found")?;
78
79    let blink_fut = async {
80        info!("blinking LED");
81        tokio::time::sleep(Duration::from_secs(1)).await;
82        loop {
83            led_characteristic.write(&[0x01]).await?;
84            info!("LED on");
85            tokio::time::sleep(Duration::from_secs(1)).await;
86            led_characteristic.write(&[0x00]).await?;
87            info!("LED off");
88            tokio::time::sleep(Duration::from_secs(1)).await;
89        }
90    };
91
92    type R = Result<(), Box<dyn Error>>;
93    let button_fut = async move {
94        let res: R = button_fut.await;
95        error!("Button task exited: {:?}", res);
96    };
97    let blink_fut = async move {
98        let res: R = blink_fut.await;
99        error!("Blink task exited: {:?}", res);
100    };
101
102    future::zip(blink_fut, button_fut).await;
103
104    Ok(())
105}
Source

pub async fn open_device(&self, id: &DeviceId) -> Result<Device>

Attempts to create the device identified by id

Examples found in repository?
examples/reconnect.rs (line 51)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let device_id = {
24        let adapter = Adapter::default().await.unwrap();
25        adapter.wait_available().await?;
26
27        info!("looking for device");
28        let device = adapter
29            .discover_devices(&[btuuid::services::BATTERY])
30            .await?
31            .next()
32            .await
33            .ok_or("Failed to discover device")??;
34        info!(
35            "found device: {} ({:?})",
36            device.name().as_deref().unwrap_or("(unknown)"),
37            device.id()
38        );
39
40        device.id()
41    };
42
43    info!("Time passes...");
44    tokio::time::sleep(Duration::from_secs(5)).await;
45
46    {
47        let adapter = Adapter::default().await.unwrap();
48        adapter.wait_available().await?;
49
50        info!("re-opening previously found device");
51        let device = adapter.open_device(&device_id).await?;
52        info!(
53            "re-opened device: {} ({:?})",
54            device.name().as_deref().unwrap_or("(unknown)"),
55            device.id()
56        );
57    }
58
59    Ok(())
60}
Source

pub async fn connected_devices(&self) -> Result<Vec<Device>>

Finds all connected Bluetooth LE devices

Examples found in repository?
examples/connected.rs (line 25)
8async fn main() -> Result<(), Box<dyn Error>> {
9    use tracing_subscriber::prelude::*;
10    use tracing_subscriber::{fmt, EnvFilter};
11
12    tracing_subscriber::registry()
13        .with(fmt::layer())
14        .with(
15            EnvFilter::builder()
16                .with_default_directive(LevelFilter::INFO.into())
17                .from_env_lossy(),
18        )
19        .init();
20
21    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
22    adapter.wait_available().await?;
23
24    info!("getting connected devices");
25    let devices = adapter.connected_devices().await?;
26    for device in devices {
27        info!("found {:?}", device);
28        adapter.connect_device(&device).await?;
29        let services = device.services().await?;
30        for service in services {
31            info!("  {:?}", service);
32            let characteristics = service.characteristics().await?;
33            for characteristic in characteristics {
34                info!("    {:?}", characteristic);
35                let props = characteristic.properties().await?;
36                info!("      props: {:?}", props);
37                if props.read {
38                    info!("      value: {:?}", characteristic.read().await);
39                }
40                if props.write_without_response {
41                    info!("      max_write_len: {:?}", characteristic.max_write_len());
42                }
43
44                let descriptors = characteristic.descriptors().await?;
45                for descriptor in descriptors {
46                    info!("      {:?}: {:?}", descriptor, descriptor.read().await);
47                }
48            }
49        }
50    }
51    info!("done");
52
53    Ok(())
54}
Source

pub async fn connected_devices_with_services( &self, services: &[Uuid], ) -> Result<Vec<Device>>

Finds all connected devices providing any service in services

§Panics

Panics if services is empty.

Source

pub async fn scan<'a>( &'a self, services: &'a [Uuid], ) -> Result<impl Stream<Item = AdvertisingDevice> + Send + Unpin + 'a>

Starts scanning for Bluetooth advertising packets.

Returns a stream of AdvertisingDevice structs which contain the data from the advertising packet and the Device which sent it. Scanning is automatically stopped when the stream is dropped. Inclusion of duplicate packets is a platform-specific implementation detail.

If services is not empty, returns advertisements including at least one GATT service with a UUID in services. Otherwise returns all advertisements.

Examples found in repository?
examples/scan.rs (line 26)
9async fn main() -> Result<(), Box<dyn Error>> {
10    use tracing_subscriber::prelude::*;
11    use tracing_subscriber::{fmt, EnvFilter};
12
13    tracing_subscriber::registry()
14        .with(fmt::layer())
15        .with(
16            EnvFilter::builder()
17                .with_default_directive(LevelFilter::INFO.into())
18                .from_env_lossy(),
19        )
20        .init();
21
22    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
23    adapter.wait_available().await?;
24
25    info!("starting scan");
26    let mut scan = adapter.scan(&[]).await?;
27    info!("scan started");
28    while let Some(discovered_device) = scan.next().await {
29        info!(
30            "{}{}: {:?}",
31            discovered_device.device.name().as_deref().unwrap_or("(unknown)"),
32            discovered_device
33                .rssi
34                .map(|x| format!(" ({}dBm)", x))
35                .unwrap_or_default(),
36            discovered_device.adv_data.services
37        );
38    }
39
40    Ok(())
41}
More examples
Hide additional examples
examples/connect.rs (line 29)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
24    adapter.wait_available().await?;
25
26    let discovered_device = {
27        info!("starting scan");
28        let services = &[btuuid::services::USER_DATA];
29        let mut scan = adapter.scan(services).await?;
30        info!("scan started");
31        scan.next().await.ok_or("scan terminated")?
32    };
33
34    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
35    adapter.connect_device(&discovered_device.device).await?;
36    info!("connected!");
37
38    tokio::time::sleep(Duration::from_secs(30)).await;
39
40    adapter.disconnect_device(&discovered_device.device).await?;
41    info!("disconnected!");
42
43    Ok(())
44}
examples/pair.rs (line 90)
72async fn main() -> Result<(), Box<dyn Error>> {
73    use tracing_subscriber::prelude::*;
74    use tracing_subscriber::{fmt, EnvFilter};
75
76    tracing_subscriber::registry()
77        .with(fmt::layer())
78        .with(
79            EnvFilter::builder()
80                .with_default_directive(LevelFilter::INFO.into())
81                .from_env_lossy(),
82        )
83        .init();
84
85    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
86    adapter.wait_available().await?;
87
88    let discovered_device = {
89        info!("starting scan");
90        let mut scan = adapter.scan(&[btuuid::services::HUMAN_INTERFACE_DEVICE]).await?;
91        info!("scan started");
92        scan.next().await.ok_or("scan terminated")?
93    };
94
95    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
96    let device = discovered_device.device;
97
98    adapter.connect_device(&device).await?;
99    info!("connected!");
100
101    device.pair_with_agent(&StdioPairingAgent).await?;
102    info!("paired!");
103
104    adapter.disconnect_device(&device).await?;
105    info!("disconnected!");
106
107    Ok(())
108}
Source

pub async fn discover_devices<'a>( &'a self, services: &'a [Uuid], ) -> Result<impl Stream<Item = Result<Device>> + Send + Unpin + 'a>

Finds Bluetooth devices providing any service in services.

Returns a stream of Device structs with matching connected devices returned first. If the stream is not dropped before all matching connected devices are consumed then scanning will begin for devices advertising any of the services. Scanning will continue until the stream is dropped. Inclusion of duplicate devices is a platform-specific implementation detail.

Examples found in repository?
examples/reconnect.rs (line 29)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let device_id = {
24        let adapter = Adapter::default().await.unwrap();
25        adapter.wait_available().await?;
26
27        info!("looking for device");
28        let device = adapter
29            .discover_devices(&[btuuid::services::BATTERY])
30            .await?
31            .next()
32            .await
33            .ok_or("Failed to discover device")??;
34        info!(
35            "found device: {} ({:?})",
36            device.name().as_deref().unwrap_or("(unknown)"),
37            device.id()
38        );
39
40        device.id()
41    };
42
43    info!("Time passes...");
44    tokio::time::sleep(Duration::from_secs(5)).await;
45
46    {
47        let adapter = Adapter::default().await.unwrap();
48        adapter.wait_available().await?;
49
50        info!("re-opening previously found device");
51        let device = adapter.open_device(&device_id).await?;
52        info!(
53            "re-opened device: {} ({:?})",
54            device.name().as_deref().unwrap_or("(unknown)"),
55            device.id()
56        );
57    }
58
59    Ok(())
60}
More examples
Hide additional examples
examples/blinky.rs (line 32)
14async fn main() -> Result<(), Box<dyn Error>> {
15    use tracing_subscriber::prelude::*;
16    use tracing_subscriber::{fmt, EnvFilter};
17
18    tracing_subscriber::registry()
19        .with(fmt::layer())
20        .with(
21            EnvFilter::builder()
22                .with_default_directive(LevelFilter::INFO.into())
23                .from_env_lossy(),
24        )
25        .init();
26
27    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
28    adapter.wait_available().await?;
29
30    info!("looking for device");
31    let device = adapter
32        .discover_devices(&[NORDIC_LED_AND_BUTTON_SERVICE])
33        .await?
34        .next()
35        .await
36        .ok_or("Failed to discover device")??;
37    info!(
38        "found device: {} ({:?})",
39        device.name().as_deref().unwrap_or("(unknown)"),
40        device.id()
41    );
42
43    adapter.connect_device(&device).await?;
44    info!("connected!");
45
46    let service = match device
47        .discover_services_with_uuid(NORDIC_LED_AND_BUTTON_SERVICE)
48        .await?
49        .first()
50    {
51        Some(service) => service.clone(),
52        None => return Err("service not found".into()),
53    };
54    info!("found LED and button service");
55
56    let characteristics = service.characteristics().await?;
57    info!("discovered characteristics");
58
59    let button_characteristic = characteristics
60        .iter()
61        .find(|x| x.uuid() == BLINKY_BUTTON_STATE_CHARACTERISTIC)
62        .ok_or("button characteristic not found")?;
63
64    let button_fut = async {
65        info!("enabling button notifications");
66        let mut updates = button_characteristic.notify().await?;
67        info!("waiting for button changes");
68        while let Some(val) = updates.next().await {
69            info!("Button state changed: {:?}", val?);
70        }
71        Ok(())
72    };
73
74    let led_characteristic = characteristics
75        .iter()
76        .find(|x| x.uuid() == BLINKY_LED_STATE_CHARACTERISTIC)
77        .ok_or("led characteristic not found")?;
78
79    let blink_fut = async {
80        info!("blinking LED");
81        tokio::time::sleep(Duration::from_secs(1)).await;
82        loop {
83            led_characteristic.write(&[0x01]).await?;
84            info!("LED on");
85            tokio::time::sleep(Duration::from_secs(1)).await;
86            led_characteristic.write(&[0x00]).await?;
87            info!("LED off");
88            tokio::time::sleep(Duration::from_secs(1)).await;
89        }
90    };
91
92    type R = Result<(), Box<dyn Error>>;
93    let button_fut = async move {
94        let res: R = button_fut.await;
95        error!("Button task exited: {:?}", res);
96    };
97    let blink_fut = async move {
98        let res: R = blink_fut.await;
99        error!("Blink task exited: {:?}", res);
100    };
101
102    future::zip(blink_fut, button_fut).await;
103
104    Ok(())
105}
Source

pub async fn connect_device(&self, device: &Device) -> Result<()>

Connects to the Device

§Platform specifics
§MacOS/iOS

This method must be called before any methods on the Device which require a connection are called. After a successful return from this method, a connection has been established with the device (if one did not already exist) and the application can then interact with the device. This connection will be maintained until either disconnect_device is called or the Adapter is dropped.

§Windows

On Windows, device connections are automatically managed by the OS. This method has no effect. Instead, a connection will automatically be established, if necessary, when methods on the device requiring a connection are called.

§Linux

If the device is not yet connected to the system, this method must be called before any methods on the Device which require a connection are called. After a successful return from this method, a connection has been established with the device (if one did not already exist) and the application can then interact with the device. This connection will be maintained until disconnect_device is called.

Examples found in repository?
examples/connect.rs (line 35)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
24    adapter.wait_available().await?;
25
26    let discovered_device = {
27        info!("starting scan");
28        let services = &[btuuid::services::USER_DATA];
29        let mut scan = adapter.scan(services).await?;
30        info!("scan started");
31        scan.next().await.ok_or("scan terminated")?
32    };
33
34    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
35    adapter.connect_device(&discovered_device.device).await?;
36    info!("connected!");
37
38    tokio::time::sleep(Duration::from_secs(30)).await;
39
40    adapter.disconnect_device(&discovered_device.device).await?;
41    info!("disconnected!");
42
43    Ok(())
44}
More examples
Hide additional examples
examples/pair.rs (line 98)
72async fn main() -> Result<(), Box<dyn Error>> {
73    use tracing_subscriber::prelude::*;
74    use tracing_subscriber::{fmt, EnvFilter};
75
76    tracing_subscriber::registry()
77        .with(fmt::layer())
78        .with(
79            EnvFilter::builder()
80                .with_default_directive(LevelFilter::INFO.into())
81                .from_env_lossy(),
82        )
83        .init();
84
85    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
86    adapter.wait_available().await?;
87
88    let discovered_device = {
89        info!("starting scan");
90        let mut scan = adapter.scan(&[btuuid::services::HUMAN_INTERFACE_DEVICE]).await?;
91        info!("scan started");
92        scan.next().await.ok_or("scan terminated")?
93    };
94
95    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
96    let device = discovered_device.device;
97
98    adapter.connect_device(&device).await?;
99    info!("connected!");
100
101    device.pair_with_agent(&StdioPairingAgent).await?;
102    info!("paired!");
103
104    adapter.disconnect_device(&device).await?;
105    info!("disconnected!");
106
107    Ok(())
108}
examples/connected.rs (line 28)
8async fn main() -> Result<(), Box<dyn Error>> {
9    use tracing_subscriber::prelude::*;
10    use tracing_subscriber::{fmt, EnvFilter};
11
12    tracing_subscriber::registry()
13        .with(fmt::layer())
14        .with(
15            EnvFilter::builder()
16                .with_default_directive(LevelFilter::INFO.into())
17                .from_env_lossy(),
18        )
19        .init();
20
21    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
22    adapter.wait_available().await?;
23
24    info!("getting connected devices");
25    let devices = adapter.connected_devices().await?;
26    for device in devices {
27        info!("found {:?}", device);
28        adapter.connect_device(&device).await?;
29        let services = device.services().await?;
30        for service in services {
31            info!("  {:?}", service);
32            let characteristics = service.characteristics().await?;
33            for characteristic in characteristics {
34                info!("    {:?}", characteristic);
35                let props = characteristic.properties().await?;
36                info!("      props: {:?}", props);
37                if props.read {
38                    info!("      value: {:?}", characteristic.read().await);
39                }
40                if props.write_without_response {
41                    info!("      max_write_len: {:?}", characteristic.max_write_len());
42                }
43
44                let descriptors = characteristic.descriptors().await?;
45                for descriptor in descriptors {
46                    info!("      {:?}: {:?}", descriptor, descriptor.read().await);
47                }
48            }
49        }
50    }
51    info!("done");
52
53    Ok(())
54}
examples/blinky.rs (line 43)
14async fn main() -> Result<(), Box<dyn Error>> {
15    use tracing_subscriber::prelude::*;
16    use tracing_subscriber::{fmt, EnvFilter};
17
18    tracing_subscriber::registry()
19        .with(fmt::layer())
20        .with(
21            EnvFilter::builder()
22                .with_default_directive(LevelFilter::INFO.into())
23                .from_env_lossy(),
24        )
25        .init();
26
27    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
28    adapter.wait_available().await?;
29
30    info!("looking for device");
31    let device = adapter
32        .discover_devices(&[NORDIC_LED_AND_BUTTON_SERVICE])
33        .await?
34        .next()
35        .await
36        .ok_or("Failed to discover device")??;
37    info!(
38        "found device: {} ({:?})",
39        device.name().as_deref().unwrap_or("(unknown)"),
40        device.id()
41    );
42
43    adapter.connect_device(&device).await?;
44    info!("connected!");
45
46    let service = match device
47        .discover_services_with_uuid(NORDIC_LED_AND_BUTTON_SERVICE)
48        .await?
49        .first()
50    {
51        Some(service) => service.clone(),
52        None => return Err("service not found".into()),
53    };
54    info!("found LED and button service");
55
56    let characteristics = service.characteristics().await?;
57    info!("discovered characteristics");
58
59    let button_characteristic = characteristics
60        .iter()
61        .find(|x| x.uuid() == BLINKY_BUTTON_STATE_CHARACTERISTIC)
62        .ok_or("button characteristic not found")?;
63
64    let button_fut = async {
65        info!("enabling button notifications");
66        let mut updates = button_characteristic.notify().await?;
67        info!("waiting for button changes");
68        while let Some(val) = updates.next().await {
69            info!("Button state changed: {:?}", val?);
70        }
71        Ok(())
72    };
73
74    let led_characteristic = characteristics
75        .iter()
76        .find(|x| x.uuid() == BLINKY_LED_STATE_CHARACTERISTIC)
77        .ok_or("led characteristic not found")?;
78
79    let blink_fut = async {
80        info!("blinking LED");
81        tokio::time::sleep(Duration::from_secs(1)).await;
82        loop {
83            led_characteristic.write(&[0x01]).await?;
84            info!("LED on");
85            tokio::time::sleep(Duration::from_secs(1)).await;
86            led_characteristic.write(&[0x00]).await?;
87            info!("LED off");
88            tokio::time::sleep(Duration::from_secs(1)).await;
89        }
90    };
91
92    type R = Result<(), Box<dyn Error>>;
93    let button_fut = async move {
94        let res: R = button_fut.await;
95        error!("Button task exited: {:?}", res);
96    };
97    let blink_fut = async move {
98        let res: R = blink_fut.await;
99        error!("Blink task exited: {:?}", res);
100    };
101
102    future::zip(blink_fut, button_fut).await;
103
104    Ok(())
105}
Source

pub async fn disconnect_device(&self, device: &Device) -> Result<()>

Disconnects from the Device

§Platform specifics
§MacOS/iOS

Once this method is called, the application will no longer have access to the Device and any methods which would require a connection will fail. If no other application has a connection to the same device, the underlying Bluetooth connection will be closed.

§Windows

On Windows, device connections are automatically managed by the OS. This method has no effect. Instead, the connection will be closed only when the Device and all its child objects are dropped.

§Linux

This method disconnects the device from the system, even if other applications are using the device.

Examples found in repository?
examples/connect.rs (line 40)
10async fn main() -> Result<(), Box<dyn Error>> {
11    use tracing_subscriber::prelude::*;
12    use tracing_subscriber::{fmt, EnvFilter};
13
14    tracing_subscriber::registry()
15        .with(fmt::layer())
16        .with(
17            EnvFilter::builder()
18                .with_default_directive(LevelFilter::INFO.into())
19                .from_env_lossy(),
20        )
21        .init();
22
23    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
24    adapter.wait_available().await?;
25
26    let discovered_device = {
27        info!("starting scan");
28        let services = &[btuuid::services::USER_DATA];
29        let mut scan = adapter.scan(services).await?;
30        info!("scan started");
31        scan.next().await.ok_or("scan terminated")?
32    };
33
34    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
35    adapter.connect_device(&discovered_device.device).await?;
36    info!("connected!");
37
38    tokio::time::sleep(Duration::from_secs(30)).await;
39
40    adapter.disconnect_device(&discovered_device.device).await?;
41    info!("disconnected!");
42
43    Ok(())
44}
More examples
Hide additional examples
examples/pair.rs (line 104)
72async fn main() -> Result<(), Box<dyn Error>> {
73    use tracing_subscriber::prelude::*;
74    use tracing_subscriber::{fmt, EnvFilter};
75
76    tracing_subscriber::registry()
77        .with(fmt::layer())
78        .with(
79            EnvFilter::builder()
80                .with_default_directive(LevelFilter::INFO.into())
81                .from_env_lossy(),
82        )
83        .init();
84
85    let adapter = Adapter::default().await.ok_or("Bluetooth adapter not found")?;
86    adapter.wait_available().await?;
87
88    let discovered_device = {
89        info!("starting scan");
90        let mut scan = adapter.scan(&[btuuid::services::HUMAN_INTERFACE_DEVICE]).await?;
91        info!("scan started");
92        scan.next().await.ok_or("scan terminated")?
93    };
94
95    info!("{:?} {:?}", discovered_device.rssi, discovered_device.adv_data);
96    let device = discovered_device.device;
97
98    adapter.connect_device(&device).await?;
99    info!("connected!");
100
101    device.pair_with_agent(&StdioPairingAgent).await?;
102    info!("paired!");
103
104    adapter.disconnect_device(&device).await?;
105    info!("disconnected!");
106
107    Ok(())
108}
Source

pub async fn device_connection_events<'a>( &'a self, device: &'a Device, ) -> Result<impl Stream<Item = ConnectionEvent> + Send + Unpin + 'a>

Monitors a device for connection/disconnection events.

§Platform specifics
§MacOS/iOS

On MacOS connection events will only be generated for calls to connect_device and disconnection events will only be generated for devices that have been connected with connect_device.

On iOS/iPadOS connection and disconnection events can be generated for any device.

Trait Implementations§

Source§

impl Clone for Adapter

Source§

fn clone(&self) -> Adapter

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Adapter

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Hash for Adapter

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Adapter

Source§

fn eq(&self, other: &Adapter) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Adapter

Source§

impl StructuralPartialEq for Adapter

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more