allow parsing config with missing keys, added nightlamp config stuff, added nightlamp testing,

This commit is contained in:
2025-03-08 18:47:30 +01:00
parent a4fd4acaa3
commit d11dc523f0
9 changed files with 140 additions and 41 deletions

View File

@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
use crate::PLANT_COUNT;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(default)]
pub struct NetworkConfig {
pub ap_ssid: heapless::String<32>,
pub ssid: Option<heapless::String<32>>,
@@ -25,22 +26,30 @@ impl Default for NetworkConfig {
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(default)]
pub struct NightLampConfig {
pub enabled: bool,
pub night_lamp_hour_start: u8,
pub night_lamp_hour_end: u8,
pub night_lamp_only_when_dark: bool,
pub low_soc_cutoff: u8,
pub low_soc_restore: u8
}
impl Default for NightLampConfig {
fn default() -> Self {
Self {
enabled: true,
night_lamp_hour_start: 19,
night_lamp_hour_end: 2,
night_lamp_only_when_dark: true,
low_soc_cutoff: 30,
low_soc_restore: 50
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(default)]
pub struct TankConfig {
pub tank_sensor_enabled: bool,
pub tank_allow_pumping_if_sensor_error: bool,
@@ -63,6 +72,7 @@ impl Default for TankConfig {
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
#[serde(default)]
pub struct PlantControllerConfig {
pub network: NetworkConfig,
pub tank: TankConfig,
@@ -71,6 +81,7 @@ pub struct PlantControllerConfig {
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(default)]
pub struct PlantConfig {
pub mode: Mode,
pub target_moisture: u8,

View File

@@ -39,8 +39,8 @@ pub mod plant_hal;
const TIME_ZONE: Tz = Berlin;
const MOIST_SENSOR_MAX_FREQUENCY: u32 = 250000; // 60kHz (500Hz margin)
const MOIST_SENSOR_MIN_FREQUENCY: u32 = 300; // this is really really dry, think like cactus levels
const MOIST_SENSOR_MAX_FREQUENCY: u32 = 5000; // 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,
@@ -76,6 +76,8 @@ impl WaitType {
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
/// Light State tracking data for mqtt
struct LightState {
/// is enabled in config
enabled: bool,
/// led is on
active: bool,
/// led should not be on at this time of day
@@ -510,28 +512,39 @@ fn safe_main() -> anyhow::Result<()> {
}
update_plant_state(&mut plantstate, &mut board, &config);
let is_day = board.is_day();
let state_of_charge = board.state_charge_percent().unwrap_or(0);
let mut light_state = LightState {
enabled: config.night_lamp.enabled,
..Default::default()
};
let is_day = board.is_day();
light_state.is_day = is_day;
light_state.out_of_work_hour = !in_time_range(
&timezone_time,
config.night_lamp.night_lamp_hour_start,
config.night_lamp.night_lamp_hour_end,
);
let state_of_charge = board.state_charge_percent().unwrap_or(0);
if state_of_charge < 30 {
board.set_low_voltage_in_cycle();
} else if state_of_charge > 50 {
board.clear_low_voltage_in_cycle();
}
light_state.battery_low = board.low_voltage_in_cycle();
if !light_state.out_of_work_hour {
if config.night_lamp.night_lamp_only_when_dark {
if !light_state.is_day {
if light_state.enabled {
light_state.is_day = is_day;
light_state.out_of_work_hour = !in_time_range(
&timezone_time,
config.night_lamp.night_lamp_hour_start,
config.night_lamp.night_lamp_hour_end,
);
if state_of_charge < config.night_lamp.low_soc_cutoff {
board.set_low_voltage_in_cycle();
} else if state_of_charge > config.night_lamp.low_soc_restore {
board.clear_low_voltage_in_cycle();
}
light_state.battery_low = board.low_voltage_in_cycle();
if !light_state.out_of_work_hour {
if config.night_lamp.night_lamp_only_when_dark {
if !light_state.is_day {
if light_state.battery_low {
board.light(false).unwrap();
} else {
light_state.active = true;
board.light(true).unwrap();
}
}
} else {
if light_state.battery_low {
board.light(false).unwrap();
} else {
@@ -540,20 +553,13 @@ fn safe_main() -> anyhow::Result<()> {
}
}
} else {
if light_state.battery_low {
board.light(false).unwrap();
} else {
light_state.active = true;
board.light(true).unwrap();
}
light_state.active = false;
board.light(false).unwrap();
}
} else {
light_state.active = false;
board.light(false).unwrap();
println!("Lightstate is {:?}", light_state);
}
println!("Lightstate is {:?}", light_state);
match serde_json::to_string(&light_state) {
Ok(state) => {
let _ = board.mqtt_publish(&config, "/light", state.as_bytes());

View File

@@ -54,6 +54,11 @@ pub struct WebBackupHeader{
size: usize
}
#[derive(Deserialize)]
pub struct NightLampCommand {
active: bool
}
fn write_time(
request: &mut Request<&mut EspHttpConnection>,
) -> Result<Option<std::string::String>, anyhow::Error> {
@@ -236,6 +241,16 @@ fn pump_test(
anyhow::Ok(None)
}
fn night_lamp_test(
request: &mut Request<&mut EspHttpConnection>,
) -> Result<Option<std::string::String>, anyhow::Error> {
let actual_data = read_up_to_bytes_from_request(request, None)?;
let light_command: NightLampCommand = serde_json::from_slice(&actual_data)?;
let mut board = BOARD_ACCESS.lock().unwrap();
board.light(light_command.active)?;
anyhow::Ok(None)
}
fn wifi_scan(
_request: &mut Request<&mut EspHttpConnection>,
) -> Result<Option<std::string::String>, anyhow::Error> {
@@ -399,6 +414,11 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> {
handle_error_to500(request, pump_test)
})
.unwrap();
server
.fn_handler("/lamptest", Method::Post, |request| {
handle_error_to500(request, night_lamp_test)
})
.unwrap();
server
.fn_handler("/boardtest", Method::Post, move |_| {
BOARD_ACCESS.lock().unwrap().test()