bleasy/
device.rs

1use btleplug::{
2    api::{BDAddr, Characteristic as BleCharacteristic, Peripheral as _, Service},
3    platform::{Adapter, Peripheral},
4    Result,
5};
6use std::collections::BTreeSet;
7use uuid::Uuid;
8
9use crate::Characteristic;
10
11#[derive(Debug, Clone)]
12pub struct Device {
13    pub(self) _adapter: Adapter,
14    pub(crate) peripheral: Peripheral,
15}
16
17impl Device {
18    pub(crate) fn new(adapter: Adapter, peripheral: Peripheral) -> Self {
19        Self {
20            _adapter: adapter,
21            peripheral,
22        }
23    }
24
25    #[inline]
26    pub fn address(&self) -> BDAddr {
27        self.peripheral.address()
28    }
29
30    /// Signal strength
31    #[inline]
32    pub async fn rssi(&self) -> Option<i16> {
33        self.peripheral
34            .properties()
35            .await
36            .ok()
37            .flatten()
38            .and_then(|props| props.rssi)
39    }
40
41    /// Local name of the device
42    #[inline]
43    pub async fn local_name(&self) -> Option<String> {
44        self.peripheral
45            .properties()
46            .await
47            .ok()
48            .flatten()
49            .and_then(|props| props.local_name)
50    }
51
52    /// Connect the device
53    #[inline]
54    pub async fn connect(&self) -> Result<()> {
55        if !self.is_connected().await? {
56            log::info!("Connecting device.");
57            self.peripheral.connect().await?;
58        }
59
60        Ok(())
61    }
62
63    /// Disconnect from the device
64    #[inline]
65    pub async fn disconnect(&self) -> Result<()> {
66        log::info!("Disconnecting device.");
67        self.peripheral.disconnect().await
68    }
69
70    /// Get the connected state
71    #[inline]
72    pub async fn is_connected(&self) -> Result<bool> {
73        self.peripheral.is_connected().await
74    }
75
76    /// Services advertised by the device
77    pub async fn services(&self) -> Result<Vec<Service>> {
78        // self.connect().await?;
79
80        let mut services = self.peripheral.services();
81        if services.is_empty() {
82            self.peripheral.discover_services().await?;
83            services = self.peripheral.services();
84        }
85
86        Ok(services.into_iter().collect::<Vec<_>>())
87    }
88
89    /// Number of services advertised by the device
90    pub async fn service_count(&self) -> Result<usize> {
91        Ok(self.services().await?.len())
92    }
93
94    /// Characteristics advertised by the device
95    pub async fn characteristics(&self) -> Result<Vec<Characteristic>> {
96        let characteristics = self.original_characteristics().await?;
97        Ok(characteristics
98            .into_iter()
99            .map(|characteristic| Characteristic {
100                peripheral: self.peripheral.clone(),
101                characteristic,
102            })
103            .collect::<Vec<_>>())
104    }
105
106    /// Get characteristic by UUID
107    pub async fn characteristic(&self, uuid: Uuid) -> Result<Option<Characteristic>> {
108        let characteristics = self.original_characteristics().await?;
109
110        Ok(characteristics
111            .into_iter()
112            .find(|characteristic| characteristic.uuid == uuid)
113            .map(|characteristic| Characteristic {
114                peripheral: self.peripheral.clone(),
115                characteristic,
116            }))
117    }
118
119    #[inline]
120    async fn original_characteristics(&self) -> Result<BTreeSet<BleCharacteristic>> {
121        // self.connect().await?;
122
123        let mut characteristics = self.peripheral.characteristics();
124        if characteristics.is_empty() {
125            self.peripheral.discover_services().await?;
126            characteristics = self.peripheral.characteristics();
127        }
128
129        Ok(characteristics)
130    }
131}
132
133#[derive(Debug, Clone)]
134pub enum DeviceEvent {
135    Discovered(Device),
136    Connected(Device),
137    Disconnected(Device),
138    Updated(Device),
139}