mirror of
https://codeberg.org/icewind/mitemp-rs.git
synced 2026-06-03 09:14:07 +02:00
get bdaddr from service data
This commit is contained in:
parent
4c4b2e0093
commit
68b7c2ddcc
1 changed files with 34 additions and 46 deletions
80
src/lib.rs
80
src/lib.rs
|
|
@ -1,12 +1,9 @@
|
|||
pub use btleplug::api::BDAddr;
|
||||
use btleplug::api::{Central, CentralEvent, Peripheral, ScanFilter};
|
||||
use btleplug::platform::PeripheralId;
|
||||
use futures_util::{future::ready, StreamExt};
|
||||
use btleplug::api::{Central, CentralEvent, ScanFilter};
|
||||
use num_enum::TryFromPrimitive;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use tokio_stream::Stream;
|
||||
use tokio_stream::{Stream, StreamExt};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Detected mitemp sensor and the data read from it
|
||||
|
|
@ -55,29 +52,12 @@ pub async fn listen<'a, A: Central + 'static>(
|
|||
adapter.start_scan(ScanFilter::default()).await?;
|
||||
|
||||
Ok(event_receiver
|
||||
.filter_map(|event| {
|
||||
ready(match event {
|
||||
CentralEvent::ServiceDataAdvertisement { id, service_data } => {
|
||||
Some((id, service_data))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
.filter_map(move |(id, service_data)| async move {
|
||||
let addr = id_to_addr(adapter, id).await?;
|
||||
Some((addr, service_data))
|
||||
})
|
||||
.filter_map(
|
||||
|(bd_addr, mut service_data): (BDAddr, HashMap<Uuid, Vec<u8>>)| {
|
||||
ready(service_data.remove(&UUID).map(move |data| (bd_addr, data)))
|
||||
},
|
||||
)
|
||||
.filter_map(|(bd_addr, data)| {
|
||||
ready(match parse_advertising_data(&data) {
|
||||
Ok(update) => Some((bd_addr, update)),
|
||||
_ => None,
|
||||
})
|
||||
.filter_map(|event| match event {
|
||||
CentralEvent::ServiceDataAdvertisement { service_data, .. } => Some(service_data),
|
||||
_ => None,
|
||||
})
|
||||
.filter_map(|mut service_data| service_data.remove(&UUID))
|
||||
.filter_map(|data| parse_advertising_data(&data).ok())
|
||||
.map(move |(bd_addr, update)| {
|
||||
let sensor_data = sensors.entry(bd_addr).or_default();
|
||||
sensor_data.update(update);
|
||||
|
|
@ -88,11 +68,6 @@ pub async fn listen<'a, A: Central + 'static>(
|
|||
}))
|
||||
}
|
||||
|
||||
async fn id_to_addr<A: Central + 'static>(adapter: &A, id: PeripheralId) -> Option<BDAddr> {
|
||||
let peripheral = adapter.peripheral(&id).await.ok()?;
|
||||
Some(peripheral.address())
|
||||
}
|
||||
|
||||
/// Collected data from a sensor
|
||||
///
|
||||
/// Because not all data is emitted at the same time, some fields might not be populated yet
|
||||
|
|
@ -136,11 +111,21 @@ enum SensorUpdate {
|
|||
|
||||
struct InvalidServiceData;
|
||||
|
||||
fn parse_advertising_data(service_data: &[u8]) -> Result<SensorUpdate, InvalidServiceData> {
|
||||
fn parse_advertising_data(
|
||||
service_data: &[u8],
|
||||
) -> Result<(BDAddr, SensorUpdate), InvalidServiceData> {
|
||||
let sensor_type = &service_data[1..4];
|
||||
if sensor_type != [0x20, 0xaa, 0x01] {
|
||||
return Err(InvalidServiceData);
|
||||
}
|
||||
let addr = BDAddr::from([
|
||||
service_data[10],
|
||||
service_data[9],
|
||||
service_data[8],
|
||||
service_data[7],
|
||||
service_data[6],
|
||||
service_data[5],
|
||||
]);
|
||||
let sensor_type = SensorType::try_from(service_data[11]).map_err(|_| InvalidServiceData)?;
|
||||
let data_length = service_data[13] as usize;
|
||||
|
||||
|
|
@ -149,17 +134,20 @@ fn parse_advertising_data(service_data: &[u8]) -> Result<SensorUpdate, InvalidSe
|
|||
}
|
||||
|
||||
let sensor_data = &service_data[14..14 + data_length];
|
||||
Ok(match sensor_type {
|
||||
SensorType::Battery => SensorUpdate::Battery(sensor_data[0]),
|
||||
SensorType::Temperature => {
|
||||
SensorUpdate::Temperature(i16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
||||
}
|
||||
SensorType::Humidity => {
|
||||
SensorUpdate::Humidity(u16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
||||
}
|
||||
SensorType::TemperatureAndHumidity => SensorUpdate::TemperatureAndHumidity(
|
||||
i16::from_le_bytes([sensor_data[0], sensor_data[1]]),
|
||||
u16::from_le_bytes([sensor_data[2], sensor_data[3]]),
|
||||
),
|
||||
})
|
||||
Ok((
|
||||
addr,
|
||||
match sensor_type {
|
||||
SensorType::Battery => SensorUpdate::Battery(sensor_data[0]),
|
||||
SensorType::Temperature => {
|
||||
SensorUpdate::Temperature(i16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
||||
}
|
||||
SensorType::Humidity => {
|
||||
SensorUpdate::Humidity(u16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
||||
}
|
||||
SensorType::TemperatureAndHumidity => SensorUpdate::TemperatureAndHumidity(
|
||||
i16::from_le_bytes([sensor_data[0], sensor_data[1]]),
|
||||
u16::from_le_bytes([sensor_data[2], sensor_data[3]]),
|
||||
),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue