diff --git a/growpi.toml b/growpi.toml index 2c6816a..687c687 100644 --- a/growpi.toml +++ b/growpi.toml @@ -34,6 +34,7 @@ temperature_set_point_upper = 35.0 temperature_set_point_lower = 28.0 temperature_loop_mins = 60 sunlight_hours = 24 +lights_off_hour = 0 watering_frequency_hours = 30 watering_amount_grams = 200 diff --git a/src/config.rs b/src/config.rs index 094bf3d..6649440 100644 --- a/src/config.rs +++ b/src/config.rs @@ -50,6 +50,7 @@ pub struct ControllerSettings { pub temperature_set_point_lower: f32, pub temperature_loop_mins: u64, pub sunlight_hours: u64, + pub lights_off_hour: u64, pub watering_frequency_hours: u64, pub watering_amount_grams: u64, } @@ -126,6 +127,7 @@ impl Default for Configuration { sunlight_hours: 24, watering_frequency_hours: 30, watering_amount_grams: 200, + lights_off_hour: 0, }, data_logging_settings: DataLoggingSettings { enabled: true, diff --git a/src/control/light.rs b/src/control/light.rs index 4bba31c..92c153a 100644 --- a/src/control/light.rs +++ b/src/control/light.rs @@ -8,12 +8,22 @@ use crate::{ state::{lock_state, ProgramStateShared}, }; +fn should_turn_on_light(on_hours: u64, lights_out: u64, current_hour: u64) -> bool { + let off_hours = 24 - on_hours; + (lights_out..(lights_out + off_hours)) + .map(|x| x % 24) + .any(|x| x == current_hour) +} + fn light_control(program_state: ProgramStateShared) -> GenericResult<()> { let program_state = program_state.clone(); let mut program_state = lock_state(&program_state)?; - let local = Local::now(); - let hour = local.time().hour(); - if hour as u64 <= program_state.config.controller_settings.sunlight_hours { + + let on_hours = program_state.config.controller_settings.sunlight_hours; + let current_hour = Local::now().time().hour() as u64; + let lights_out_hour = program_state.config.controller_settings.lights_off_hour; + + if should_turn_on_light(on_hours, lights_out_hour, current_hour) { actuators::switch_lights(crate::io::RelaySwitchState::On, &mut program_state)?; } else { actuators::switch_lights(crate::io::RelaySwitchState::Off, &mut program_state)?; @@ -28,3 +38,31 @@ pub async fn light_control_loop(program_state: ProgramStateShared) { tokio::time::sleep(Duration::from_hours(1)).await; } } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_should_turn_on_light() { + assert!(!should_turn_on_light(24, 5, 4)); + assert!(!should_turn_on_light(24, 5, 5)); + assert!(!should_turn_on_light(24, 5, 6)); + assert!(!should_turn_on_light(24, 0, 0)); + assert!(!should_turn_on_light(24, 0, 23)); + assert!(!should_turn_on_light(24, 0, 1)); + + assert!(!should_turn_on_light(23, 5, 4)); + assert!(should_turn_on_light(23, 5, 5)); + assert!(!should_turn_on_light(23, 5, 6)); + assert!(!should_turn_on_light(23, 0, 23)); + assert!(should_turn_on_light(23, 0, 0)); + assert!(!should_turn_on_light(23, 0, 1)); + + assert!(!should_turn_on_light(20, 22, 21)); + assert!(should_turn_on_light(20, 22, 22)); + assert!(should_turn_on_light(20, 22, 23)); + assert!(should_turn_on_light(20, 22, 0)); + assert!(should_turn_on_light(20, 22, 1)); + assert!(!should_turn_on_light(20, 22, 2)); + } +}