diff --git a/rust/src/main.rs b/rust/src/main.rs index db1e76f..3f4902c 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -401,41 +401,32 @@ fn safe_main() -> anyhow::Result<()> { let dry_run = false; let tank_state = determine_tank_state(&mut board, &config); - let mut tank_state_mqtt = TankStateMQTT { - enough_water: tank_state.enough_water, - left_ml: tank_state.left_ml, - warn_level: tank_state.warn_level, - sensor_error: tank_state.sensor_error, - raw: tank_state.raw, - water_frozen: "".to_owned(), - }; let mut water_frozen = false; - let mut temp: Option = None; - for _attempt in 0..5 { - let water_temperature = board.water_temperature_c(); - match water_temperature { + let mut attempt = 1; + let water_temp: Result = loop { + let temp = board.water_temperature_c(); + match &temp { Ok(res) => { - temp = Some(res); - break; + println!("Water temp is {}", res); + break temp } Err(err) => { - println!("Could not get water temp {} attempt {}", err, _attempt) + println!("Could not get water temp {} attempt {}", err, attempt) } } - } - match temp { - Some(res) => { - println!("Water temp is {}", res); - if res < 4_f32 { - water_frozen = true; - } - tank_state_mqtt.water_frozen = water_frozen.to_string(); + if attempt == 5 { + break temp + } + attempt += 1; + }; + if let Ok(res) = water_temp { + if res < WATER_FROZEN_THRESH { + water_frozen = true; } - None => tank_state_mqtt.water_frozen = "tank sensor error".to_owned(), } - match serde_json::to_string(&tank_state_mqtt) { + match serde_json::to_string(&tank_state.as_mqtt_info(&config.tank, water_temp)) { Ok(state) => { let _ = board.mqtt_publish(&config, "/water", state.as_bytes()); } diff --git a/rust/src/tank.rs b/rust/src/tank.rs index 3a7e223..29b9041 100644 --- a/rust/src/tank.rs +++ b/rust/src/tank.rs @@ -1,34 +1,21 @@ -use crate::{config::{self, PlantControllerConfig, TankConfig}, plant_hal::PlantCtrlBoard}; +use serde::Serialize; + +use crate::{config::{PlantControllerConfig, TankConfig}, plant_hal::PlantCtrlBoard}; const OPEN_TANK_VOLTAGE: f32 = 3.0; +pub const WATER_FROZEN_THRESH: f32 = 4.0; -#[derive(Debug, PartialEq, Default)] -/// State data for water tank -/// -/// TODO unify with TankStateMQTT -pub struct TankInfo { - /// is there enough water in the tank - enough_water: bool, - /// warning that water needs to be refilled soon - warn_level: bool, - /// estimation how many ml are still in tank - left_ml: u32, - /// if there is was an issue with the water level sensor - /// TODO merge with left_ml as Result - sensor_error: bool, - /// raw water sensor value - raw: u16, -} - +#[derive(Debug, Clone, Serialize)] pub enum TankError { SensorDisabled, SensorMissing(f32), SensorValueError { value: f32, min: f32, max: f32 }, - BoardError(anyhow::Error) + BoardError(String) } pub enum TankState { TankSensorPresent(f32), + TankSensorError(TankError), TankSensorDisabled, } @@ -72,6 +59,7 @@ impl TankState { pub fn left_ml(&self, config: &TankConfig) -> Result { match self { TankState::TankSensorDisabled => Err(TankError::SensorDisabled), + TankState::TankSensorError(err) => Err(err.clone()), TankState::TankSensorPresent(raw_value_mv) => { let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?; //TODO(judge) move logging to more sensible place @@ -86,6 +74,7 @@ impl TankState { pub fn enough_water(&self, config: &TankConfig) -> Result { match self { TankState::TankSensorDisabled => Err(TankError::SensorDisabled), + TankState::TankSensorError(err) => Err(err.clone()), TankState::TankSensorPresent(raw_value_mv) => { let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?; if tank_fill_percent > config.tank_empty_percent.into() { @@ -105,6 +94,7 @@ impl TankState { pub fn warn_level(&self, config: &TankConfig) -> Result { match self { TankState::TankSensorDisabled => Err(TankError::SensorDisabled), + TankState::TankSensorError(err) => Err(err.clone()), TankState::TankSensorPresent(raw_value_mv) => { let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?; if tank_fill_percent < config.tank_warn_percent.into() { @@ -126,30 +116,69 @@ impl TankState { pub fn got_error(&self, config: &TankConfig) -> Option { match self { TankState::TankSensorPresent(raw_value_mv) => raw_voltage_to_tank_fill_percent(*raw_value_mv, config).err(), + TankState::TankSensorError(err) => Some(err.clone()), TankState::TankSensorDisabled => Some(TankError::SensorDisabled), } } -} + pub fn as_mqtt_info(&self, config: &TankConfig, water_temp: Result) -> TankInfo { + let mut tank_err: Option = None; + let left_ml = match self.left_ml(config) { + Err(err) => { tank_err = Some(err); None }, + Ok(left_ml) => Some(left_ml), + }; + let enough_water = self.enough_water(config).unwrap_or(false); //NOTE: is this correct if there is an error assume not enough water? + let warn_level = self.warn_level(config).unwrap_or(false); //NOTE: should no warn level be triggered if there is an error? + let raw = match self { + TankState::TankSensorDisabled + | TankState::TankSensorError(_) => None, + TankState::TankSensorPresent(raw_value_mv) => Some(*raw_value_mv), + }; -#[derive(serde::Serialize)] -pub struct TankStateMQTT { - enough_water: bool, - warn_level: bool, - left_ml: u32, - sensor_error: bool, - raw: u16, - water_frozen: String, + TankInfo { + enough_water, + warn_level, + left_ml, + sensor_error: tank_err, + raw, + water_frozen: water_temp.as_ref().is_ok_and(|temp| *temp < WATER_FROZEN_THRESH), + water_temp: water_temp.as_ref().copied().ok(), + temp_sensor_error: water_temp.err().map(|err| err.to_string()) + } + } } pub fn determine_tank_state( board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>, config: &PlantControllerConfig, -) -> Result { +) -> TankState { if config.tank.tank_sensor_enabled { - let raw_sensor_value_mv = board.tank_sensor_voltage().map_err(|err| TankError::BoardError(err))?; - Ok(TankState::TankSensorPresent(raw_sensor_value_mv)) + match board.tank_sensor_voltage() { + Ok(raw_sensor_value_mv) => TankState::TankSensorPresent(raw_sensor_value_mv), + Err(err) => TankState::TankSensorError(TankError::BoardError(err.to_string())) + } + } else { - Ok(TankState::TankSensorDisabled) + TankState::TankSensorDisabled } } + +#[derive(Debug, Serialize)] +/// Information structure send to mqtt for monitoring purposes +pub struct TankInfo { + /// is there enough water in the tank + enough_water: bool, + /// warning that water needs to be refilled soon + warn_level: bool, + /// estimation how many ml are still in tank + left_ml: Option, + /// if there is was an issue with the water level sensor + sensor_error: Option, + /// raw water sensor value + raw: Option, + /// water in tank might be frozen + water_frozen: bool, + /// water temperature + water_temp: Option, + temp_sensor_error: Option, +}