rust_powered_lego/
connection_manager.rs

1use std::time::Duration;
2use std::str::FromStr;
3use std::collections::HashMap;
4
5use tokio::time;
6
7use btleplug::api::{BDAddr, Manager as _, Central, ScanFilter, Peripheral as _};
8use btleplug::platform::{Manager, Peripheral};
9
10use anyhow::{Result, anyhow};
11
12use crate::hub::Hub;
13
14struct PeripheralInfo {
15    address: BDAddr,
16    local_name: String,
17    // manufacturer_data: HashMap<u16, Vec<u8>>
18}
19
20pub struct ConnectionManager {}
21
22impl ConnectionManager {
23    pub fn new() -> Self {
24        Self {}
25    }
26
27    pub async fn get_hub(
28        &self, 
29        peripheral_name: Option<String>, 
30        bd_add: Option<BDAddr>,
31        scan_time_seconds: u64,
32    ) -> Result<Hub> {
33        let p = self.get_peripheral(peripheral_name, bd_add, scan_time_seconds).await?;
34        Hub::new(p).await
35    }
36
37    async fn get_peripheral(
38        &self, 
39        mut peripheral_name: Option<String>, 
40        mut bd_add: Option<BDAddr>,
41        scan_time_seconds: u64,
42    ) -> Result<Peripheral> {
43        if bd_add.is_none() {
44            if let Ok(x) = BDAddr::from_str("00:00:00:00:00:00") {
45                bd_add = Some(x);
46            }
47        }
48        if peripheral_name.is_none() {
49            peripheral_name = Some(String::from_str("")?);
50        }
51        let peripherals = self.get_peripherals(scan_time_seconds).await?;
52        //println!("{}", peripherals.len());
53        let mut peripheral_info: PeripheralInfo;
54        if !peripherals.is_empty() {
55            
56            // All peripheral devices in range
57            for peripheral in peripherals.into_iter() {
58                peripheral_info = self.get_peripheral_info(&peripheral).await?;
59                // println!("{}", peripheral_info.local_name);
60                if peripheral_info.local_name.eq(peripheral_name.as_ref().unwrap()) || peripheral_info.address.eq(bd_add.as_ref().unwrap()) {
61                    let is_connected = peripheral.is_connected().await?;
62                    //while peripheral_info.manufacturer_data.is_empty() {
63                    //    peripheral_info = self.get_peripheral_info(&peripheral).await?;
64                    //}
65                    if !is_connected {
66                        println!("Connecting to peripheral {:?}...", &peripheral_info.local_name);
67                        if let Err(err) = peripheral.connect().await {
68                            eprintln!("Error connecting to peripheral, skipping: {}", err);
69                            continue;
70                        }
71                    }
72                    if peripheral.is_connected().await? {
73                        return Ok(peripheral);
74                    }
75                }
76            }
77        }
78        Err(anyhow!("No connections found"))
79    }
80
81    async fn get_peripherals(&self, scan_time_seconds: u64) -> Result<Vec<Peripheral>> {
82        let manager = Manager::new().await?;
83        let adapter_list = manager.adapters().await?;
84        if adapter_list.is_empty() {
85            eprintln!("No Bluetooth adapters found");
86        }
87
88        let mut peripherals: Vec<Peripheral> = Vec::new();
89
90        for adapter in adapter_list.iter() {
91            //println!("Starting scan on {}...", adapter.adapter_info().await?);
92            adapter
93                .start_scan(ScanFilter::default())
94                .await
95                .expect("Can't scan BLE adapter for connected devices...");
96            time::sleep(Duration::from_secs(scan_time_seconds)).await;
97            peripherals.append(&mut adapter.peripherals().await?);
98        }
99        Ok(peripherals)
100    }
101
102    async fn get_peripheral_info(&self, peripheral: &Peripheral) -> Result<PeripheralInfo> {
103        let properties = peripheral.properties().await?;
104        let def_str = String::from("(peripheral name unknown)");
105        let local_name = properties.as_ref().unwrap()
106            .local_name.as_ref()
107            .unwrap_or(&def_str);
108        let address = properties.as_ref()
109            .unwrap()
110            .address;
111        let mut manufacturer_data: HashMap<u16, Vec<u8>> = HashMap::new();
112        manufacturer_data.clone_from(&properties.as_ref()
113        .unwrap()
114        .manufacturer_data);
115        
116        Ok(PeripheralInfo { 
117            address: address, 
118            local_name: local_name.to_string(), 
119            // manufacturer_data: manufacturer_data,
120    })
121
122    }
123}
124