allow to selectivly enable redundant sensors
This commit is contained in:
		@@ -65,7 +65,7 @@ embedded-svc = { version = "0.27.0", features = ["experimental"] }
 | 
				
			|||||||
esp-idf-hal = "0.43.0"
 | 
					esp-idf-hal = "0.43.0"
 | 
				
			||||||
esp-idf-sys = { version = "0.34.0", features = ["binstart", "native"] }
 | 
					esp-idf-sys = { version = "0.34.0", features = ["binstart", "native"] }
 | 
				
			||||||
esp_idf_build = "0.1.3"
 | 
					esp_idf_build = "0.1.3"
 | 
				
			||||||
chrono = { version = "0.4.23", default-features = false , features = ["iana-time-zone"] }
 | 
					chrono = { version = "0.4.23", default-features = false , features = ["iana-time-zone" , "alloc"] }
 | 
				
			||||||
chrono-tz = {version="0.8.0", default-features = false , features = [ "filter-by-regex" ]}
 | 
					chrono-tz = {version="0.8.0", default-features = false , features = [ "filter-by-regex" ]}
 | 
				
			||||||
embedded-hal = "1.0.0"
 | 
					embedded-hal = "1.0.0"
 | 
				
			||||||
one-wire-bus = "0.1.1"
 | 
					one-wire-bus = "0.1.1"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,8 @@ pub struct Plant {
 | 
				
			|||||||
    pub pump_cooldown_min: u16,
 | 
					    pub pump_cooldown_min: u16,
 | 
				
			||||||
    pub pump_hour_start: u8,
 | 
					    pub pump_hour_start: u8,
 | 
				
			||||||
    pub pump_hour_end: u8,
 | 
					    pub pump_hour_end: u8,
 | 
				
			||||||
 | 
					    pub sensor_b: bool,
 | 
				
			||||||
 | 
					    pub sensor_p: bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
impl Default for Plant {
 | 
					impl Default for Plant {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
@@ -69,6 +71,8 @@ impl Default for Plant {
 | 
				
			|||||||
            pump_hour_start: 8,
 | 
					            pump_hour_start: 8,
 | 
				
			||||||
            pump_hour_end: 20,
 | 
					            pump_hour_end: 20,
 | 
				
			||||||
            mode: Mode::OFF,
 | 
					            mode: Mode::OFF,
 | 
				
			||||||
 | 
					            sensor_b : false,
 | 
				
			||||||
 | 
					            sensor_p : false
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										306
									
								
								rust/src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										306
									
								
								rust/src/main.rs
									
									
									
									
									
								
							@@ -6,6 +6,7 @@ use std::{
 | 
				
			|||||||
use chrono::{DateTime, Datelike, Duration, NaiveDateTime, Timelike};
 | 
					use chrono::{DateTime, Datelike, Duration, NaiveDateTime, Timelike};
 | 
				
			||||||
use chrono_tz::{Europe::Berlin, Tz};
 | 
					use chrono_tz::{Europe::Berlin, Tz};
 | 
				
			||||||
use config::Plant;
 | 
					use config::Plant;
 | 
				
			||||||
 | 
					use embedded_svc::mqtt;
 | 
				
			||||||
use esp_idf_hal::delay::Delay;
 | 
					use esp_idf_hal::delay::Delay;
 | 
				
			||||||
use esp_idf_sys::{
 | 
					use esp_idf_sys::{
 | 
				
			||||||
    esp_deep_sleep, esp_restart, gpio_deep_sleep_hold_dis, gpio_deep_sleep_hold_en, vTaskDelay,
 | 
					    esp_deep_sleep, esp_restart, gpio_deep_sleep_hold_dis, gpio_deep_sleep_hold_en, vTaskDelay,
 | 
				
			||||||
@@ -65,7 +66,7 @@ struct LightState {
 | 
				
			|||||||
    is_day: bool,
 | 
					    is_day: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Default)]
 | 
					#[derive(Copy, Clone, Debug, PartialEq, Default)]
 | 
				
			||||||
struct PlantState {
 | 
					struct PlantState {
 | 
				
			||||||
    a: Option<u8>,
 | 
					    a: Option<u8>,
 | 
				
			||||||
    b: Option<u8>,
 | 
					    b: Option<u8>,
 | 
				
			||||||
@@ -83,6 +84,7 @@ struct PlantState {
 | 
				
			|||||||
    sensor_error_b: Option<SensorError>,
 | 
					    sensor_error_b: Option<SensorError>,
 | 
				
			||||||
    sensor_error_p: Option<SensorError>,
 | 
					    sensor_error_p: Option<SensorError>,
 | 
				
			||||||
    out_of_work_hour: bool,
 | 
					    out_of_work_hour: bool,
 | 
				
			||||||
 | 
					    next_pump: Option<DateTime<Tz>>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
 | 
					#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
 | 
				
			||||||
@@ -230,7 +232,7 @@ fn safe_main() -> anyhow::Result<()> {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    println!("attempting to connect wifi");
 | 
					    println!("attempting to connect wifi");
 | 
				
			||||||
    match board.wifi(wifi.ssid, wifi.password, 5000) {
 | 
					    match board.wifi(wifi.ssid, wifi.password, 10000) {
 | 
				
			||||||
        Ok(_) => {
 | 
					        Ok(_) => {
 | 
				
			||||||
            online_mode = OnlineMode::Wifi;
 | 
					            online_mode = OnlineMode::Wifi;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -288,6 +290,9 @@ fn safe_main() -> anyhow::Result<()> {
 | 
				
			|||||||
    if online_mode == OnlineMode::Online {
 | 
					    if online_mode == OnlineMode::Online {
 | 
				
			||||||
        let _ = board.mqtt_publish(&config, "/firmware/githash", git_hash.as_bytes());
 | 
					        let _ = board.mqtt_publish(&config, "/firmware/githash", git_hash.as_bytes());
 | 
				
			||||||
        let _ = board.mqtt_publish(&config, "/state", "online".as_bytes());
 | 
					        let _ = board.mqtt_publish(&config, "/state", "online".as_bytes());
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(&config, "/last_online", europe_time.to_rfc3339().as_bytes());
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        publish_battery_state(&mut board, &config);
 | 
					        publish_battery_state(&mut board, &config);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -348,6 +353,20 @@ fn safe_main() -> anyhow::Result<()> {
 | 
				
			|||||||
            let consecutive_pump_count = board.consecutive_pump_count(plant) + 1;
 | 
					            let consecutive_pump_count = board.consecutive_pump_count(plant) + 1;
 | 
				
			||||||
            board.store_consecutive_pump_count(plant, consecutive_pump_count);
 | 
					            board.store_consecutive_pump_count(plant, consecutive_pump_count);
 | 
				
			||||||
            let plant_config = config.plants[plant];
 | 
					            let plant_config = config.plants[plant];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if plant_config.sensor_p {
 | 
				
			||||||
 | 
					                match map_range_moisture(
 | 
				
			||||||
 | 
					                    board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32
 | 
				
			||||||
 | 
					                ) {
 | 
				
			||||||
 | 
					                    Ok(p) => state.p = Some(p),
 | 
				
			||||||
 | 
					                    Err(err) => {
 | 
				
			||||||
 | 
					                        board.fault(plant, true);
 | 
				
			||||||
 | 
					                        state.sensor_error_p = Some(err);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            println!(
 | 
					            println!(
 | 
				
			||||||
                "Trying to pump for {}s with pump {} now",
 | 
					                "Trying to pump for {}s with pump {} now",
 | 
				
			||||||
                plant_config.pump_time_s, plant
 | 
					                plant_config.pump_time_s, plant
 | 
				
			||||||
@@ -358,32 +377,61 @@ fn safe_main() -> anyhow::Result<()> {
 | 
				
			|||||||
            board.pump(plant, true)?;
 | 
					            board.pump(plant, true)?;
 | 
				
			||||||
            board.last_pump_time(plant);
 | 
					            board.last_pump_time(plant);
 | 
				
			||||||
            state.active = true;
 | 
					            state.active = true;
 | 
				
			||||||
            //FIXME do periodic pump test here and state update
 | 
					            for t in 0..plant_config.pump_time_s {
 | 
				
			||||||
            unsafe { vTaskDelay(plant_config.pump_time_s as u32 * CONFIG_FREERTOS_HZ) };
 | 
					                //FIXME do periodic pump test here and state update
 | 
				
			||||||
 | 
					                unsafe { vTaskDelay(CONFIG_FREERTOS_HZ) };
 | 
				
			||||||
 | 
					                if plant_config.sensor_p {
 | 
				
			||||||
 | 
					                    let moist =  map_range_moisture(
 | 
				
			||||||
 | 
					                        board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32);
 | 
				
			||||||
 | 
					                    if online_mode == OnlineMode::Online {
 | 
				
			||||||
 | 
					                        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                            &config,
 | 
				
			||||||
 | 
					                            format!("/plant{}/Sensor P after", plant+1).as_str(),
 | 
				
			||||||
 | 
					                            option_to_string(moist.ok()).as_bytes(),
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                        
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    if online_mode == OnlineMode::Online {
 | 
				
			||||||
 | 
					                        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                            &config,
 | 
				
			||||||
 | 
					                            format!("/plant{}/Sensor P after", plant+1).as_str(),
 | 
				
			||||||
 | 
					                            "disabled".as_bytes(),
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            board.pump(plant, false)?;
 | 
					            board.pump(plant, false)?;
 | 
				
			||||||
            match map_range_moisture(
 | 
					            if plant_config.sensor_p {
 | 
				
			||||||
                board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32
 | 
					                match map_range_moisture(
 | 
				
			||||||
            ) {
 | 
					                    board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32
 | 
				
			||||||
                Ok(p) => state.after_p = Some(p),
 | 
					                ) {
 | 
				
			||||||
                Err(err) => {
 | 
					                    Ok(p) => state.after_p = Some(p),
 | 
				
			||||||
 | 
					                    Err(err) => {
 | 
				
			||||||
 | 
					                        board.fault(plant, true);
 | 
				
			||||||
 | 
					                        state.sensor_error_p = Some(err);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if state.after_p.is_none()
 | 
				
			||||||
 | 
					                    || state.p.is_none()
 | 
				
			||||||
 | 
					                    || state.after_p.unwrap() < state.p.unwrap() + 5
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    state.pump_error = true;
 | 
				
			||||||
                    board.fault(plant, true);
 | 
					                    board.fault(plant, true);
 | 
				
			||||||
                    state.sensor_error_p = Some(err);
 | 
					                    //mqtt sync pump error value
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if state.after_p.is_none()
 | 
					            
 | 
				
			||||||
                || state.p.is_none()
 | 
					 | 
				
			||||||
                || state.after_p.unwrap() < state.p.unwrap() + 5
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                state.pump_error = true;
 | 
					 | 
				
			||||||
                board.fault(plant, true);
 | 
					 | 
				
			||||||
                //mqtt sync pump error value
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        None => {
 | 
					        None => {
 | 
				
			||||||
            println!("Nothing to do");
 | 
					            println!("Nothing to do");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if online_mode == OnlineMode::Online {
 | 
				
			||||||
 | 
					        update_plant_state(&mut plantstate, &mut board, &config);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    let mut light_state = LightState {
 | 
					    let mut light_state = LightState {
 | 
				
			||||||
        ..Default::default()
 | 
					        ..Default::default()
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -700,20 +748,23 @@ fn determine_state_target_moisture_for_plant(
 | 
				
			|||||||
            state.sensor_error_a = Some(SensorError::Unknown);
 | 
					            state.sensor_error_a = Some(SensorError::Unknown);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    match board.measure_moisture_hz(plant, plant_hal::Sensor::B) {
 | 
					    if plant_config.sensor_b {
 | 
				
			||||||
        Ok(b) => {
 | 
					        match board.measure_moisture_hz(plant, plant_hal::Sensor::B) {
 | 
				
			||||||
            let mapped = map_range_moisture(b as f32);
 | 
					            Ok(b) => {
 | 
				
			||||||
            match mapped {
 | 
					                let mapped = map_range_moisture(b as f32);
 | 
				
			||||||
                Ok(result) => state.b = Some(result),
 | 
					                match mapped {
 | 
				
			||||||
                Err(err) => {
 | 
					                    Ok(result) => state.b = Some(result),
 | 
				
			||||||
                    state.sensor_error_b = Some(err);
 | 
					                    Err(err) => {
 | 
				
			||||||
 | 
					                        state.sensor_error_b = Some(err);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					            Err(_) => {
 | 
				
			||||||
        Err(_) => {
 | 
					                state.sensor_error_b = Some(SensorError::Unknown);
 | 
				
			||||||
            state.sensor_error_b = Some(SensorError::Unknown);
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
    //FIXME how to average analyze whatever?
 | 
					    //FIXME how to average analyze whatever?
 | 
				
			||||||
    let a_low = state.a.is_some() && state.a.unwrap() < plant_config.target_moisture;
 | 
					    let a_low = state.a.is_some() && state.a.unwrap() < plant_config.target_moisture;
 | 
				
			||||||
    let b_low = state.b.is_some() && state.b.unwrap() < plant_config.target_moisture;
 | 
					    let b_low = state.b.is_some() && state.b.unwrap() < plant_config.target_moisture;
 | 
				
			||||||
@@ -729,6 +780,8 @@ fn determine_state_target_moisture_for_plant(
 | 
				
			|||||||
    let duration = Duration::minutes((plant_config.pump_cooldown_min).into());
 | 
					    let duration = Duration::minutes((plant_config.pump_cooldown_min).into());
 | 
				
			||||||
    let next_pump = board.last_pump_time(plant) + duration;
 | 
					    let next_pump = board.last_pump_time(plant) + duration;
 | 
				
			||||||
    if next_pump > cur {
 | 
					    if next_pump > cur {
 | 
				
			||||||
 | 
					        let europe_time = next_pump.with_timezone(&Berlin);
 | 
				
			||||||
 | 
					        state.next_pump = Some(europe_time);
 | 
				
			||||||
        state.cooldown = true;
 | 
					        state.cooldown = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if !in_time_range(
 | 
					    if !in_time_range(
 | 
				
			||||||
@@ -779,6 +832,8 @@ fn determine_next_plant(
 | 
				
			|||||||
                let duration = Duration::minutes((plant_config.pump_cooldown_min).into());
 | 
					                let duration = Duration::minutes((plant_config.pump_cooldown_min).into());
 | 
				
			||||||
                let next_pump = board.last_pump_time(plant) + duration;
 | 
					                let next_pump = board.last_pump_time(plant) + duration;
 | 
				
			||||||
                if next_pump > cur {
 | 
					                if next_pump > cur {
 | 
				
			||||||
 | 
					                    let europe_time = next_pump.with_timezone(&Berlin);
 | 
				
			||||||
 | 
					                    state.next_pump = Some(europe_time);
 | 
				
			||||||
                    state.cooldown = true;
 | 
					                    state.cooldown = true;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    if water_frozen {
 | 
					                    if water_frozen {
 | 
				
			||||||
@@ -792,6 +847,8 @@ fn determine_next_plant(
 | 
				
			|||||||
                let duration = Duration::minutes((60 * plant_config.pump_cooldown_min).into());
 | 
					                let duration = Duration::minutes((60 * plant_config.pump_cooldown_min).into());
 | 
				
			||||||
                let next_pump = board.last_pump_time(plant) + duration;
 | 
					                let next_pump = board.last_pump_time(plant) + duration;
 | 
				
			||||||
                if next_pump > cur {
 | 
					                if next_pump > cur {
 | 
				
			||||||
 | 
					                    let europe_time = next_pump.with_timezone(&Berlin);
 | 
				
			||||||
 | 
					                    state.next_pump = Some(europe_time);
 | 
				
			||||||
                    state.cooldown = true;
 | 
					                    state.cooldown = true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if !in_time_range(
 | 
					                if !in_time_range(
 | 
				
			||||||
@@ -828,69 +885,7 @@ fn determine_next_plant(
 | 
				
			|||||||
        println!("Plant {} state is {:?}", plant, state);
 | 
					        println!("Plant {} state is {:?}", plant, state);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if online_mode == OnlineMode::Online {
 | 
					    if online_mode == OnlineMode::Online {
 | 
				
			||||||
        for plant in 0..PLANT_COUNT {
 | 
					        update_plant_state(plantstate, board, config);
 | 
				
			||||||
            let state = &plantstate[plant];
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Sensor A", plant).as_str(),
 | 
					 | 
				
			||||||
                option_to_string(state.a).as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Sensor B", plant).as_str(),
 | 
					 | 
				
			||||||
                option_to_string(state.b).as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Sensor P before", plant).as_str(),
 | 
					 | 
				
			||||||
                option_to_string(state.p).as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Sensor P after", plant).as_str(),
 | 
					 | 
				
			||||||
                option_to_string(state.after_p).as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Should water", plant).as_str(),
 | 
					 | 
				
			||||||
                state.do_water.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Is frozen", plant).as_str(),
 | 
					 | 
				
			||||||
                state.frozen.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Is dry", plant).as_str(),
 | 
					 | 
				
			||||||
                state.dry.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Pump Error", plant).as_str(),
 | 
					 | 
				
			||||||
                state.pump_error.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Pump Ineffective", plant).as_str(),
 | 
					 | 
				
			||||||
                state.not_effective.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Is in Cooldown", plant).as_str(),
 | 
					 | 
				
			||||||
                state.cooldown.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/No Water", plant).as_str(),
 | 
					 | 
				
			||||||
                state.no_water.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            let _ = board.mqtt_publish(
 | 
					 | 
				
			||||||
                &config,
 | 
					 | 
				
			||||||
                format!("/plant{}/Out of Work Hour", plant).as_str(),
 | 
					 | 
				
			||||||
                state.out_of_work_hour.to_string().as_bytes(),
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    for plant in 0..PLANT_COUNT {
 | 
					    for plant in 0..PLANT_COUNT {
 | 
				
			||||||
        let state = &plantstate[plant];
 | 
					        let state = &plantstate[plant];
 | 
				
			||||||
@@ -906,6 +901,133 @@ fn determine_next_plant(
 | 
				
			|||||||
    return None;
 | 
					    return None;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn update_plant_state(plantstate: &mut [PlantState; PLANT_COUNT], board: &mut std::sync::MutexGuard<'_, PlantCtrlBoard<'_>>, config: &Config){
 | 
				
			||||||
 | 
					    for plant in 0..PLANT_COUNT {
 | 
				
			||||||
 | 
					        let state = &plantstate[plant];
 | 
				
			||||||
 | 
					        let plant_config = config.plants[plant];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let last_time = board.last_pump_time(plant);
 | 
				
			||||||
 | 
					        let europe_time = last_time.with_timezone(&Berlin);
 | 
				
			||||||
 | 
					        if europe_time.year() > 2023 {
 | 
				
			||||||
 | 
					            let time = europe_time.to_rfc3339();
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/last pump", plant+1).as_str(),
 | 
				
			||||||
 | 
					                time.as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/last pump", plant+1).as_str(),
 | 
				
			||||||
 | 
					                "N/A".as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match state.next_pump {
 | 
				
			||||||
 | 
					            Some(next) => {
 | 
				
			||||||
 | 
					                let time = next.to_rfc3339();
 | 
				
			||||||
 | 
					                let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                    &config,
 | 
				
			||||||
 | 
					                    format!("/plant{}/next pump", plant+1).as_str(),
 | 
				
			||||||
 | 
					                    time.as_bytes(),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            None => {
 | 
				
			||||||
 | 
					                let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                    &config,
 | 
				
			||||||
 | 
					                    format!("/plant{}/next pump", plant+1).as_str(),
 | 
				
			||||||
 | 
					                    "N/A".as_bytes(),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Sensor A", plant+1).as_str(),
 | 
				
			||||||
 | 
					            option_to_string(state.a).as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        if plant_config.sensor_b {
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/Sensor B", plant+1).as_str(),
 | 
				
			||||||
 | 
					                option_to_string(state.b).as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/Sensor B", plant+1).as_str(),
 | 
				
			||||||
 | 
					                "disabled".as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if plant_config.sensor_p {
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/Sensor P before", plant+1).as_str(),
 | 
				
			||||||
 | 
					                option_to_string(state.p).as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/Sensor P after", plant+1).as_str(),
 | 
				
			||||||
 | 
					                option_to_string(state.after_p).as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/Sensor P before", plant+1).as_str(),
 | 
				
			||||||
 | 
					                "disabled".as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					                &config,
 | 
				
			||||||
 | 
					                format!("/plant{}/Sensor P after", plant+1).as_str(),
 | 
				
			||||||
 | 
					                "disabled".as_bytes(),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Should water", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.do_water.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Is frozen", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.frozen.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Is dry", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.dry.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Pump Error", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.pump_error.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Pump Ineffective", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.not_effective.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Is in Cooldown", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.cooldown.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/No Water", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.no_water.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let _ = board.mqtt_publish(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            format!("/plant{}/Out of Work Hour", plant+1).as_str(),
 | 
				
			||||||
 | 
					            state.out_of_work_hour.to_string().as_bytes(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! {
 | 
					fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! {
 | 
				
			||||||
    let delay = match wait_type {
 | 
					    let delay = match wait_type {
 | 
				
			||||||
        WaitType::InitialConfig => 250_u32,
 | 
					        WaitType::InitialConfig => 250_u32,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -589,21 +589,18 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        for i in 0..8 {
 | 
					        for i in 0..8 {
 | 
				
			||||||
            self.pump(i, true)?;
 | 
					            self.pump(i, true)?;
 | 
				
			||||||
            unsafe { vTaskDelay(500) };
 | 
					            unsafe { vTaskDelay(100) };
 | 
				
			||||||
            self.pump(i, false)?;
 | 
					            self.pump(i, false)?;
 | 
				
			||||||
            unsafe { vTaskDelay(500) };
 | 
					            unsafe { vTaskDelay(100) };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        for i in 0..8 {
 | 
					        for i in 0..8 {
 | 
				
			||||||
            self.measure_moisture_hz(i, Sensor::A)?;
 | 
					            self.measure_moisture_hz(i, Sensor::A)?;
 | 
				
			||||||
            unsafe { vTaskDelay(500) };
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        for i in 0..8 {
 | 
					        for i in 0..8 {
 | 
				
			||||||
            self.measure_moisture_hz(i, Sensor::B)?;
 | 
					            self.measure_moisture_hz(i, Sensor::B)?;
 | 
				
			||||||
            unsafe { vTaskDelay(500) };
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        for i in 0..8 {
 | 
					        for i in 0..8 {
 | 
				
			||||||
            self.measure_moisture_hz(i, Sensor::PUMP)?;
 | 
					            self.measure_moisture_hz(i, Sensor::PUMP)?;
 | 
				
			||||||
            unsafe { vTaskDelay(500) };
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,9 @@ interface PlantConfig {
 | 
				
			|||||||
    pump_time_s: number,
 | 
					    pump_time_s: number,
 | 
				
			||||||
    pump_cooldown_min: number,
 | 
					    pump_cooldown_min: number,
 | 
				
			||||||
    pump_hour_start: number,
 | 
					    pump_hour_start: number,
 | 
				
			||||||
    pump_hour_end: number
 | 
					    pump_hour_end: number,
 | 
				
			||||||
 | 
					    sensor_b: boolean,
 | 
				
			||||||
 | 
					    sensor_p: boolean
 | 
				
			||||||
  }[]
 | 
					  }[]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -173,6 +175,32 @@ let fromWrapper = (() => {
 | 
				
			|||||||
        holder.appendChild(text)
 | 
					        holder.appendChild(text)
 | 
				
			||||||
        text.innerHTML += "Pump Hour End"
 | 
					        text.innerHTML += "Pump Hour End"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        let holder = document.createElement("div");
 | 
				
			||||||
 | 
					        plant.appendChild(holder);
 | 
				
			||||||
 | 
					        let input = document.createElement("input");
 | 
				
			||||||
 | 
					        input.id = "plant_" + i + "_sensor_b";
 | 
				
			||||||
 | 
					        input.type = "checkbox";
 | 
				
			||||||
 | 
					        input.onchange = updateJson;
 | 
				
			||||||
 | 
					        holder.appendChild(input)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let text = document.createElement("span");
 | 
				
			||||||
 | 
					        holder.appendChild(text)
 | 
				
			||||||
 | 
					        text.innerHTML += "Sensor B installed"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        let holder = document.createElement("div");
 | 
				
			||||||
 | 
					        plant.appendChild(holder);
 | 
				
			||||||
 | 
					        let input = document.createElement("input");
 | 
				
			||||||
 | 
					        input.id = "plant_" + i + "_sensor_p";
 | 
				
			||||||
 | 
					        input.type = "checkbox";
 | 
				
			||||||
 | 
					        input.onchange = updateJson;
 | 
				
			||||||
 | 
					        holder.appendChild(input)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let text = document.createElement("span");
 | 
				
			||||||
 | 
					        holder.appendChild(text)
 | 
				
			||||||
 | 
					        text.innerHTML += "Sensor P installed"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sync(current);
 | 
					    sync(current);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -208,6 +236,11 @@ let fromWrapper = (() => {
 | 
				
			|||||||
      plant_pump_hour_start.value = current.plants[i].pump_hour_start.toString();
 | 
					      plant_pump_hour_start.value = current.plants[i].pump_hour_start.toString();
 | 
				
			||||||
      let plant_pump_hour_end = document.getElementById("plant_" + i + "_pump_hour_end") as HTMLInputElement;
 | 
					      let plant_pump_hour_end = document.getElementById("plant_" + i + "_pump_hour_end") as HTMLInputElement;
 | 
				
			||||||
      plant_pump_hour_end.value = current.plants[i].pump_hour_end.toString();
 | 
					      plant_pump_hour_end.value = current.plants[i].pump_hour_end.toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      let plant_sensor_b = document.getElementById("plant_" + i + "_sensor_b") as HTMLInputElement;
 | 
				
			||||||
 | 
					      plant_sensor_b.checked = current.plants[i].sensor_b;
 | 
				
			||||||
 | 
					      let plant_sensor_p = document.getElementById("plant_" + i + "_sensor_p") as HTMLInputElement;
 | 
				
			||||||
 | 
					      plant_sensor_p.checked = current.plants[i].sensor_p;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -236,6 +269,8 @@ let fromWrapper = (() => {
 | 
				
			|||||||
      let plant_pump_cooldown_min = document.getElementById("plant_" + i + "_pump_cooldown_min") as HTMLInputElement;
 | 
					      let plant_pump_cooldown_min = document.getElementById("plant_" + i + "_pump_cooldown_min") as HTMLInputElement;
 | 
				
			||||||
      let plant_pump_hour_start = document.getElementById("plant_" + i + "_pump_hour_start") as HTMLInputElement;
 | 
					      let plant_pump_hour_start = document.getElementById("plant_" + i + "_pump_hour_start") as HTMLInputElement;
 | 
				
			||||||
      let plant_pump_hour_end = document.getElementById("plant_" + i + "_pump_hour_end") as HTMLInputElement;
 | 
					      let plant_pump_hour_end = document.getElementById("plant_" + i + "_pump_hour_end") as HTMLInputElement;
 | 
				
			||||||
 | 
					      let plant_sensor_b = document.getElementById("plant_" + i + "_sensor_b") as HTMLInputElement;
 | 
				
			||||||
 | 
					      let plant_sensor_p = document.getElementById("plant_" + i + "_sensor_p") as HTMLInputElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      current.plants[i] = {
 | 
					      current.plants[i] = {
 | 
				
			||||||
        mode: plant_mode.value,
 | 
					        mode: plant_mode.value,
 | 
				
			||||||
@@ -243,8 +278,9 @@ let fromWrapper = (() => {
 | 
				
			|||||||
        pump_time_s: +plant_pump_time_s.value,
 | 
					        pump_time_s: +plant_pump_time_s.value,
 | 
				
			||||||
        pump_cooldown_min: +plant_pump_cooldown_min.value,
 | 
					        pump_cooldown_min: +plant_pump_cooldown_min.value,
 | 
				
			||||||
        pump_hour_start: +plant_pump_hour_start.value,
 | 
					        pump_hour_start: +plant_pump_hour_start.value,
 | 
				
			||||||
        pump_hour_end: +plant_pump_hour_end.value
 | 
					        pump_hour_end: +plant_pump_hour_end.value,
 | 
				
			||||||
 | 
					        sensor_b: plant_sensor_b.checked,
 | 
				
			||||||
 | 
					        sensor_p: plant_sensor_p.checked
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sync(current);
 | 
					    sync(current);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user