Example: Discovering and Inspecting Devices
This example provides a complete walkthrough of the process of scanning for all nearby BLE peripherals, connecting to each one, discovering its services and characteristics, and then disconnecting.
This is a useful pattern for debugging or developing a general-purpose BLE scanner application.
Full Code
This code is based on examples/discover_adapters_peripherals.rs
.
use std::time::Duration;
use tokio::time;
use btleplug::api::{Central, Manager as _, Peripheral, ScanFilter};
use btleplug::platform::Manager;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize the logger
pretty_env_logger::init();
// Initialize the manager and get the first adapter
let manager = Manager::new().await?;
let adapter_list = manager.adapters().await?;
if adapter_list.is_empty() {
eprintln!("No Bluetooth adapters found");
return Ok(());
}
for adapter in adapter_list.iter() {
println!("Starting scan on {}...", adapter.adapter_info().await?);
adapter
.start_scan(ScanFilter::default())
.await
.expect("Can't scan BLE adapter for connected devices...");
// Scan for 10 seconds
time::sleep(Duration::from_secs(10)).await;
let peripherals = adapter.peripherals().await?;
if peripherals.is_empty() {
eprintln!("->>> No BLE peripheral devices were found.");
} else {
println!("Found {} peripherals:", peripherals.len());
// Iterate through all discovered peripherals
for peripheral in peripherals.iter() {
let properties = peripheral.properties().await?;
let local_name = properties
.unwrap()
.local_name
.unwrap_or_else(|| String::from("(peripheral name unknown)"));
println!("\n--- Peripheral: {} ---", local_name);
// Try to connect
println!("Connecting to {}...", &local_name);
if let Err(err) = peripheral.connect().await {
eprintln!("Error connecting to peripheral, skipping: {}", err);
continue;
}
let is_connected = peripheral.is_connected().await?;
println!("Successfully connected: {}", is_connected);
if is_connected {
// Discover services
println!("Discovering services...");
peripheral.discover_services().await?;
// Print all services and their characteristics
for service in peripheral.services() {
println!(
" Service: UUID {}, Primary: {}",
service.uuid, service.primary
);
for characteristic in service.characteristics {
println!(" Characteristic: {:?}", characteristic);
}
}
// Disconnect
println!("Disconnecting from {}...", &local_name);
peripheral
.disconnect()
.await
.expect("Error disconnecting from BLE peripheral");
}
}
}
}
Ok(())
}
Explanation
- Setup: We initialize a logger, the
Manager
, and get a list of all available BluetoothAdapter
s. - Scan: For each adapter, we call
start_scan
with a default (empty) filter to find all devices. Wesleep
for 10 seconds to allow ample time for devices to be discovered. - Get Peripherals: After scanning,
adapter.peripherals().await?
returns aVec<Peripheral>
containing all devices found during the scan. - Iterate and Connect: The code loops through each peripheral.
- It retrieves and prints the peripheral's
local_name
. - It attempts to
connect()
. If the connection fails, it prints an error and moves to the next peripheral.
- It retrieves and prints the peripheral's
- Discover and Inspect: If the connection is successful:
- It calls
discover_services()
to populate the peripheral's service and characteristic cache. - It then iterates through
peripheral.services()
andservice.characteristics
, printing detailed information about each.
- It calls
- Disconnect: Finally, it calls
disconnect()
to cleanly close the connection before moving on to the next peripheral.