mirror of
https://codeberg.org/icewind/mitemp-rs.git
synced 2026-06-03 17:24:08 +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;
|
pub use btleplug::api::BDAddr;
|
||||||
use btleplug::api::{Central, CentralEvent, Peripheral, ScanFilter};
|
use btleplug::api::{Central, CentralEvent, ScanFilter};
|
||||||
use btleplug::platform::PeripheralId;
|
|
||||||
use futures_util::{future::ready, StreamExt};
|
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use tokio_stream::{Stream, StreamExt};
|
||||||
use tokio_stream::Stream;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
/// Detected mitemp sensor and the data read from it
|
/// 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?;
|
adapter.start_scan(ScanFilter::default()).await?;
|
||||||
|
|
||||||
Ok(event_receiver
|
Ok(event_receiver
|
||||||
.filter_map(|event| {
|
.filter_map(|event| match event {
|
||||||
ready(match event {
|
CentralEvent::ServiceDataAdvertisement { service_data, .. } => Some(service_data),
|
||||||
CentralEvent::ServiceDataAdvertisement { id, service_data } => {
|
_ => None,
|
||||||
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(|mut service_data| service_data.remove(&UUID))
|
||||||
|
.filter_map(|data| parse_advertising_data(&data).ok())
|
||||||
.map(move |(bd_addr, update)| {
|
.map(move |(bd_addr, update)| {
|
||||||
let sensor_data = sensors.entry(bd_addr).or_default();
|
let sensor_data = sensors.entry(bd_addr).or_default();
|
||||||
sensor_data.update(update);
|
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
|
/// Collected data from a sensor
|
||||||
///
|
///
|
||||||
/// Because not all data is emitted at the same time, some fields might not be populated yet
|
/// 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;
|
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];
|
let sensor_type = &service_data[1..4];
|
||||||
if sensor_type != [0x20, 0xaa, 0x01] {
|
if sensor_type != [0x20, 0xaa, 0x01] {
|
||||||
return Err(InvalidServiceData);
|
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 sensor_type = SensorType::try_from(service_data[11]).map_err(|_| InvalidServiceData)?;
|
||||||
let data_length = service_data[13] as usize;
|
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];
|
let sensor_data = &service_data[14..14 + data_length];
|
||||||
Ok(match sensor_type {
|
Ok((
|
||||||
SensorType::Battery => SensorUpdate::Battery(sensor_data[0]),
|
addr,
|
||||||
SensorType::Temperature => {
|
match sensor_type {
|
||||||
SensorUpdate::Temperature(i16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
SensorType::Battery => SensorUpdate::Battery(sensor_data[0]),
|
||||||
}
|
SensorType::Temperature => {
|
||||||
SensorType::Humidity => {
|
SensorUpdate::Temperature(i16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
||||||
SensorUpdate::Humidity(u16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
}
|
||||||
}
|
SensorType::Humidity => {
|
||||||
SensorType::TemperatureAndHumidity => SensorUpdate::TemperatureAndHumidity(
|
SensorUpdate::Humidity(u16::from_le_bytes([sensor_data[0], sensor_data[1]]))
|
||||||
i16::from_le_bytes([sensor_data[0], sensor_data[1]]),
|
}
|
||||||
u16::from_le_bytes([sensor_data[2], sensor_data[3]]),
|
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