streamline tank state mqtt information structure
This commit is contained in:
parent
b993f2b037
commit
4a334ef2f2
@ -401,41 +401,32 @@ 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);
|
||||||
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 water_frozen = false;
|
||||||
|
|
||||||
let mut temp: Option<f32> = None;
|
let mut attempt = 1;
|
||||||
for _attempt in 0..5 {
|
let water_temp: Result<f32, anyhow::Error> = loop {
|
||||||
let water_temperature = board.water_temperature_c();
|
let temp = board.water_temperature_c();
|
||||||
match water_temperature {
|
match &temp {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
temp = Some(res);
|
println!("Water temp is {}", res);
|
||||||
break;
|
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 {
|
||||||
match temp {
|
break temp
|
||||||
Some(res) => {
|
}
|
||||||
println!("Water temp is {}", res);
|
attempt += 1;
|
||||||
if res < 4_f32 {
|
};
|
||||||
water_frozen = true;
|
if let Ok(res) = water_temp {
|
||||||
}
|
if res < WATER_FROZEN_THRESH {
|
||||||
tank_state_mqtt.water_frozen = water_frozen.to_string();
|
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) => {
|
Ok(state) => {
|
||||||
let _ = board.mqtt_publish(&config, "/water", state.as_bytes());
|
let _ = board.mqtt_publish(&config, "/water", state.as_bytes());
|
||||||
}
|
}
|
||||||
|
@ -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;
|
const OPEN_TANK_VOLTAGE: f32 = 3.0;
|
||||||
|
pub const WATER_FROZEN_THRESH: f32 = 4.0;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
/// 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<u32, error_type>
|
|
||||||
sensor_error: bool,
|
|
||||||
/// raw water sensor value
|
|
||||||
raw: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TankError {
|
pub enum TankError {
|
||||||
SensorDisabled,
|
SensorDisabled,
|
||||||
SensorMissing(f32),
|
SensorMissing(f32),
|
||||||
SensorValueError { value: f32, min: f32, max: f32 },
|
SensorValueError { value: f32, min: f32, max: f32 },
|
||||||
BoardError(anyhow::Error)
|
BoardError(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TankState {
|
pub enum TankState {
|
||||||
TankSensorPresent(f32),
|
TankSensorPresent(f32),
|
||||||
|
TankSensorError(TankError),
|
||||||
TankSensorDisabled,
|
TankSensorDisabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +59,7 @@ 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 {
|
||||||
TankState::TankSensorDisabled => Err(TankError::SensorDisabled),
|
TankState::TankSensorDisabled => Err(TankError::SensorDisabled),
|
||||||
|
TankState::TankSensorError(err) => Err(err.clone()),
|
||||||
TankState::TankSensorPresent(raw_value_mv) => {
|
TankState::TankSensorPresent(raw_value_mv) => {
|
||||||
let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?;
|
let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?;
|
||||||
//TODO(judge) move logging to more sensible place
|
//TODO(judge) move logging to more sensible place
|
||||||
@ -86,6 +74,7 @@ impl TankState {
|
|||||||
pub fn enough_water(&self, config: &TankConfig) -> Result<bool, TankError> {
|
pub fn enough_water(&self, config: &TankConfig) -> Result<bool, TankError> {
|
||||||
match self {
|
match self {
|
||||||
TankState::TankSensorDisabled => Err(TankError::SensorDisabled),
|
TankState::TankSensorDisabled => Err(TankError::SensorDisabled),
|
||||||
|
TankState::TankSensorError(err) => Err(err.clone()),
|
||||||
TankState::TankSensorPresent(raw_value_mv) => {
|
TankState::TankSensorPresent(raw_value_mv) => {
|
||||||
let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?;
|
let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?;
|
||||||
if tank_fill_percent > config.tank_empty_percent.into() {
|
if tank_fill_percent > config.tank_empty_percent.into() {
|
||||||
@ -105,6 +94,7 @@ impl TankState {
|
|||||||
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),
|
||||||
|
TankState::TankSensorError(err) => Err(err.clone()),
|
||||||
TankState::TankSensorPresent(raw_value_mv) => {
|
TankState::TankSensorPresent(raw_value_mv) => {
|
||||||
let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?;
|
let tank_fill_percent = raw_voltage_to_tank_fill_percent(*raw_value_mv, config)?;
|
||||||
if tank_fill_percent < config.tank_warn_percent.into() {
|
if tank_fill_percent < config.tank_warn_percent.into() {
|
||||||
@ -126,30 +116,69 @@ impl TankState {
|
|||||||
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::TankSensorDisabled => Some(TankError::SensorDisabled),
|
TankState::TankSensorDisabled => Some(TankError::SensorDisabled),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
pub fn as_mqtt_info(&self, config: &TankConfig, water_temp: Result<f32, anyhow::Error>) -> TankInfo {
|
||||||
|
let mut tank_err: Option<TankError> = 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)]
|
TankInfo {
|
||||||
pub struct TankStateMQTT {
|
enough_water,
|
||||||
enough_water: bool,
|
warn_level,
|
||||||
warn_level: bool,
|
left_ml,
|
||||||
left_ml: u32,
|
sensor_error: tank_err,
|
||||||
sensor_error: bool,
|
raw,
|
||||||
raw: u16,
|
water_frozen: water_temp.as_ref().is_ok_and(|temp| *temp < WATER_FROZEN_THRESH),
|
||||||
water_frozen: String,
|
water_temp: water_temp.as_ref().copied().ok(),
|
||||||
|
temp_sensor_error: water_temp.err().map(|err| err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn determine_tank_state(
|
pub fn determine_tank_state(
|
||||||
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
|
||||||
config: &PlantControllerConfig,
|
config: &PlantControllerConfig,
|
||||||
) -> Result<TankState, TankError> {
|
) -> TankState {
|
||||||
if config.tank.tank_sensor_enabled {
|
if config.tank.tank_sensor_enabled {
|
||||||
let raw_sensor_value_mv = board.tank_sensor_voltage().map_err(|err| TankError::BoardError(err))?;
|
match board.tank_sensor_voltage() {
|
||||||
Ok(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()))
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} 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<f32>,
|
||||||
|
/// if there is was an issue with the water level sensor
|
||||||
|
sensor_error: Option<TankError>,
|
||||||
|
/// raw water sensor value
|
||||||
|
raw: Option<f32>,
|
||||||
|
/// water in tank might be frozen
|
||||||
|
water_frozen: bool,
|
||||||
|
/// water temperature
|
||||||
|
water_temp: Option<f32>,
|
||||||
|
temp_sensor_error: Option<String>,
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user