save compiling state during refactor
This commit is contained in:
parent
4b1d87b66f
commit
d2b55fdafb
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user