From 7335d35c68a5e3c431c599115a7916ac0d399dff Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 27 Jun 2026 00:13:40 +0200 Subject: [PATCH] store rf/mitemp names with device state --- src/device/mitemp.rs | 16 +++++---- src/device/mod.rs | 82 ++++++++++++++++++++++++++++++++------------ src/main.rs | 4 ++- 3 files changed, 72 insertions(+), 30 deletions(-) diff --git a/src/device/mitemp.rs b/src/device/mitemp.rs index 16daeed..673ecae 100644 --- a/src/device/mitemp.rs +++ b/src/device/mitemp.rs @@ -8,7 +8,9 @@ use std::{ }; #[derive(Debug)] -pub struct MiTempState { +pub struct MiTempDevice { + pub name: String, + pub addr: BDAddr, temperature: f32, humidity: f32, dew_point: f32, @@ -16,9 +18,11 @@ pub struct MiTempState { pub last_seen: Instant, } -impl Default for MiTempState { - fn default() -> Self { - MiTempState { +impl MiTempDevice { + pub fn new(addr: BDAddr, name: String) -> Self { + MiTempDevice { + name, + addr, temperature: 0.0, humidity: 0.0, dew_point: 0.0, @@ -26,9 +30,7 @@ impl Default for MiTempState { last_seen: Instant::now(), } } -} -impl MiTempState { pub fn update(&mut self, json: &JsonValue) { self.last_seen = Instant::now(); if let Some(temperature) = json["Temperature"].as_number().map(f32::from) { @@ -53,7 +55,7 @@ pub fn format_mi_temp_state( mut writer: W, addr: BDAddr, names: &BTreeMap, - state: &MiTempState, + state: &MiTempDevice, ) -> fmt::Result { // sensor_battery{name="Living Room", mac="58:2D:34:39:1D:5B"} 100 // sensor_temperature{name="Living Room", mac="58:2D:34:39:1D:5B"} 16.2 diff --git a/src/device/mod.rs b/src/device/mod.rs index 829de04..faab89d 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -1,6 +1,6 @@ mod mitemp; -pub use crate::device::mitemp::{MiTempState, format_mi_temp_state}; +pub use crate::device::mitemp::{MiTempDevice, format_mi_temp_state}; use color_eyre::{Report, Result, eyre::WrapErr}; use jzon::JsonValue; use rumqttc::{AsyncClient, QoS}; @@ -17,14 +17,28 @@ use tokio::task::spawn; #[derive(Default)] pub struct DeviceStates { + pub mi_temp_names: BTreeMap, + pub rf_temp_names: HashMap, + pub devices: HashMap, pub dsmr_devices: HashMap, - pub mi_temp_devices: BTreeMap, + pub mi_temp_devices: BTreeMap, pub rf_temp_devices: HashMap, active_rf_temp_id: RfDeviceId, } impl DeviceStates { + pub fn new( + mi_temp_names: BTreeMap, + rf_temp_names: HashMap, + ) -> Self { + DeviceStates { + mi_temp_names, + rf_temp_names, + ..Self::default() + } + } + pub fn devices(&self) -> impl Iterator { self.devices.iter() } @@ -41,8 +55,13 @@ impl DeviceStates { let addr = addr.trim_start_matches('-'); match BDAddr::from_mi_temp_mac_part(addr) { Ok(addr) => { - let state = self.mi_temp_devices.entry(addr).or_default(); - state.update(value); + if let Some(name) = self.mi_temp_names.get(&addr) { + let state = self + .mi_temp_devices + .entry(addr) + .or_insert_with(|| MiTempDevice::new(addr, name.clone())); + state.update(value); + } } Err(e) => eprintln!("Failed to parse mitemp mac: {:#}", e), } @@ -68,9 +87,15 @@ impl DeviceStates { pub fn update_rf(&mut self, payload: &str) { if let Some(data) = parse_rf_payload(payload) { - let state = self.rf_temp_devices.entry(data.device_id()).or_default(); - state.humidity = data.humidity; - state.temperature = data.temperature; + let id = data.device_id(); + if let Some(name) = self.rf_temp_names.get(&id) { + let state = self + .rf_temp_devices + .entry(data.device_id()) + .or_insert_with(|| TempState::new(name.clone())); + state.humidity = data.humidity; + state.temperature = data.temperature; + } } else { eprintln!("invalid rf payload: {payload}") } @@ -92,24 +117,26 @@ impl DeviceStates { } fn update_active_rtl(&mut self, field: &str, payload: &str) { - let state = self - .rf_temp_devices - .entry(self.active_rf_temp_id.clone()) - .or_default(); - match field { - "temperature_C" => state.temperature = payload.parse().unwrap_or_default(), - "temperature_F" => { - state.temperature = payload - .parse() - .map(|temp_f: f32| (temp_f - 32.0) * 5.0 / 9.0) - .unwrap_or_default() + if let Some(name) = self.rf_temp_names.get(&self.active_rf_temp_id) { + let state = self + .rf_temp_devices + .entry(self.active_rf_temp_id.clone()) + .or_insert_with(|| TempState::new(name.clone())); + match field { + "temperature_C" => state.temperature = payload.parse().unwrap_or_default(), + "temperature_F" => { + state.temperature = payload + .parse() + .map(|temp_f: f32| (temp_f - 32.0) * 5.0 / 9.0) + .unwrap_or_default() + } + "humidity" => state.humidity = payload.parse().unwrap_or_default(), + _ => {} } - "humidity" => state.humidity = payload.parse().unwrap_or_default(), - _ => {} } } - pub fn mi_temp(&self) -> impl Iterator { + pub fn mi_temp(&self) -> impl Iterator { self.mi_temp_devices.iter() } @@ -393,12 +420,23 @@ pub fn format_device_state( Ok(()) } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct TempState { + name: String, temperature: f32, humidity: u8, } +impl TempState { + pub fn new(name: String) -> Self { + TempState { + name, + temperature: 0.0, + humidity: 0, + } + } +} + pub fn format_rf_temp_state( mut writer: W, channel: &RfDeviceId, diff --git a/src/main.rs b/src/main.rs index 3e03473..9fdc359 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,7 +43,9 @@ async fn main() -> Result<()> { }; let mqtt_options = config.mqtt()?; - let device_states = >>::default(); + let device_states = + DeviceStates::new(config.names.mi_temp.clone(), config.names.rf_temp.clone()); + let device_states = Arc::new(Mutex::new(device_states)); ctrlc::set_handler(move || { std::process::exit(0);