1#![warn(clippy::all, future_incompatible, nonstandard_style, rust_2018_idioms)]
42
43mod characteristic;
44mod common;
45mod device;
46mod scanner;
47
48pub use self::{
49 characteristic::Characteristic,
50 common::*,
51 device::{Device, DeviceEvent},
52 scanner::{
53 config::{Filter, ScanConfig},
54 Scanner,
55 },
56};
57pub use btleplug::{
58 api::{BDAddr, PeripheralProperties},
59 Error, Result,
60};
61
62#[cfg(test)]
63mod tests {
64 use crate::{Filter, ScanConfig, Scanner};
65 use btleplug::{api::BDAddr, Error};
66 use std::time::Duration;
67 use tokio_stream::StreamExt;
68 use uuid::Uuid;
69
70 #[tokio::test]
71 async fn test_discover() -> anyhow::Result<()> {
72 rsutil::log::Log4rsConfig::default().initialize().unwrap();
73
74 let cfg = ScanConfig::default().stop_after_timeout(Duration::from_secs(10));
75
76 let mut scanner = Scanner::new();
77 scanner.start(cfg).await?;
78
79 while let Some(device) = scanner.device_stream()?.next().await {
80 println!("Found device: {}", device.address());
81 }
82
83 Ok(())
84 }
85
86 #[tokio::test]
87 async fn test_filter_by_address() -> Result<(), Error> {
88 rsutil::log::Log4rsConfig::default().initialize().unwrap();
89
90 let mac_addr = [0xE3, 0x9E, 0x2A, 0x4D, 0xAA, 0x97];
91 let filers = vec![Filter::Address("E3:9E:2A:4D:AA:97".into())];
92 let cfg = ScanConfig::default()
93 .with_filters(&filers)
94 .stop_after_timeout(Duration::from_secs(10))
95 .stop_after_first_match();
96 let mut scanner = Scanner::default();
97
98 scanner.start(cfg).await?;
99 while let Some(device) = scanner.device_stream()?.next().await {
100 assert_eq!(device.address(), BDAddr::from(mac_addr));
101 }
102
103 Ok(())
104 }
105
106 #[tokio::test]
107 async fn test_filter_by_character() -> Result<(), Error> {
108 rsutil::log::Log4rsConfig::default().initialize().unwrap();
109
110 let filers = vec![Filter::Characteristic(Uuid::from_u128(
111 0x6e400001_b5a3_f393_e0a9_e50e24dcca9e,
112 ))];
113 let cfg = ScanConfig::default()
114 .with_filters(&filers)
115 .stop_after_timeout(Duration::from_secs(10))
116 .stop_after_first_match();
117 let mut scanner = Scanner::default();
118
119 scanner.start(cfg).await?;
120 while let Some(device) = scanner.device_stream()?.next().await {
121 println!("device: {:?} found", device);
122 }
123
124 Ok(())
125 }
126
127 #[tokio::test]
128 async fn test_filter_by_name() -> Result<(), Error> {
129 rsutil::log::Log4rsConfig::default().initialize().unwrap();
130
131 let name = "73429485";
132 let filers = vec![Filter::Name(name.into())];
133 let cfg = ScanConfig::default()
134 .with_filters(&filers)
135 .stop_after_timeout(Duration::from_secs(10))
136 .stop_after_first_match();
137 let mut scanner = Scanner::default();
138
139 scanner.start(cfg).await?;
140 while let Some(device) = scanner.device_stream()?.next().await {
141 assert_eq!(device.local_name().await, Some(name.into()));
142 }
143
144 Ok(())
145 }
146
147 #[tokio::test]
148 async fn test_filter_by_rssi() -> Result<(), Error> {
149 rsutil::log::Log4rsConfig::default().initialize().unwrap();
150
151 let filers = vec![Filter::Rssi(-70)];
152 let cfg = ScanConfig::default()
153 .with_filters(&filers)
154 .stop_after_timeout(Duration::from_secs(10))
155 .stop_after_first_match();
156 let mut scanner = Scanner::default();
157
158 scanner.start(cfg).await?;
159 while let Some(device) = scanner.device_stream()?.next().await {
160 println!("device: {:?} found", device);
161 }
162
163 Ok(())
164 }
165
166 #[tokio::test]
167 async fn test_filter_by_service() -> Result<(), Error> {
168 rsutil::log::Log4rsConfig::default().initialize().unwrap();
169
170 let service = Uuid::from_u128(0x6e400001_b5a3_f393_e0a9_e50e24dcca9e);
171 let filers = vec![Filter::Service(service)];
172 let cfg = ScanConfig::default()
173 .with_filters(&filers)
174 .stop_after_timeout(Duration::from_secs(10))
175 .stop_after_first_match();
176 let mut scanner = Scanner::default();
177
178 scanner.start(cfg).await?;
179 while let Some(device) = scanner.device_stream()?.next().await {
180 println!("device: {:?} found", device);
181 }
182
183 Ok(())
184 }
185}