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 #[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 #[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 #[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 #[inline]
65 pub async fn disconnect(&self) -> Result<()> {
66 log::info!("Disconnecting device.");
67 self.peripheral.disconnect().await
68 }
69
70 #[inline]
72 pub async fn is_connected(&self) -> Result<bool> {
73 self.peripheral.is_connected().await
74 }
75
76 pub async fn services(&self) -> Result<Vec<Service>> {
78 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 pub async fn service_count(&self) -> Result<usize> {
91 Ok(self.services().await?.len())
92 }
93
94 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 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 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}