diff --git a/board/PlantCtrlESP32.kicad_prl b/board/PlantCtrlESP32.kicad_prl index 2c20d8a..4c6c9a4 100644 --- a/board/PlantCtrlESP32.kicad_prl +++ b/board/PlantCtrlESP32.kicad_prl @@ -68,7 +68,7 @@ 39, 40 ], - "visible_layers": "ffc7055_fffffff8", + "visible_layers": "ffc7055_ffffffff", "zone_display_mode": 1 }, "git": { diff --git a/rust/src/config.rs b/rust/src/config.rs index 8b329f6..21833eb 100644 --- a/rust/src/config.rs +++ b/rust/src/config.rs @@ -60,7 +60,6 @@ pub struct Plant { pub pump_hour_start: u8, pub pump_hour_end: u8, pub sensor_b: bool, - pub sensor_p: bool, } impl Default for Plant { fn default() -> Self { @@ -71,8 +70,7 @@ impl Default for Plant { pump_hour_start: 8, pump_hour_end: 20, mode: Mode::OFF, - sensor_b: false, - sensor_p: false, + sensor_b: false } } } diff --git a/rust/src/main.rs b/rust/src/main.rs index a19ef4a..8781446 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -74,7 +74,6 @@ struct LightState { struct PlantState { a: Option, b: Option, - p: Option, consecutive_pump_count: u32, after_p: Option, do_water: bool, @@ -86,7 +85,6 @@ struct PlantState { no_water: bool, sensor_error_a: Option, sensor_error_b: Option, - sensor_error_p: Option, out_of_work_hour: bool, next_pump: Option>, } @@ -120,8 +118,6 @@ struct TankStateMQTT { struct PlantStateMQTT<'a> { a: &'a str, b: &'a str, - p_start: &'a str, - p_end: &'a str, mode: &'a str, consecutive_pump_count: u32, dry: bool, @@ -438,18 +434,6 @@ fn safe_main() -> anyhow::Result<()> { 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!( "Trying to pump for {}s with pump {} now", plant_config.pump_time_s, plant @@ -463,48 +447,11 @@ fn safe_main() -> anyhow::Result<()> { state.active = true; for _ in 0..plant_config.pump_time_s { unsafe { vTaskDelay(CONFIG_FREERTOS_HZ) }; - let p_live_topic = format!("/plant{} p live", plant + 1); - 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, - &p_live_topic, - option_to_string(&moist.ok()).as_bytes(), - ); - } - } else { - if online_mode == OnlineMode::Online { - let _ = - board.mqtt_publish(&config, &p_live_topic, "disabled".as_bytes()); - } - } + //info message or something? } board.pump(plant, false)?; } - - if plant_config.sensor_p { - match map_range_moisture( - board.measure_moisture_hz(plant, plant_hal::Sensor::PUMP)? as f32, - ) { - 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); - //mqtt sync pump error value - } - } } None => { println!("Nothing to do"); @@ -896,10 +843,7 @@ fn determine_next_plant( } } - if state.sensor_error_a.is_some() - || state.sensor_error_b.is_some() - || state.sensor_error_p.is_some() - { + if state.sensor_error_a.is_some() || state.sensor_error_b.is_some() { board.fault(plant, true); } if !state.dry { @@ -936,8 +880,6 @@ fn update_plant_state( let mode = format!("{:?}", plant_config.mode); let plant_dto = PlantStateMQTT { - p_start: &sensor_to_string(&state.p, &state.sensor_error_p, plant_config.sensor_p), - p_end: &sensor_to_string(&state.after_p, &state.sensor_error_p, plant_config.sensor_p), a: &sensor_to_string( &state.a, &state.sensor_error_a, @@ -1108,10 +1050,3 @@ fn in_time_range(cur: &DateTime, start: u8, end: u8) -> bool { return curhour > start || curhour < end; } } - -fn option_to_string(value: &Option) -> String { - match value { - Some(v) => v.to_string(), - None => "Error".to_owned(), - } -} diff --git a/rust/src/plant_hal.rs b/rust/src/plant_hal.rs index 0a902ec..70b5a9c 100644 --- a/rust/src/plant_hal.rs +++ b/rust/src/plant_hal.rs @@ -1,5 +1,5 @@ use bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver}; -//mod config; + use chrono_tz::Europe::Berlin; use embedded_svc::wifi::{ AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration, @@ -50,13 +50,8 @@ use one_wire_bus::OneWire; use crate::config::{self, Config, WifiConfig}; use crate::STAY_ALIVE; +//Only support for 8 right now! pub const PLANT_COUNT: usize = 8; -const PINS_PER_PLANT: usize = 5; -const PLANT_PUMP_OFFSET: usize = 0; -const PLANT_FAULT_OFFSET: usize = 1; -const PLANT_MOIST_PUMP_OFFSET: usize = 2; -const PLANT_MOIST_A_OFFSET: usize = 3; -const PLANT_MOIST_B_OFFSET: usize = 4; const SPIFFS_PARTITION_NAME: &str = "storage"; const WIFI_CONFIG_FILE: &str = "/spiffs/wifi.cfg"; @@ -64,6 +59,51 @@ const CONFIG_FILE: &str = "/spiffs/config.cfg"; const TANK_MULTI_SAMPLE: usize = 11; +const PUMP8_BIT: usize = 0; +const PUMP1_BIT: usize = 1; +const PUMP2_BIT: usize = 2; +const PUMP3_BIT: usize = 3; +const PUMP4_BIT: usize = 4; +const PUMP5_BIT: usize = 5; +const PUMP6_BIT: usize = 6; +const PUMP7_BIT: usize = 7; + +const MS_0: usize = 8; +const MS_4: usize = 9; +const MS_2: usize = 10; +const MS_3: usize = 11; +const SENSOR_ON: usize = 12; +const MS_1: usize = 13; +//unused 14 +//unused 15 + +const FAULT_3: usize = 16; +const FAULT_8: usize = 17; +const FAULT_7: usize = 18; +const FAULT_6: usize = 19; +const FAULT_5: usize = 20; +const FAULT_4: usize = 21; +const FAULT_1: usize = 22; +const FAULT_2: usize = 23; + +const SENSOR_A_1: u8 = 7; +const SENSOR_A_2: u8 = 6; +const SENSOR_A_3: u8 = 5; +const SENSOR_A_4: u8 = 4; +const SENSOR_A_5: u8 = 3; +const SENSOR_A_6: u8 = 2; +const SENSOR_A_7: u8 = 1; +const SENSOR_A_8: u8 = 0; + +const SENSOR_B_1: u8 = 8; +const SENSOR_B_2: u8 = 9; +const SENSOR_B_3: u8 = 10; +const SENSOR_B_4: u8 = 11; +const SENSOR_B_5: u8 = 12; +const SENSOR_B_6: u8 = 13; +const SENSOR_B_7: u8 = 14; +const SENSOR_B_8: u8 = 15; + #[link_section = ".rtc.data"] static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT]; #[link_section = ".rtc.data"] @@ -88,7 +128,6 @@ pub enum ClearConfigType { pub enum Sensor { A, B, - PUMP, } pub trait PlantCtrlBoardInteraction { fn time(&mut self) -> Result>; @@ -125,7 +164,7 @@ pub trait PlantCtrlBoardInteraction { //keep state during deepsleep fn light(&mut self, enable: bool) -> Result<()>; - fn measure_moisture_hz(&self, plant: usize, sensor: Sensor) -> Result; + fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result; fn pump(&self, plant: usize, enable: bool) -> Result<()>; fn last_pump_time(&self, plant: usize) -> Option>; fn store_last_pump_time(&mut self, plant: usize, time: chrono::DateTime); @@ -149,6 +188,8 @@ pub trait PlantCtrlBoardInteraction { fn is_wifi_config_file_existant(&mut self) -> bool; fn mqtt(&mut self, config: &Config) -> Result<()>; fn mqtt_publish(&mut self, config: &Config, subtopic: &str, message: &[u8]) -> Result<()>; + + fn sensor_multiplexer(&mut self, n: u8) -> Result<()>; } pub trait CreatePlantHal<'a> { @@ -266,7 +307,17 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> { } fn pump(&self, plant: usize, enable: bool) -> Result<()> { - let index = plant * PINS_PER_PLANT + PLANT_PUMP_OFFSET; + let index = match plant { + 0 => PUMP1_BIT, + 1 => PUMP2_BIT, + 2 => PUMP3_BIT, + 3 => PUMP4_BIT, + 4 => PUMP5_BIT, + 5 => PUMP6_BIT, + 6 => PUMP7_BIT, + 7 => PUMP8_BIT, + _ => bail!("Invalid pump {plant}",), + }; //currently infailable error, keep for future as result anyway self.shift_register.decompose()[index].set_state(enable.into())?; Ok(()) @@ -296,7 +347,17 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> { } fn fault(&self, plant: usize, enable: bool) { - let index = plant * PINS_PER_PLANT + PLANT_FAULT_OFFSET; + let index = match plant { + 0 => FAULT_1, + 1 => FAULT_2, + 2 => FAULT_3, + 3 => FAULT_4, + 4 => FAULT_5, + 5 => FAULT_6, + 6 => FAULT_7, + 7 => FAULT_8, + _ => panic!("Invalid plant id {}", plant) + }; self.shift_register.decompose()[index] .set_state(enable.into()) .unwrap() @@ -338,28 +399,58 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> { self.time() } - fn measure_moisture_hz(&self, plant: usize, sensor: Sensor) -> Result { + fn measure_moisture_hz(&mut self, plant: usize, sensor: Sensor) -> Result { self.signal_counter.counter_pause()?; self.signal_counter.counter_clear()?; - // - let offset = match sensor { - Sensor::A => PLANT_MOIST_A_OFFSET, - Sensor::B => PLANT_MOIST_B_OFFSET, - Sensor::PUMP => PLANT_MOIST_PUMP_OFFSET, + //Disable all + self.shift_register.decompose()[SENSOR_ON] + .set_high() + .unwrap(); + + + let sensor_channel = match sensor { + Sensor::A => match plant { + 0 => SENSOR_A_1, + 1 => SENSOR_A_2, + 2 => SENSOR_A_3, + 3 => SENSOR_A_4, + 4 => SENSOR_A_5, + 5 => SENSOR_A_6, + 6 => SENSOR_A_7, + 7 => SENSOR_A_8, + _ => bail!("Invalid plant id {}", plant) + }, + Sensor::B => match plant { + 0 => SENSOR_B_1, + 1 => SENSOR_B_2, + 2 => SENSOR_B_3, + 3 => SENSOR_B_4, + 4 => SENSOR_B_5, + 5 => SENSOR_B_6, + 6 => SENSOR_B_7, + 7 => SENSOR_B_8, + _ => bail!("Invalid plant id {}", plant) + }, }; - let index = plant * PINS_PER_PLANT + offset; + + self.sensor_multiplexer(sensor_channel)?; + + self.shift_register.decompose()[SENSOR_ON] + .set_low() + .unwrap(); let delay = Delay::new_default(); let measurement = 100; let factor = 1000 as f32 / measurement as f32; - self.shift_register.decompose()[index].set_high().unwrap(); //give some time to stabilize delay.delay_ms(10); self.signal_counter.counter_resume()?; delay.delay_ms(measurement); self.signal_counter.counter_pause()?; - self.shift_register.decompose()[index].set_low().unwrap(); + self.shift_register.decompose()[SENSOR_ON] + .set_high() + .unwrap(); let unscaled = self.signal_counter.get_counter_value()? as i32; let hz = (unscaled as f32 * factor) as i32; println!("Measuring {:?} @ {} with {}", sensor, plant, hz); @@ -605,10 +696,6 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> { for i in 0..8 { self.measure_moisture_hz(i, Sensor::B)?; } - for i in 0..8 { - self.measure_moisture_hz(i, Sensor::PUMP)?; - } - Ok(()) } @@ -887,6 +974,37 @@ impl PlantCtrlBoardInteraction for PlantCtrlBoard<'_> { None => bail!("Error reading State of Health bq34z100 not found"), } } + + fn sensor_multiplexer(&mut self, n: u8) -> Result<()> { + assert!(n < 16); + let is_bit_set = |b: u8| -> bool { n & (1 << b) != 0 }; + + let pin_0 = &mut self.shift_register.decompose()[MS_0]; + let pin_1 = &mut self.shift_register.decompose()[MS_1]; + let pin_2 = &mut self.shift_register.decompose()[MS_2]; + let pin_3 = &mut self.shift_register.decompose()[MS_3]; + if is_bit_set(0) { + pin_0.set_high()?; + } else { + pin_0.set_low()?; + } + if is_bit_set(1) { + pin_1.set_high()?; + } else { + pin_1.set_low()?; + } + if is_bit_set(2) { + pin_2.set_high()?; + } else { + pin_2.set_low()?; + } + if is_bit_set(3) { + pin_3.set_high()?; + } else { + pin_3.set_low()?; + } + Ok(()) + } } fn print_battery( @@ -988,8 +1106,11 @@ impl CreatePlantHal<'_> for PlantHal { let mut one_wire_pin = PinDriver::input_output_od(peripherals.pins.gpio18)?; one_wire_pin.set_pull(Pull::Floating).unwrap(); - //TODO make to none if not possible to init + //disable all + let ms4 = &mut shift_register.decompose()[MS_4]; + ms4.set_high()?; + //init,reset rtc memory depending on cause let reasons = ResetReason::get(); let reset_store = match reasons {