use crate::config::TankConfig; const OPEN_TANK_VOLTAGE: f32 = 3.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, } pub enum TankError { SensorDisabled, SensorMissing(f32), SensorValueError { value: f32, min: f32, max: f32 }, } pub enum TankState { TankSensorPresent(u16), TankSensorDisabled, } fn raw_volatge_to_divider_percent(raw_value_mv: u16) -> Result { if raw_value_mv > OPEN_TANK_VOLTAGE { return Err(TankError::SensorMissing(raw_value_mv)); } let r2 = raw_value_mv * 50.0 / (3.3 - raw_value_mv); let mut percent = r2 / 190_f32 * 100_f32; percent = percent.clamp(0.0, 100.0); // TODO(judge) move this to a sensible place //log( //LogMessage::SensorTankRaw, //raw_value_mv as u32, //percent as u32, //"", //"", //); Ok(percent) } fn raw_voltage_to_tank_fill_percent( raw_value_mv: u16, config: &TankConfig, ) -> Result { let divider_percent = raw_volatge_to_divider_percent(raw_value_mv)?; if s < config.tank_empty_percent || s > config.tank_full_percent { return Err(TankError::SensorValueError { value: divider_percent, min: config.tank_empty_percent, max: config.tank_full_percent, }); } Ok((divider_percent - config.tank_empty_percent) * 100 / (config.tank_full_percent - config.tank_empty_percent)) } impl TankState { pub fn left_ml(&self, config: &TankConfig) -> Result { match self { TankState::TankSensorDisabled => Err(TankError::SensorMissing), TankState::TankSensorPresent(raw_value_mv) => { let tank_fill_percent = raw_voltage_to_tank_fill_percent(raw_value_mv, config); todo!() } } } } #[derive(Serialize)] pub struct TankStateMQTT { enough_water: bool, warn_level: bool, left_ml: u32, sensor_error: bool, raw: u16, water_frozen: String, } pub fn determine_tank_state( board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>, config: &PlantControllerConfig, ) -> TankInfo { if config.tank.tank_sensor_enabled { let mut rv: TankInfo = TankInfo { ..Default::default() }; let success = board .tank_sensor_percent() .and_then(|raw| { rv.raw = raw; return map_range( ( config.tank.tank_empty_percent as f32, config.tank.tank_full_percent as f32, ), raw as f32, ); }) .and_then(|percent| { rv.left_ml = ((percent * config.tank.tank_useable_ml as f32) / 100_f32) as u32; println!( "Tank sensor returned mv {} as {}% leaving {} ml useable", rv.raw, percent as u8, rv.left_ml ); if config.tank.tank_warn_percent > percent as u8 { board.general_fault(true); println!( "Low water, current percent is {}, minimum warn level is {}", percent as u8, config.tank.tank_warn_percent ); rv.warn_level = true; } if config.tank.tank_empty_percent < percent as u8 { println!( "Enough water, current percent is {}, minimum empty level is {}", percent as u8, config.tank.tank_empty_percent ); rv.enough_water = true; } return Ok(()); }); match success { Err(err) => { println!("Could not determine tank value due to {}", err); board.general_fault(true); rv.sensor_error = true; } Ok(_) => {} } return rv; } return TankInfo { warn_level: false, enough_water: true, left_ml: 1337, sensor_error: false, raw: 0, }; }