WIP introduce plant_state module

This commit is contained in:
2025-03-27 22:28:41 +01:00
parent d9c3d4e13c
commit cf31ce8d43
2 changed files with 138 additions and 85 deletions

View File

@@ -26,21 +26,14 @@ use crate::{config::PlantControllerConfig, webserver::webserver::httpd};
mod config;
mod log;
pub mod plant_hal;
mod plant_state;
mod tank;
use plant_state::{PlantInfo, PlantStateMQTT};
use tank::*;
const TIME_ZONE: Tz = Berlin;
const MOIST_SENSOR_MAX_FREQUENCY: u32 = 6500; // 60kHz (500Hz margin)
const MOIST_SENSOR_MIN_FREQUENCY: u32 = 150; // this is really really dry, think like cactus levels
const FROM: (f32, f32) = (
MOIST_SENSOR_MIN_FREQUENCY as f32,
MOIST_SENSOR_MAX_FREQUENCY as f32,
);
const TO: (f32, f32) = (0_f32, 100_f32);
pub static BOARD_ACCESS: Lazy<Mutex<PlantCtrlBoard>> = Lazy::new(|| PlantHal::create().unwrap());
pub static STAY_ALIVE: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false));
@@ -80,46 +73,6 @@ struct LightState {
is_day: bool,
}
#[derive(Debug, PartialEq, Default)]
/// State of a single plant to be tracked
///
/// TODO can some state be replaced with functions
/// TODO unify with PlantStateMQTT
struct PlantState {
/// state of humidity sensor on bank a
a: Option<u8>,
/// raw measured frequency value for sensor on bank a in hertz
a_raw: Option<u32>,
/// state of humidity sensor on bank b
b: Option<u8>,
/// raw measured frequency value for sensor on bank b in hertz
b_raw: Option<u32>,
/// how often has the logic determined that plant should have been irrigated but wasn't
consecutive_pump_count: u32,
/// plant needs to be watered
do_water: bool,
/// is plant considerd to be dry according to settings
dry: bool,
/// is pump currently running
active: bool,
/// TODO: convert this to an Option<PumpErorr> enum for every case that can happen
pump_error: bool,
/// if pump count has increased higher than configured limit
not_effective: bool,
/// plant irrigation cooldown is active
cooldown: bool,
/// we want to irrigate but tank is empty
no_water: bool,
///TODO: combine with field a using Result
sensor_error_a: Option<SensorError>,
///TODO: combine with field b using Result
sensor_error_b: Option<SensorError>,
/// pump should not be watered at this time of day
out_of_work_hour: bool,
/// next time when pump should activate
next_pump: Option<DateTime<Tz>>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
/// humidity sensor error
enum SensorError {
@@ -128,24 +81,6 @@ enum SensorError {
OpenCircuit { hz: f32, min: f32 },
}
#[derive(Serialize)]
struct PlantStateMQTT<'a> {
a: &'a str,
a_raw: &'a str,
b: &'a str,
b_raw: &'a str,
mode: &'a str,
consecutive_pump_count: u32,
dry: bool,
active: bool,
pump_error: bool,
not_effective: bool,
cooldown: bool,
out_of_work_hour: bool,
last_pump: &'a str,
next_pump: &'a str,
}
fn safe_main() -> anyhow::Result<()> {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
@@ -471,7 +406,7 @@ fn safe_main() -> anyhow::Result<()> {
}
};
let mut plantstate: [PlantState; PLANT_COUNT] = core::array::from_fn(|_| PlantState {
let mut plantstate: [PlantInfo; PLANT_COUNT] = core::array::from_fn(|_| PlantInfo {
..Default::default()
});
determine_plant_state(
@@ -636,7 +571,7 @@ fn publish_battery_state(
fn determine_state_target_moisture_for_plant(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
plant: usize,
state: &mut PlantState,
state: &mut PlantInfo,
config: &PlantControllerConfig,
tank_state: &TankState,
cur: DateTime<Tz>,
@@ -731,7 +666,7 @@ fn determine_state_target_moisture_for_plant(
fn determine_state_timer_only_for_plant(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
plant: usize,
state: &mut PlantState,
state: &mut PlantInfo,
config: &PlantControllerConfig,
tank_state: &TankState,
cur: DateTime<Tz>,
@@ -774,7 +709,7 @@ fn determine_state_timer_only_for_plant(
fn determine_state_timer_and_deadzone_for_plant(
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
plant: usize,
state: &mut PlantState,
state: &mut PlantInfo,
config: &PlantControllerConfig,
tank_state: &TankState,
cur: DateTime<Tz>,
@@ -823,7 +758,7 @@ fn determine_state_timer_and_deadzone_for_plant(
}
fn determine_plant_state(
plantstate: &mut [PlantState; PLANT_COUNT],
plantstate: &mut [PlantInfo; PLANT_COUNT],
cur: DateTime<Tz>,
tank_state: &TankState,
config: &PlantControllerConfig,
@@ -861,7 +796,7 @@ fn determine_plant_state(
}
fn update_plant_state(
plantstate: &mut [PlantState; PLANT_COUNT],
plantstate: &mut [PlantInfo; PLANT_COUNT],
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &PlantControllerConfig,
) {
@@ -1006,18 +941,6 @@ fn to_string<T: Display>(value: Result<T>) -> String {
};
}
fn map_range_moisture(s: f32) -> Result<u8, SensorError> {
if s < FROM.0 {
return Err(SensorError::OpenCircuit { hz: s, min: FROM.0 });
}
if s > FROM.1 {
return Err(SensorError::ShortCircuit { hz: s, max: FROM.1 });
}
let tmp = TO.0 + (s - FROM.0) * (TO.1 - TO.0) / (FROM.1 - FROM.0);
return Ok(tmp as u8);
}
fn in_time_range(cur: &DateTime<Tz>, start: u8, end: u8) -> bool {
let curhour = cur.hour() as u8;
//eg 10-14