diff --git a/rust/src/log/mod.rs b/rust/src/log/mod.rs index 9d468bc..0b3384b 100644 --- a/rust/src/log/mod.rs +++ b/rust/src/log/mod.rs @@ -137,8 +137,16 @@ pub enum LogMessage { LowVoltage, #[strum(serialize = "Error communicating with battery!! ${txt_long}")] BatteryCommunicationError, - #[strum(serialize = "Tank sensor raw ${number_a} percent ${number_b}")] - SensorTankRaw, + #[strum(serialize = "Tank water level cricial! Refill tank!")] + TankWaterLevelLow, + #[strum(serialize = "Tank sensor hardware error: ${txt_long}")] + TankSensorBoardError, + #[strum(serialize = "Tank sensor not present, raw voltage measured = ${number_a} mV")] + TankSensorMissing, + #[strum( + serialize = "Tank sensor value out of range, min = ${number_a}%, max = ${number_b}%, value = ${text_short}%" + )] + TankSensorValueRangeError, #[strum( serialize = "raw measure unscaled ${number_a} hz ${number_b}, plant ${txt_short} sensor ${txt_long}" )] diff --git a/rust/src/main.rs b/rust/src/main.rs index cf04194..dd08ee5 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -17,7 +17,7 @@ use esp_idf_sys::{ esp_ota_img_states_t_ESP_OTA_IMG_VALID, vTaskDelay, }; use esp_ota::{mark_app_valid, rollback_and_reboot}; -use log::log; +use log::{log, LogMessage}; use once_cell::sync::Lazy; use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT}; use serde::{Deserialize, Serialize}; @@ -401,37 +401,41 @@ fn safe_main() -> anyhow::Result<()> { let dry_run = false; let tank_state = determine_tank_state(&mut board, &config); - if let Some(_err) = tank_state.got_error(&config.tank) { - //TODO log error state to serial - //log( - //LogMessage::SensorTankRaw, - //raw_value_mv as u32, - //percent as u32, - //"", - //"", - //); - } else if tank_state.warn_level(&config.tank).is_ok_and(|warn| warn) { - //TODO(judge) enable logging again, might require returning level as well - //println!( - //"Low water, current percent is {}, minimum warn level is {}", - //percent as u8, config.tank.tank_warn_percent - //); - board.general_fault(true); - } else if tank_state.enough_water(&config.tank).is_ok_and(|enough| enough) { - //TODO(judge) enable logging again, might require returning level as well - //println!( - //"Enough water, current percent is {}, minimum empty level is {}", - //percent as u8, config.tank.tank_empty_percent - //); - } else { - if let Ok(_left_ml) = tank_state.left_ml(&config.tank) { - //TODO(judge) enable logging again, might require returning level as well - //println!( - //"Tank sensor returned mv {} as {}% leaving {} ml useable", - //rv.raw, percent as u8, rv.left_ml - //); + + if tank_state.is_enabled() { + if let Some(err) = tank_state.got_error(&config.tank) { + match err { + TankError::SensorDisabled => { /* unreachable */ } + TankError::SensorMissing(raw_value_mv) => log( + LogMessage::TankSensorMissing, + raw_value_mv as u32, + 0, + "", + "", + ), + TankError::SensorValueError { value, min, max } => log( + LogMessage::TankSensorValueRangeError, + min as u32, + max as u32, + &format!("{}", value), + "", + ), + TankError::BoardError(err) => log( + LogMessage::TankSensorBoardError, + 0, + 0, + "", + &format!("{}", &err.to_string()), + ), + } + // disabled can not trigger this because of wrapping if is_enabled + board.general_fault(true); + } else if tank_state.warn_level(&config.tank).is_ok_and(|warn| warn) { + log(LogMessage::TankWaterLevelLow, 0, 0, "", ""); + board.general_fault(true); } } + let mut water_frozen = false; let mut attempt = 1; @@ -440,14 +444,14 @@ fn safe_main() -> anyhow::Result<()> { match &temp { Ok(res) => { println!("Water temp is {}", res); - break temp + break temp; } Err(err) => { println!("Could not get water temp {} attempt {}", err, attempt) } } if attempt == 5 { - break temp + break temp; } attempt += 1; }; @@ -682,14 +686,12 @@ fn determine_state_target_moisture_for_plant( match tank_state.enough_water(&config.tank) { Err(_tank_err) => { if !config.tank.tank_allow_pumping_if_sensor_error { - // ignore is ok - // wtf does this meen, shouldn't something happen if the configuration specifies - // that no water should flow if there was an error? + state.no_water = true; } - }, - Ok(enough_water) => { - state.no_water = !enough_water - }, + } + // when no tank error, if plant should be watered depends on if enough water is in tank + // no_water behaves inversly to enough_water + Ok(enough_water) => state.no_water = !enough_water, } } let duration = TimeDelta::try_minutes(plant_config.pump_cooldown_min as i64).unwrap(); @@ -750,10 +752,10 @@ fn determine_state_timer_only_for_plant( if !config.tank.tank_allow_pumping_if_sensor_error { state.do_water = true; } - }, + } Ok(enough_water) => { state.no_water = !enough_water; - }, + } } } } @@ -801,10 +803,10 @@ fn determine_state_timer_and_deadzone_for_plant( if !config.tank.tank_allow_pumping_if_sensor_error { state.do_water = true; } - }, + } Ok(enough_water) => { state.no_water = !enough_water; - }, + } } } } diff --git a/rust/src/tank.rs b/rust/src/tank.rs index eb531a0..f0a1de8 100644 --- a/rust/src/tank.rs +++ b/rust/src/tank.rs @@ -1,6 +1,9 @@ use serde::Serialize; -use crate::{config::{PlantControllerConfig, TankConfig}, plant_hal::PlantCtrlBoard}; +use crate::{ + config::{PlantControllerConfig, TankConfig}, + plant_hal::PlantCtrlBoard, +}; const OPEN_TANK_VOLTAGE: f32 = 3.0; pub const WATER_FROZEN_THRESH: f32 = 4.0; @@ -10,7 +13,7 @@ pub enum TankError { SensorDisabled, SensorMissing(f32), SensorValueError { value: f32, min: f32, max: f32 }, - BoardError(String) + BoardError(String), } pub enum TankState { @@ -35,18 +38,21 @@ fn raw_voltage_to_tank_fill_percent( config: &TankConfig, ) -> Result { let divider_percent = raw_volatge_to_divider_percent(raw_value_mv)?; - if divider_percent < config.tank_empty_percent.into() || divider_percent > config.tank_full_percent.into() { + if divider_percent < config.tank_empty_percent.into() + || divider_percent > config.tank_full_percent.into() + { return Err(TankError::SensorValueError { value: divider_percent, min: config.tank_empty_percent.into(), max: config.tank_full_percent.into(), }); } - Ok((divider_percent - f32::from(config.tank_empty_percent)) * 100. - / f32::from(config.tank_full_percent - config.tank_empty_percent)) + Ok( + (divider_percent - f32::from(config.tank_empty_percent)) * 100. + / f32::from(config.tank_full_percent - config.tank_empty_percent), + ) } - impl TankState { pub fn left_ml(&self, config: &TankConfig) -> Result { match self { @@ -69,10 +75,14 @@ impl TankState { } else { Ok(false) } - }, + } } } + pub fn is_enabled(&self) -> bool { + matches!(self, TankState::TankSensorDisabled) + } + pub fn warn_level(&self, config: &TankConfig) -> Result { match self { TankState::TankSensorDisabled => Err(TankError::SensorDisabled), @@ -84,29 +94,37 @@ impl TankState { } else { Ok(false) } - }, + } } } 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::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 { + 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 }, + 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::TankSensorDisabled | TankState::TankSensorError(_) => None, TankState::TankSensorPresent(raw_value_mv) => Some(*raw_value_mv), }; @@ -116,9 +134,11 @@ impl TankState { left_ml, sensor_error: tank_err, raw, - water_frozen: water_temp.as_ref().is_ok_and(|temp| *temp < WATER_FROZEN_THRESH), + 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()) + temp_sensor_error: water_temp.err().map(|err| err.to_string()), } } } @@ -130,9 +150,8 @@ pub fn determine_tank_state( if config.tank.tank_sensor_enabled { 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())) + Err(err) => TankState::TankSensorError(TankError::BoardError(err.to_string())), } - } else { TankState::TankSensorDisabled }