finalize tank state logging
This commit is contained in:
parent
fbf1a84e7d
commit
038f74bca1
@ -137,8 +137,16 @@ pub enum LogMessage {
|
|||||||
LowVoltage,
|
LowVoltage,
|
||||||
#[strum(serialize = "Error communicating with battery!! ${txt_long}")]
|
#[strum(serialize = "Error communicating with battery!! ${txt_long}")]
|
||||||
BatteryCommunicationError,
|
BatteryCommunicationError,
|
||||||
#[strum(serialize = "Tank sensor raw ${number_a} percent ${number_b}")]
|
#[strum(serialize = "Tank water level cricial! Refill tank!")]
|
||||||
SensorTankRaw,
|
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(
|
#[strum(
|
||||||
serialize = "raw measure unscaled ${number_a} hz ${number_b}, plant ${txt_short} sensor ${txt_long}"
|
serialize = "raw measure unscaled ${number_a} hz ${number_b}, plant ${txt_short} sensor ${txt_long}"
|
||||||
)]
|
)]
|
||||||
|
@ -17,7 +17,7 @@ use esp_idf_sys::{
|
|||||||
esp_ota_img_states_t_ESP_OTA_IMG_VALID, vTaskDelay,
|
esp_ota_img_states_t_ESP_OTA_IMG_VALID, vTaskDelay,
|
||||||
};
|
};
|
||||||
use esp_ota::{mark_app_valid, rollback_and_reboot};
|
use esp_ota::{mark_app_valid, rollback_and_reboot};
|
||||||
use log::log;
|
use log::{log, LogMessage};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
|
use plant_hal::{PlantCtrlBoard, PlantHal, PLANT_COUNT};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -401,37 +401,41 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
let dry_run = false;
|
let dry_run = false;
|
||||||
|
|
||||||
let tank_state = determine_tank_state(&mut board, &config);
|
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
|
if tank_state.is_enabled() {
|
||||||
//log(
|
if let Some(err) = tank_state.got_error(&config.tank) {
|
||||||
//LogMessage::SensorTankRaw,
|
match err {
|
||||||
//raw_value_mv as u32,
|
TankError::SensorDisabled => { /* unreachable */ }
|
||||||
//percent as u32,
|
TankError::SensorMissing(raw_value_mv) => log(
|
||||||
//"",
|
LogMessage::TankSensorMissing,
|
||||||
//"",
|
raw_value_mv as u32,
|
||||||
//);
|
0,
|
||||||
} 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 {}",
|
TankError::SensorValueError { value, min, max } => log(
|
||||||
//percent as u8, config.tank.tank_warn_percent
|
LogMessage::TankSensorValueRangeError,
|
||||||
//);
|
min as u32,
|
||||||
board.general_fault(true);
|
max as u32,
|
||||||
} else if tank_state.enough_water(&config.tank).is_ok_and(|enough| enough) {
|
&format!("{}", value),
|
||||||
//TODO(judge) enable logging again, might require returning level as well
|
"",
|
||||||
//println!(
|
),
|
||||||
//"Enough water, current percent is {}, minimum empty level is {}",
|
TankError::BoardError(err) => log(
|
||||||
//percent as u8, config.tank.tank_empty_percent
|
LogMessage::TankSensorBoardError,
|
||||||
//);
|
0,
|
||||||
} else {
|
0,
|
||||||
if let Ok(_left_ml) = tank_state.left_ml(&config.tank) {
|
"",
|
||||||
//TODO(judge) enable logging again, might require returning level as well
|
&format!("{}", &err.to_string()),
|
||||||
//println!(
|
),
|
||||||
//"Tank sensor returned mv {} as {}% leaving {} ml useable",
|
}
|
||||||
//rv.raw, percent as u8, rv.left_ml
|
// 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 water_frozen = false;
|
||||||
|
|
||||||
let mut attempt = 1;
|
let mut attempt = 1;
|
||||||
@ -440,14 +444,14 @@ fn safe_main() -> anyhow::Result<()> {
|
|||||||
match &temp {
|
match &temp {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
println!("Water temp is {}", res);
|
println!("Water temp is {}", res);
|
||||||
break temp
|
break temp;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Could not get water temp {} attempt {}", err, attempt)
|
println!("Could not get water temp {} attempt {}", err, attempt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if attempt == 5 {
|
if attempt == 5 {
|
||||||
break temp
|
break temp;
|
||||||
}
|
}
|
||||||
attempt += 1;
|
attempt += 1;
|
||||||
};
|
};
|
||||||
@ -682,14 +686,12 @@ fn determine_state_target_moisture_for_plant(
|
|||||||
match tank_state.enough_water(&config.tank) {
|
match tank_state.enough_water(&config.tank) {
|
||||||
Err(_tank_err) => {
|
Err(_tank_err) => {
|
||||||
if !config.tank.tank_allow_pumping_if_sensor_error {
|
if !config.tank.tank_allow_pumping_if_sensor_error {
|
||||||
// ignore is ok
|
state.no_water = true;
|
||||||
// wtf does this meen, shouldn't something happen if the configuration specifies
|
|
||||||
// that no water should flow if there was an error?
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Ok(enough_water) => {
|
// when no tank error, if plant should be watered depends on if enough water is in tank
|
||||||
state.no_water = !enough_water
|
// 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();
|
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 {
|
if !config.tank.tank_allow_pumping_if_sensor_error {
|
||||||
state.do_water = true;
|
state.do_water = true;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Ok(enough_water) => {
|
Ok(enough_water) => {
|
||||||
state.no_water = !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 {
|
if !config.tank.tank_allow_pumping_if_sensor_error {
|
||||||
state.do_water = true;
|
state.do_water = true;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Ok(enough_water) => {
|
Ok(enough_water) => {
|
||||||
state.no_water = !enough_water;
|
state.no_water = !enough_water;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use serde::Serialize;
|
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;
|
const OPEN_TANK_VOLTAGE: f32 = 3.0;
|
||||||
pub const WATER_FROZEN_THRESH: f32 = 4.0;
|
pub const WATER_FROZEN_THRESH: f32 = 4.0;
|
||||||
@ -10,7 +13,7 @@ pub enum TankError {
|
|||||||
SensorDisabled,
|
SensorDisabled,
|
||||||
SensorMissing(f32),
|
SensorMissing(f32),
|
||||||
SensorValueError { value: f32, min: f32, max: f32 },
|
SensorValueError { value: f32, min: f32, max: f32 },
|
||||||
BoardError(String)
|
BoardError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TankState {
|
pub enum TankState {
|
||||||
@ -35,18 +38,21 @@ fn raw_voltage_to_tank_fill_percent(
|
|||||||
config: &TankConfig,
|
config: &TankConfig,
|
||||||
) -> Result<f32, TankError> {
|
) -> Result<f32, TankError> {
|
||||||
let divider_percent = raw_volatge_to_divider_percent(raw_value_mv)?;
|
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 {
|
return Err(TankError::SensorValueError {
|
||||||
value: divider_percent,
|
value: divider_percent,
|
||||||
min: config.tank_empty_percent.into(),
|
min: config.tank_empty_percent.into(),
|
||||||
max: config.tank_full_percent.into(),
|
max: config.tank_full_percent.into(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok((divider_percent - f32::from(config.tank_empty_percent)) * 100.
|
Ok(
|
||||||
/ f32::from(config.tank_full_percent - config.tank_empty_percent))
|
(divider_percent - f32::from(config.tank_empty_percent)) * 100.
|
||||||
|
/ f32::from(config.tank_full_percent - config.tank_empty_percent),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl TankState {
|
impl TankState {
|
||||||
pub fn left_ml(&self, config: &TankConfig) -> Result<f32, TankError> {
|
pub fn left_ml(&self, config: &TankConfig) -> Result<f32, TankError> {
|
||||||
match self {
|
match self {
|
||||||
@ -69,10 +75,14 @@ impl TankState {
|
|||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
matches!(self, TankState::TankSensorDisabled)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn warn_level(&self, config: &TankConfig) -> Result<bool, TankError> {
|
pub fn warn_level(&self, config: &TankConfig) -> Result<bool, TankError> {
|
||||||
match self {
|
match self {
|
||||||
TankState::TankSensorDisabled => Err(TankError::SensorDisabled),
|
TankState::TankSensorDisabled => Err(TankError::SensorDisabled),
|
||||||
@ -84,29 +94,37 @@ impl TankState {
|
|||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn got_error(&self, config: &TankConfig) -> Option<TankError> {
|
pub fn got_error(&self, config: &TankConfig) -> Option<TankError> {
|
||||||
match self {
|
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::TankSensorError(err) => Some(err.clone()),
|
||||||
TankState::TankSensorDisabled => Some(TankError::SensorDisabled),
|
TankState::TankSensorDisabled => Some(TankError::SensorDisabled),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_mqtt_info(&self, config: &TankConfig, water_temp: Result<f32, anyhow::Error>) -> TankInfo {
|
pub fn as_mqtt_info(
|
||||||
|
&self,
|
||||||
|
config: &TankConfig,
|
||||||
|
water_temp: Result<f32, anyhow::Error>,
|
||||||
|
) -> TankInfo {
|
||||||
let mut tank_err: Option<TankError> = None;
|
let mut tank_err: Option<TankError> = None;
|
||||||
let left_ml = match self.left_ml(config) {
|
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),
|
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 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 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 {
|
let raw = match self {
|
||||||
TankState::TankSensorDisabled
|
TankState::TankSensorDisabled | TankState::TankSensorError(_) => None,
|
||||||
| TankState::TankSensorError(_) => None,
|
|
||||||
TankState::TankSensorPresent(raw_value_mv) => Some(*raw_value_mv),
|
TankState::TankSensorPresent(raw_value_mv) => Some(*raw_value_mv),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -116,9 +134,11 @@ impl TankState {
|
|||||||
left_ml,
|
left_ml,
|
||||||
sensor_error: tank_err,
|
sensor_error: tank_err,
|
||||||
raw,
|
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(),
|
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 {
|
if config.tank.tank_sensor_enabled {
|
||||||
match board.tank_sensor_voltage() {
|
match board.tank_sensor_voltage() {
|
||||||
Ok(raw_sensor_value_mv) => TankState::TankSensorPresent(raw_sensor_value_mv),
|
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 {
|
} else {
|
||||||
TankState::TankSensorDisabled
|
TankState::TankSensorDisabled
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user