1use btleplug::{
2 api::{Characteristic as BtleCharacteristic, Peripheral as _, WriteType},
3 platform::Peripheral,
4 Result,
5};
6use std::pin::Pin;
7use tokio_stream::{Stream, StreamExt};
8use uuid::Uuid;
9
10#[derive(Debug, Clone)]
11pub struct Characteristic {
12 pub(crate) peripheral: Peripheral,
13 pub(crate) characteristic: BtleCharacteristic,
14}
15
16impl Characteristic {
17 pub async fn read(&self) -> Result<Vec<u8>> {
18 self.peripheral.read(&self.characteristic).await
19 }
20
21 pub async fn write_request(&self, data: &[u8]) -> Result<()> {
22 self.write(data, WriteType::WithResponse).await
23 }
24
25 pub async fn write_command(&self, data: &[u8]) -> Result<()> {
26 self.write(data, WriteType::WithoutResponse).await
27 }
28
29 #[inline]
30 async fn write(&self, data: &[u8], write_type: WriteType) -> Result<()> {
31 self.peripheral
32 .write(&self.characteristic, data, write_type)
33 .await
34 }
35
36 pub async fn subscribe(&self) -> Result<Pin<Box<dyn Stream<Item = Vec<u8>> + Send>>> {
37 self.peripheral.subscribe(&self.characteristic).await?;
38
39 let stream = self.peripheral.notifications().await?;
40 let uuid = self.characteristic.uuid;
41
42 Ok(Box::pin(stream.filter_map(move |n| {
43 if n.uuid == uuid {
44 Some(n.value)
45 } else {
46 None
47 }
48 })))
49 }
50
51 #[inline]
52 pub async fn unsubscribe(&self) -> Result<()> {
53 self.peripheral.unsubscribe(&self.characteristic).await
54 }
55
56 pub fn uuid(&self) -> Uuid {
57 self.characteristic.uuid
58 }
59}