WIP introduce plant_state module
This commit is contained in:
130
rust/src/plant_state.rs
Normal file
130
rust/src/plant_state.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono_tz::Tz;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{config, plant_hal};
|
||||
|
||||
const MOIST_SENSOR_MAX_FREQUENCY: u32 = 5500; // 60kHz (500Hz margin)
|
||||
const MOIST_SENSOR_MIN_FREQUENCY: u32 = 150; // this is really really dry, think like cactus levels
|
||||
|
||||
pub enum HumiditySensorError{
|
||||
ShortCircuit{hz: f32, max: f32},
|
||||
OpenLoop{hz: f32, min: f32}
|
||||
}
|
||||
|
||||
pub enum HumiditySensorState {
|
||||
Disabled,
|
||||
HumidityValue{raw_hz: u32, moisture_percent: f32},
|
||||
SensorError(HumiditySensorError),
|
||||
BoardError(String)
|
||||
}
|
||||
|
||||
impl HumiditySensorState {
|
||||
}
|
||||
|
||||
pub enum PumpError {}
|
||||
|
||||
pub struct PumpState {
|
||||
consecutive_pump_count: u32,
|
||||
previous_pump: Option<DateTime<Utc>>
|
||||
}
|
||||
|
||||
pub enum PlantError{}
|
||||
|
||||
pub struct PlantState {
|
||||
sensor_a: HumiditySensorState,
|
||||
sensor_b: HumiditySensorState,
|
||||
pump: PumpState,
|
||||
}
|
||||
|
||||
fn map_range_moisture(s: f32) -> Result<f32, HumiditySensorError> {
|
||||
if s < MOIST_SENSOR_MIN_FREQUENCY {
|
||||
return Err(HumiditySensorError::OpenCircuit { hz: s, min: FROM.0 });
|
||||
}
|
||||
if s > MOIST_SENSOR_MAX_FREQUENCY {
|
||||
return Err(HumiditySensorError::ShortCircuit { hz: s, max: FROM.1 });
|
||||
}
|
||||
let moisture_percent = (s - MOIST_SENSOR_MIN_FREQUENCY) * 100 / (MOIST_SENSOR_MAX_FREQUENCY - MOIST_SENSOR_MIN_FREQUENCY);
|
||||
|
||||
return Ok(moisture_percent);
|
||||
}
|
||||
|
||||
|
||||
impl PlantState {
|
||||
pub fn read_hardware_state(
|
||||
plant_id: usize,
|
||||
board: &mut plant_hal::PlantCtrlBoard,
|
||||
config: &config::PlantConfig
|
||||
) -> Self {
|
||||
let sensor_a = if config.sensor_a {
|
||||
match board.measure_moisture_hz(plant_id, plant_hal::Sensor::A) {
|
||||
Ok(raw) => {
|
||||
match map_range_moisture(raw) {
|
||||
Ok(moisture_percent) => HumiditySensorState::HumidityValue { raw_hz: raw, moisture_percent },
|
||||
Err(err) => HumiditySensorState::SensorError(err),
|
||||
}
|
||||
},
|
||||
Err(err) => HumiditySensorState::BoardError(err.to_string()),
|
||||
}
|
||||
} else {
|
||||
HumiditySensorState::Disabled
|
||||
};
|
||||
let sensor_b = if config.sensor_b {
|
||||
match board.measure_moisture_hz(plant_id, plant_hal::Sensor::B) {
|
||||
Ok(raw) => {
|
||||
match map_range_moisture(raw) {
|
||||
Ok(moisture_percent) => HumiditySensorState::HumidityValue { raw_hz: raw, moisture_percent },
|
||||
Err(err) => HumiditySensorState::SensorError(err),
|
||||
}
|
||||
},
|
||||
Err(err) => HumiditySensorState::BoardError(err.to_string()),
|
||||
}
|
||||
} else {
|
||||
HumiditySensorState::Disabled
|
||||
};
|
||||
let previous_pump = board.last_pump_time(plant_id);
|
||||
let consecutive_pump_count = board.consecutive_pump_count(plant_id);
|
||||
Self {
|
||||
sensor_a,
|
||||
sensor_b,
|
||||
pump: PumpState { consecutive_pump_count , previous_pump}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Default, Serialize)]
|
||||
/// State of a single plant to be tracked
|
||||
pub struct PlantInfo {
|
||||
/// state of humidity sensor on bank a
|
||||
a: HumiditySensorState,
|
||||
/// raw measured frequency value for sensor on bank a in hertz
|
||||
a_raw: Option<u32>,
|
||||
/// state of humidity sensor on bank b
|
||||
b: HumiditySensorState,
|
||||
/// raw measured frequency value for sensor on bank b in hertz
|
||||
b_raw: Option<u32>,
|
||||
/// configured plant watering mode
|
||||
mode: config::Mode,
|
||||
/// 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,
|
||||
/// pump should not be watered at this time of day
|
||||
out_of_work_hour: bool,
|
||||
/// last time when pump was active
|
||||
last_pump: Option<DateTime<Tz>>,
|
||||
/// next time when pump should activate
|
||||
next_pump: Option<DateTime<Tz>>,
|
||||
}
|
||||
Reference in New Issue
Block a user