Refactor plant state handling and moisture interpretation

- Replaced `read_hardware_state` with `interpret_raw_values` for better abstraction and clarity.
- Enhanced error handling by introducing `NoMessage` and `NotExpectedMessage` states.
- Updated moisture sensor logic to differentiate expected and unexpected messages.
- Renamed and refactored enum fields for consistency (`raw_hz` to `hz`).
- Minor imports and formatting optimizations.
This commit is contained in:
2026-04-16 23:58:23 +02:00
parent 6a71ac4234
commit 2493507304
4 changed files with 51 additions and 64 deletions

View File

@@ -2,7 +2,7 @@ use alloc::vec::Vec;
use bincode::{Decode, Encode}; use bincode::{Decode, Encode};
use embedded_savegame::storage::{Flash, Storage}; use embedded_savegame::storage::{Flash, Storage};
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
use esp_bootloader_esp_idf::partitions::{Error as PartitionError, Error, FlashRegion}; use esp_bootloader_esp_idf::partitions::{Error as PartitionError, FlashRegion};
use log::{error, info}; use log::{error, info};
use serde::Serialize; use serde::Serialize;

View File

@@ -385,14 +385,14 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let moisture = board.board_hal.measure_moisture_hz().await?; let moisture = board.board_hal.measure_moisture_hz().await?;
let plantstate: [PlantState; PLANT_COUNT] = [ let plantstate: [PlantState; PLANT_COUNT] = [
PlantState::read_hardware_state(moisture, 0, &mut board).await, PlantState::interpret_raw_values(moisture, 0, &mut board).await,
PlantState::read_hardware_state(moisture, 1, &mut board).await, PlantState::interpret_raw_values(moisture, 1, &mut board).await,
PlantState::read_hardware_state(moisture, 2, &mut board).await, PlantState::interpret_raw_values(moisture, 2, &mut board).await,
PlantState::read_hardware_state(moisture, 3, &mut board).await, PlantState::interpret_raw_values(moisture, 3, &mut board).await,
PlantState::read_hardware_state(moisture, 4, &mut board).await, PlantState::interpret_raw_values(moisture, 4, &mut board).await,
PlantState::read_hardware_state(moisture, 5, &mut board).await, PlantState::interpret_raw_values(moisture, 5, &mut board).await,
PlantState::read_hardware_state(moisture, 6, &mut board).await, PlantState::interpret_raw_values(moisture, 6, &mut board).await,
PlantState::read_hardware_state(moisture, 7, &mut board).await, PlantState::interpret_raw_values(moisture, 7, &mut board).await,
]; ];
publish_plant_states(&mut board, &timezone_time.clone(), &plantstate) publish_plant_states(&mut board, &timezone_time.clone(), &plantstate)

View File

@@ -10,14 +10,16 @@ const MOIST_SENSOR_MIN_FREQUENCY: f32 = 150.; // this is really, really dry, thi
#[derive(Debug, PartialEq, Serialize)] #[derive(Debug, PartialEq, Serialize)]
pub enum MoistureSensorError { pub enum MoistureSensorError {
NoMessage, MissingMessage,
NotExpectedMessage { hz: f32 },
ShortCircuit { hz: f32, max: f32 }, ShortCircuit { hz: f32, max: f32 },
OpenLoop { hz: f32, min: f32 }, OpenLoop { hz: f32, min: f32 },
} }
#[derive(Debug, PartialEq, Serialize)] #[derive(Debug, PartialEq, Serialize)]
pub enum MoistureSensorState { pub enum MoistureSensorState {
MoistureValue { raw_hz: f32, moisture_percent: f32 }, MoistureValue { hz: f32, moisture_percent: f32 },
NoMessage,
SensorError(MoistureSensorError), SensorError(MoistureSensorError),
} }
@@ -31,7 +33,7 @@ impl MoistureSensorState {
pub fn moisture_percent(&self) -> Option<f32> { pub fn moisture_percent(&self) -> Option<f32> {
if let MoistureSensorState::MoistureValue { if let MoistureSensorState::MoistureValue {
raw_hz: _, hz: _,
moisture_percent, moisture_percent,
} = self } = self
{ {
@@ -112,64 +114,47 @@ fn map_range_moisture(
} }
impl PlantState { impl PlantState {
pub async fn read_hardware_state( pub async fn interpret_raw_values(
moistures: Moistures, moistures: Moistures,
plant_id: usize, plant_id: usize,
board: &mut HAL<'_>, board: &mut HAL<'_>,
) -> Self { ) -> Self {
let sensor_a = { let min = board.board_hal.get_config().plants[plant_id].moisture_sensor_min_frequency;
//if board.board_hal.get_config().plants[plant_id].sensor_a { let max = board.board_hal.get_config().plants[plant_id].moisture_sensor_max_frequency;
let raw = moistures.sensor_a_hz[plant_id];
match raw {
None => MoistureSensorState::SensorError(MoistureSensorError::NoMessage),
Some(raw) => {
match map_range_moisture(
raw,
board.board_hal.get_config().plants[plant_id]
.moisture_sensor_min_frequency
.map(|a| a as f32),
board.board_hal.get_config().plants[plant_id]
.moisture_sensor_max_frequency
.map(|b| b as f32),
) {
Ok(moisture_percent) => MoistureSensorState::MoistureValue {
raw_hz: raw,
moisture_percent,
},
Err(err) => MoistureSensorState::SensorError(err),
}
}
}
}; // else {
// MoistureSensorState::Disabled
//};
let sensor_b = { let raw_to_value = |raw: Option<f32>, expected: bool| -> MoistureSensorState {
//if board.board_hal.get_config().plants[plant_id].sensor_b {
let raw = moistures.sensor_b_hz[plant_id];
match raw { match raw {
None => MoistureSensorState::SensorError(MoistureSensorError::NoMessage), None => {
if expected {
MoistureSensorState::SensorError(MoistureSensorError::MissingMessage)
} else {
MoistureSensorState::NoMessage
}
}
Some(raw) => { Some(raw) => {
match map_range_moisture( if expected {
raw, match map_range_moisture(raw, min.map(|a| a as f32), max.map(|b| b as f32))
board.board_hal.get_config().plants[plant_id] {
.moisture_sensor_min_frequency Ok(moisture_percent) => MoistureSensorState::MoistureValue {
.map(|a| a as f32), hz: raw,
board.board_hal.get_config().plants[plant_id] moisture_percent,
.moisture_sensor_max_frequency },
.map(|b| b as f32), Err(err) => MoistureSensorState::SensorError(err),
) { }
Ok(moisture_percent) => MoistureSensorState::MoistureValue { } else {
raw_hz: raw, MoistureSensorState::SensorError(MoistureSensorError::NotExpectedMessage {
moisture_percent, hz: raw,
}, })
Err(err) => MoistureSensorState::SensorError(err),
} }
} }
} }
}; // else { };
// MoistureSensorState::Disabled
//}; let expected_a = board.board_hal.get_config().plants[plant_id].sensor_a;
let expected_b = board.board_hal.get_config().plants[plant_id].sensor_b;
let sensor_a = { raw_to_value(moistures.sensor_a_hz[plant_id], expected_a) };
let sensor_b = { raw_to_value(moistures.sensor_b_hz[plant_id], expected_b) };
let previous_pump = board.board_hal.get_esp().last_pump_time(plant_id); let previous_pump = board.board_hal.get_esp().last_pump_time(plant_id);
let consecutive_pump_count = board.board_hal.get_esp().consecutive_pump_count(plant_id); let consecutive_pump_count = board.board_hal.get_esp().consecutive_pump_count(plant_id);

View File

@@ -5,7 +5,7 @@ use crate::plant_state::{MoistureSensorState, PlantState};
use crate::tank::determine_tank_state; use crate::tank::determine_tank_state;
use crate::{get_version, BOARD_ACCESS}; use crate::{get_version, BOARD_ACCESS};
use alloc::format; use alloc::format;
use alloc::string::String; use alloc::string::{String, ToString};
use alloc::vec::Vec; use alloc::vec::Vec;
use chrono_tz::Tz; use chrono_tz::Tz;
use core::str::FromStr; use core::str::FromStr;
@@ -40,25 +40,27 @@ where
let moistures = board.board_hal.measure_moisture_hz().await?; let moistures = board.board_hal.measure_moisture_hz().await?;
let mut plant_state = Vec::new(); let mut plant_state = Vec::new();
for i in 0..PLANT_COUNT { for i in 0..PLANT_COUNT {
plant_state.push(PlantState::read_hardware_state(moistures, i, &mut board).await); plant_state.push(PlantState::interpret_raw_values(moistures, i, &mut board).await);
} }
let a = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_a { let a = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_a {
MoistureSensorState::MoistureValue { MoistureSensorState::MoistureValue {
raw_hz, hz: raw_hz,
moisture_percent, moisture_percent,
} => { } => {
format!("{moisture_percent:.2}% {raw_hz}hz",) format!("{moisture_percent:.2}% {raw_hz}hz",)
} }
MoistureSensorState::SensorError(err) => format!("{err:?}"), MoistureSensorState::SensorError(err) => format!("{err:?}"),
MoistureSensorState::NoMessage => "No Message".to_string(),
})); }));
let b = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_b { let b = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_b {
MoistureSensorState::MoistureValue { MoistureSensorState::MoistureValue {
raw_hz, hz: raw_hz,
moisture_percent, moisture_percent,
} => { } => {
format!("{moisture_percent:.2}% {raw_hz}hz",) format!("{moisture_percent:.2}% {raw_hz}hz",)
} }
MoistureSensorState::SensorError(err) => format!("{err:?}"), MoistureSensorState::SensorError(err) => format!("{err:?}"),
MoistureSensorState::NoMessage => "No Message".to_string(),
})); }));
let data = Moistures { let data = Moistures {