1
0
Fork 0
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:
Robin Appelman 2021-10-31 18:22:04 +01:00
commit 68b7c2ddcc

View file

@ -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]]),
),
},
))
}