save compiling state during refactor

This commit is contained in:
ju6ge 2025-04-18 14:01:51 +02:00
parent 4b1d87b66f
commit d2b55fdafb
Signed by: judge
GPG Key ID: 6512C30DD8E017B5
4 changed files with 98 additions and 92 deletions

View File

@ -7,7 +7,6 @@ use anyhow::{bail, Result};
use chrono::{DateTime, Datelike, TimeDelta, Timelike, Utc}; use chrono::{DateTime, Datelike, TimeDelta, Timelike, Utc};
use chrono_tz::{Europe::Berlin, Tz}; use chrono_tz::{Europe::Berlin, Tz};
use config::PlantWateringMode;
use esp_idf_hal::delay::Delay; use esp_idf_hal::delay::Delay;
use esp_idf_sys::{ use esp_idf_sys::{
esp_ota_get_app_partition_count, esp_ota_get_running_partition, esp_ota_get_state_partition, esp_ota_get_app_partition_count, esp_ota_get_running_partition, esp_ota_get_state_partition,
@ -410,50 +409,55 @@ fn safe_main() -> anyhow::Result<()> {
let mut plantstate: [PlantState; PLANT_COUNT] = let mut plantstate: [PlantState; PLANT_COUNT] =
core::array::from_fn(|i| PlantState::read_hardware_state(i, &mut board, &config.plants[i])); core::array::from_fn(|i| PlantState::read_hardware_state(i, &mut board, &config.plants[i]));
let pump_required = plantstate.iter().any(|it| it.needs_to_be_watered(&config.plants[i], &timezone_time)) && !water_frozen; let pump_required = plantstate
.iter()
.zip(&config.plants)
.any(|(it, conf)| it.needs_to_be_watered(&conf, &timezone_time))
&& !water_frozen;
if pump_required { if pump_required {
log(log::LogMessage::EnableMain, dry_run as u32, 0, "", ""); log(log::LogMessage::EnableMain, dry_run as u32, 0, "", "");
if !dry_run { if !dry_run {
board.any_pump(true)?; board.any_pump(true)?; // what does this do? Does it need to be reset?
} }
for plant in 0..PLANT_COUNT { for (plant_id, (state, plant_config)) in plantstate.iter().zip(&config.plants).enumerate() {
let state = &mut plantstate[plant]; if state.needs_to_be_watered(&plant_config, &timezone_time) {
if state.do_water { let pump_count = board.consecutive_pump_count(plant_id) + 1;
let plant_config = &config.plants[plant]; board.store_consecutive_pump_count(plant_id, pump_count);
state.consecutive_pump_count = board.consecutive_pump_count(plant) + 1; //TODO(judge) where to put this?
board.store_consecutive_pump_count(plant, state.consecutive_pump_count); //if state.consecutive_pump_count > plant_config.max_consecutive_pump_count as u32 {
if state.consecutive_pump_count > plant_config.max_consecutive_pump_count as u32 { // log(
log( // log::LogMessage::ConsecutivePumpCountLimit,
log::LogMessage::ConsecutivePumpCountLimit, // state.consecutive_pump_count as u32,
state.consecutive_pump_count as u32, // plant_config.max_consecutive_pump_count as u32,
plant_config.max_consecutive_pump_count as u32, // &plant.to_string(),
&plant.to_string(), // "",
"", // );
); // state.not_effective = true;
state.not_effective = true; // board.fault(plant, true);
board.fault(plant, true); //}
}
log( log(
log::LogMessage::PumpPlant, log::LogMessage::PumpPlant,
(plant + 1) as u32, (plant_id + 1) as u32,
plant_config.pump_time_s as u32, plant_config.pump_time_s as u32,
&dry_run.to_string(), &dry_run.to_string(),
"", "",
); );
board.store_last_pump_time(plant, cur); board.store_last_pump_time(plant_id, cur);
board.last_pump_time(plant); board.last_pump_time(plant_id);
state.active = true; //state.active = true;
if !dry_run { if !dry_run {
board.pump(plant, true)?; board.pump(plant_id, true)?;
for _ in 0..plant_config.pump_time_s { Delay::new_default().delay_ms(1000*plant_config.pump_time_s as u32);
Delay::new_default().delay_ms(1000); board.pump(plant_id, false)?;
}
board.pump(plant, false)?;
} }
} else if !state.pump_in_timeout(&plant_config, &timezone_time){
// plant does not need to be watered and is not in timeout
// -> reset consecutive pump count
board.store_consecutive_pump_count(plant_id, 0);
} }
} }
} }
update_plant_state(&mut plantstate, &mut board, &config); //update_plant_state(&mut plantstate, &mut board, &config);
let is_day = board.is_day(); let is_day = board.is_day();
let state_of_charge = board.state_charge_percent().unwrap_or(0); let state_of_charge = board.state_charge_percent().unwrap_or(0);

View File

@ -603,7 +603,7 @@ impl PlantCtrlBoard<'_> {
self.time() self.time()
} }
pub fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<u32> { pub fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result<f32> {
let sensor_channel = match sensor { let sensor_channel = match sensor {
Sensor::A => match plant { Sensor::A => match plant {
0 => SENSOR_A_1, 0 => SENSOR_A_1,
@ -629,7 +629,7 @@ impl PlantCtrlBoard<'_> {
}, },
}; };
let mut results = [0_u32; REPEAT_MOIST_MEASURE]; let mut results = [0_f32; REPEAT_MOIST_MEASURE];
for repeat in 0..REPEAT_MOIST_MEASURE { for repeat in 0..REPEAT_MOIST_MEASURE {
self.signal_counter.counter_pause()?; self.signal_counter.counter_pause()?;
self.signal_counter.counter_clear()?; self.signal_counter.counter_clear()?;
@ -644,7 +644,7 @@ impl PlantCtrlBoard<'_> {
.unwrap(); .unwrap();
let delay = Delay::new_default(); let delay = Delay::new_default();
let measurement = 100; let measurement = 100; // TODO what is this scaling factor? what is its purpose?
let factor = 1000 as f32 / measurement as f32; let factor = 1000 as f32 / measurement as f32;
//give some time to stabilize //give some time to stabilize
@ -658,7 +658,7 @@ impl PlantCtrlBoard<'_> {
.unwrap(); .unwrap();
delay.delay_ms(10); delay.delay_ms(10);
let unscaled = self.signal_counter.get_counter_value()? as i32; let unscaled = self.signal_counter.get_counter_value()? as i32;
let hz = (unscaled as f32 * factor) as u32; let hz = unscaled as f32 * factor;
log( log(
LogMessage::RawMeasure, LogMessage::RawMeasure,
unscaled as u32, unscaled as u32,
@ -668,7 +668,7 @@ impl PlantCtrlBoard<'_> {
); );
results[repeat] = hz; results[repeat] = hz;
} }
results.sort(); results.sort_by(|a,b| a.partial_cmp(b).unwrap()); // floats don't seem to implement total_ord
let mid = results.len() / 2; let mid = results.len() / 2;

View File

@ -8,18 +8,19 @@ use crate::{
plant_hal::{self, PLANT_COUNT}, plant_hal::{self, PLANT_COUNT},
}; };
const MOIST_SENSOR_MAX_FREQUENCY: u32 = 5500; // 60kHz (500Hz margin) const MOIST_SENSOR_MAX_FREQUENCY: f32 = 5500.; // 60kHz (500Hz margin)
const MOIST_SENSOR_MIN_FREQUENCY: u32 = 150; // this is really really dry, think like cactus levels const MOIST_SENSOR_MIN_FREQUENCY: f32 = 150.; // this is really really dry, think like cactus levels
#[derive(Debug, PartialEq, Serialize)]
pub enum HumiditySensorError { pub enum HumiditySensorError {
ShortCircuit { hz: f32, max: f32 }, ShortCircuit { hz: f32, max: f32 },
OpenLoop { hz: f32, min: f32 }, OpenLoop { hz: f32, min: f32 },
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Serialize)]
pub enum HumiditySensorState { pub enum HumiditySensorState {
Disabled, Disabled,
HumidityValue { raw_hz: u32, moisture_percent: f32 }, HumidityValue { raw_hz: f32, moisture_percent: f32 },
SensorError(HumiditySensorError), SensorError(HumiditySensorError),
BoardError(String), BoardError(String),
} }
@ -35,7 +36,7 @@ impl HumiditySensorState {
moisture_percent, moisture_percent,
} = self } = self
{ {
Some(moisture_percent) Some(*moisture_percent)
} else { } else {
None None
} }
@ -44,7 +45,7 @@ impl HumiditySensorState {
impl HumiditySensorState {} impl HumiditySensorState {}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Serialize)]
pub enum PumpError { pub enum PumpError {
PumpNotWorking { PumpNotWorking {
failed_attempts: usize, failed_attempts: usize,
@ -52,6 +53,7 @@ pub enum PumpError {
}, },
} }
#[derive(Debug, Serialize)]
pub struct PumpState { pub struct PumpState {
consecutive_pump_count: u32, consecutive_pump_count: u32,
previous_pump: Option<DateTime<Utc>>, previous_pump: Option<DateTime<Utc>>,
@ -74,7 +76,7 @@ pub struct PlantState {
fn map_range_moisture(s: f32) -> Result<f32, HumiditySensorError> { fn map_range_moisture(s: f32) -> Result<f32, HumiditySensorError> {
if s < MOIST_SENSOR_MIN_FREQUENCY { if s < MOIST_SENSOR_MIN_FREQUENCY {
return Err(HumiditySensorError::OpenCircuit { return Err(HumiditySensorError::OpenLoop {
hz: s, hz: s,
min: MOIST_SENSOR_MIN_FREQUENCY, min: MOIST_SENSOR_MIN_FREQUENCY,
}); });
@ -85,7 +87,7 @@ fn map_range_moisture(s: f32) -> Result<f32, HumiditySensorError> {
max: MOIST_SENSOR_MAX_FREQUENCY, max: MOIST_SENSOR_MAX_FREQUENCY,
}); });
} }
let moisture_percent = (s - MOIST_SENSOR_MIN_FREQUENCY) * 100 let moisture_percent = (s - MOIST_SENSOR_MIN_FREQUENCY) * 100.0
/ (MOIST_SENSOR_MAX_FREQUENCY - MOIST_SENSOR_MIN_FREQUENCY); / (MOIST_SENSOR_MAX_FREQUENCY - MOIST_SENSOR_MIN_FREQUENCY);
return Ok(moisture_percent); return Ok(moisture_percent);
@ -165,7 +167,7 @@ impl PlantState {
PlantWateringMode::TargetMoisture => { PlantWateringMode::TargetMoisture => {
let moisture_percent = match ( let moisture_percent = match (
self.sensor_a.moisture_percent(), self.sensor_a.moisture_percent(),
&self.sensor_b.moisture_percent(), self.sensor_b.moisture_percent(),
) { ) {
(Some(moisture_a), Some(moisture_b)) => (moisture_a + moisture_b) / 2., (Some(moisture_a), Some(moisture_b)) => (moisture_a + moisture_b) / 2.,
(Some(moisture_percent), _) => moisture_percent, (Some(moisture_percent), _) => moisture_percent,
@ -196,51 +198,51 @@ impl PlantState {
} }
} }
fn update_plant_state( //fn update_plant_state(
plantstate: &mut [PlantInfo; PLANT_COUNT], // plantstate: &mut [PlantInfo; PLANT_COUNT],
board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>, // board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>,
config: &PlantControllerConfig, // config: &PlantControllerConfig,
) { //) {
for plant in 0..PLANT_COUNT { // for plant in 0..PLANT_COUNT {
let state = &plantstate[plant]; // let state = &plantstate[plant];
let plant_config = &config.plants[plant]; // let plant_config = &config.plants[plant];
//
let mode = format!("{:?}", plant_config.mode); // let mode = format!("{:?}", plant_config.mode);
//
let plant_dto = PlantStateMQTT { // let plant_dto = PlantStateMQTT {
a: &sensor_to_string( // a: &sensor_to_string(
&state.a, // &state.a,
&state.sensor_error_a, // &state.sensor_error_a,
plant_config.mode != PlantWateringMode::OFF, // plant_config.mode != PlantWateringMode::OFF,
), // ),
a_raw: &state.a_raw.unwrap_or(0).to_string(), // a_raw: &state.a_raw.unwrap_or(0).to_string(),
b: &sensor_to_string(&state.b, &state.sensor_error_b, plant_config.sensor_b), // b: &sensor_to_string(&state.b, &state.sensor_error_b, plant_config.sensor_b),
b_raw: &state.b_raw.unwrap_or(0).to_string(), // b_raw: &state.b_raw.unwrap_or(0).to_string(),
active: state.active, // active: state.active,
mode: &mode, // mode: &mode,
last_pump: &time_to_string_utc(board.last_pump_time(plant)), // last_pump: &time_to_string_utc(board.last_pump_time(plant)),
next_pump: &time_to_string(state.next_pump), // next_pump: &time_to_string(state.next_pump),
consecutive_pump_count: state.consecutive_pump_count, // consecutive_pump_count: state.consecutive_pump_count,
cooldown: state.cooldown, // cooldown: state.cooldown,
dry: state.dry, // dry: state.dry,
not_effective: state.not_effective, // not_effective: state.not_effective,
out_of_work_hour: state.out_of_work_hour, // out_of_work_hour: state.out_of_work_hour,
pump_error: state.pump_error, // pump_error: state.pump_error,
}; // };
//
match serde_json::to_string(&plant_dto) { // match serde_json::to_string(&plant_dto) {
Ok(state) => { // Ok(state) => {
let plant_topic = format!("/plant{}", plant + 1); // let plant_topic = format!("/plant{}", plant + 1);
let _ = board.mqtt_publish(&config, &plant_topic, state.as_bytes()); // let _ = board.mqtt_publish(&config, &plant_topic, state.as_bytes());
//reduce speed as else messages will be dropped // //reduce speed as else messages will be dropped
Delay::new_default().delay_ms(200); // Delay::new_default().delay_ms(200);
} // }
Err(err) => { // Err(err) => {
println!("Error publishing lightstate {}", err); // println!("Error publishing lightstate {}", err);
} // }
}; // };
} // }
} //}
#[derive(Debug, PartialEq, Serialize)] #[derive(Debug, PartialEq, Serialize)]
/// State of a single plant to be tracked /// State of a single plant to be tracked
@ -250,7 +252,7 @@ pub struct PlantInfo {
/// state of humidity sensor on bank b /// state of humidity sensor on bank b
sensor_b: HumiditySensorState, sensor_b: HumiditySensorState,
/// configured plant watering mode /// configured plant watering mode
mode: config::PlantWateringMode, mode: PlantWateringMode,
/// plant needs to be watered /// plant needs to be watered
do_water: bool, do_water: bool,
/// is plant considerd to be dry according to settings /// is plant considerd to be dry according to settings

View File

@ -1,10 +1,10 @@
pub trait LimitPrecision { pub trait LimitPrecision {
fn to_precision(self, presision: i32) -> self; fn to_precision(self, presision: i32) -> Self;
} }
impl LimitPrecision for f32 { impl LimitPrecision for f32 {
fn to_precision(self, precision: i32) -> self { fn to_precision(self, precision: i32) -> Self {
(self * (10_f32).powi(precision)).round() / (10_f32).powi(precision) (self * (10_f32).powi(precision)).round() / (10_f32).powi(precision)
} }
} }