store rf/mitemp names with device state

This commit is contained in:
Robin Appelman 2026-06-27 00:13:40 +02:00
commit 7335d35c68
3 changed files with 72 additions and 30 deletions

View file

@ -8,7 +8,9 @@ use std::{
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct MiTempState { pub struct MiTempDevice {
pub name: String,
pub addr: BDAddr,
temperature: f32, temperature: f32,
humidity: f32, humidity: f32,
dew_point: f32, dew_point: f32,
@ -16,9 +18,11 @@ pub struct MiTempState {
pub last_seen: Instant, pub last_seen: Instant,
} }
impl Default for MiTempState { impl MiTempDevice {
fn default() -> Self { pub fn new(addr: BDAddr, name: String) -> Self {
MiTempState { MiTempDevice {
name,
addr,
temperature: 0.0, temperature: 0.0,
humidity: 0.0, humidity: 0.0,
dew_point: 0.0, dew_point: 0.0,
@ -26,9 +30,7 @@ impl Default for MiTempState {
last_seen: Instant::now(), last_seen: Instant::now(),
} }
} }
}
impl MiTempState {
pub fn update(&mut self, json: &JsonValue) { pub fn update(&mut self, json: &JsonValue) {
self.last_seen = Instant::now(); self.last_seen = Instant::now();
if let Some(temperature) = json["Temperature"].as_number().map(f32::from) { if let Some(temperature) = json["Temperature"].as_number().map(f32::from) {
@ -53,7 +55,7 @@ pub fn format_mi_temp_state<W: Write>(
mut writer: W, mut writer: W,
addr: BDAddr, addr: BDAddr,
names: &BTreeMap<BDAddr, String>, names: &BTreeMap<BDAddr, String>,
state: &MiTempState, state: &MiTempDevice,
) -> fmt::Result { ) -> fmt::Result {
// sensor_battery{name="Living Room", mac="58:2D:34:39:1D:5B"} 100 // 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 // sensor_temperature{name="Living Room", mac="58:2D:34:39:1D:5B"} 16.2

View file

@ -1,6 +1,6 @@
mod mitemp; 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 color_eyre::{Report, Result, eyre::WrapErr};
use jzon::JsonValue; use jzon::JsonValue;
use rumqttc::{AsyncClient, QoS}; use rumqttc::{AsyncClient, QoS};
@ -17,14 +17,28 @@ use tokio::task::spawn;
#[derive(Default)] #[derive(Default)]
pub struct DeviceStates { pub struct DeviceStates {
pub mi_temp_names: BTreeMap<BDAddr, String>,
pub rf_temp_names: HashMap<RfDeviceId, String>,
pub devices: HashMap<Device, DeviceState>, pub devices: HashMap<Device, DeviceState>,
pub dsmr_devices: HashMap<Device, DsmrState>, pub dsmr_devices: HashMap<Device, DsmrState>,
pub mi_temp_devices: BTreeMap<BDAddr, MiTempState>, pub mi_temp_devices: BTreeMap<BDAddr, MiTempDevice>,
pub rf_temp_devices: HashMap<RfDeviceId, TempState>, pub rf_temp_devices: HashMap<RfDeviceId, TempState>,
active_rf_temp_id: RfDeviceId, active_rf_temp_id: RfDeviceId,
} }
impl DeviceStates { impl DeviceStates {
pub fn new(
mi_temp_names: BTreeMap<BDAddr, String>,
rf_temp_names: HashMap<RfDeviceId, String>,
) -> Self {
DeviceStates {
mi_temp_names,
rf_temp_names,
..Self::default()
}
}
pub fn devices(&self) -> impl Iterator<Item = (&Device, &DeviceState)> { pub fn devices(&self) -> impl Iterator<Item = (&Device, &DeviceState)> {
self.devices.iter() self.devices.iter()
} }
@ -41,9 +55,14 @@ impl DeviceStates {
let addr = addr.trim_start_matches('-'); let addr = addr.trim_start_matches('-');
match BDAddr::from_mi_temp_mac_part(addr) { match BDAddr::from_mi_temp_mac_part(addr) {
Ok(addr) => { Ok(addr) => {
let state = self.mi_temp_devices.entry(addr).or_default(); 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); state.update(value);
} }
}
Err(e) => eprintln!("Failed to parse mitemp mac: {:#}", e), Err(e) => eprintln!("Failed to parse mitemp mac: {:#}", e),
} }
} }
@ -68,9 +87,15 @@ impl DeviceStates {
pub fn update_rf(&mut self, payload: &str) { pub fn update_rf(&mut self, payload: &str) {
if let Some(data) = parse_rf_payload(payload) { if let Some(data) = parse_rf_payload(payload) {
let state = self.rf_temp_devices.entry(data.device_id()).or_default(); 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.humidity = data.humidity;
state.temperature = data.temperature; state.temperature = data.temperature;
}
} else { } else {
eprintln!("invalid rf payload: {payload}") eprintln!("invalid rf payload: {payload}")
} }
@ -92,10 +117,11 @@ impl DeviceStates {
} }
fn update_active_rtl(&mut self, field: &str, payload: &str) { fn update_active_rtl(&mut self, field: &str, payload: &str) {
if let Some(name) = self.rf_temp_names.get(&self.active_rf_temp_id) {
let state = self let state = self
.rf_temp_devices .rf_temp_devices
.entry(self.active_rf_temp_id.clone()) .entry(self.active_rf_temp_id.clone())
.or_default(); .or_insert_with(|| TempState::new(name.clone()));
match field { match field {
"temperature_C" => state.temperature = payload.parse().unwrap_or_default(), "temperature_C" => state.temperature = payload.parse().unwrap_or_default(),
"temperature_F" => { "temperature_F" => {
@ -108,8 +134,9 @@ impl DeviceStates {
_ => {} _ => {}
} }
} }
}
pub fn mi_temp(&self) -> impl Iterator<Item = (&BDAddr, &MiTempState)> { pub fn mi_temp(&self) -> impl Iterator<Item = (&BDAddr, &MiTempDevice)> {
self.mi_temp_devices.iter() self.mi_temp_devices.iter()
} }
@ -393,12 +420,23 @@ pub fn format_device_state<W: Write>(
Ok(()) Ok(())
} }
#[derive(Debug, Default)] #[derive(Debug)]
pub struct TempState { pub struct TempState {
name: String,
temperature: f32, temperature: f32,
humidity: u8, humidity: u8,
} }
impl TempState {
pub fn new(name: String) -> Self {
TempState {
name,
temperature: 0.0,
humidity: 0,
}
}
}
pub fn format_rf_temp_state<W: Write>( pub fn format_rf_temp_state<W: Write>(
mut writer: W, mut writer: W,
channel: &RfDeviceId, channel: &RfDeviceId,

View file

@ -43,7 +43,9 @@ async fn main() -> Result<()> {
}; };
let mqtt_options = config.mqtt()?; let mqtt_options = config.mqtt()?;
let device_states = <Arc<Mutex<DeviceStates>>>::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 || { ctrlc::set_handler(move || {
std::process::exit(0); std::process::exit(0);