Part 1 of V3 extraction in preperation of v4 and v3 software merge #16
| @@ -88,6 +88,7 @@ text-template = "0.1.0" | ||||
| strum_macros = "0.27.0" | ||||
| esp-ota = { version = "0.2.2", features = ["log"] } | ||||
| unit-enum = "1.4.1" | ||||
| pca9535 = { version = "2.0.0", features = ["std"] } | ||||
|  | ||||
|  | ||||
| [patch.crates-io] | ||||
|   | ||||
| @@ -88,11 +88,16 @@ pub enum BoardVersion{ | ||||
|     V4 | ||||
| } | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] | ||||
| pub struct BoardHardware { | ||||
|     pub board: BoardVersion, | ||||
|     pub battery: BatteryBoardVersion, | ||||
| } | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] | ||||
| #[serde(default)] | ||||
| pub struct PlantControllerConfig { | ||||
|     pub board_hardware: BoardVersion, | ||||
|     pub battery_hardware: BatteryBoardVersion, | ||||
|     pub hardware: BoardHardware, | ||||
|     pub network: NetworkConfig, | ||||
|     pub tank: TankConfig, | ||||
|     pub night_lamp: NightLampConfig, | ||||
|   | ||||
| @@ -57,7 +57,7 @@ use esp_idf_svc::sntp::{self, SyncStatus}; | ||||
| use esp_idf_svc::systime::EspSystemTime; | ||||
| use esp_idf_sys::{gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError}; | ||||
| use one_wire_bus::OneWire; | ||||
|  | ||||
| use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; | ||||
| use crate::config::{BatteryBoardVersion, BoardVersion, PlantControllerConfig}; | ||||
| use crate::log::log; | ||||
| use crate::plant_hal::BoardHal::{Initial, V3, V4}; | ||||
| @@ -78,12 +78,39 @@ 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; | ||||
| #[non_exhaustive] | ||||
| struct V3Constants; | ||||
|  | ||||
| impl V3Constants { | ||||
|     const MS_0: usize = 8; | ||||
|     const MS_4: usize = 9; | ||||
|     const MS_2: usize = 10; | ||||
|     const MS_3: usize = 11; | ||||
|     const MS_1: usize = 13; | ||||
|     const SENSOR_ON: usize = 12; | ||||
|  | ||||
|     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; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| const CHARGING: usize = 14; | ||||
| const AWAKE: usize = 15; | ||||
|  | ||||
| @@ -96,23 +123,7 @@ 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; | ||||
|  | ||||
| const X25: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_SDLC); | ||||
|  | ||||
| @@ -382,13 +393,9 @@ pub enum BoardHal<'a>{ | ||||
|     V4 { | ||||
|         tank_channel: AdcChannelDriver<'a, Gpio5, AdcDriver<'a, esp_idf_hal::adc::ADC1>>, | ||||
|         solar_is_day: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, | ||||
|         boot_button: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, | ||||
|         signal_counter: PcntDriver<'a>, | ||||
|         light: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, | ||||
|         main_pump: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, | ||||
|         tank_power: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, | ||||
|         general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, | ||||
|         wifi_driver: EspWifi<'a>, | ||||
|         one_wire_bus: OneWire<PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>>, | ||||
|         rtc: | ||||
|             Ds323x<ds323x::interface::I2cInterface<MutexDevice<'a, I2cDriver<'a>>>, ds323x::ic::DS3231>, | ||||
| @@ -398,6 +405,9 @@ pub enum BoardHal<'a>{ | ||||
|             eeprom24x::addr_size::TwoBytes, | ||||
|             eeprom24x::unique_serial::No, | ||||
|         >, | ||||
|         general_fault: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, InputOutput>, | ||||
|         pump_expander: Pca9535Immediate<MutexDevice<'a, I2cDriver<'a>>>, | ||||
|         sensor_expander: Pca9535Immediate<MutexDevice<'a, I2cDriver<'a>>>, | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -882,9 +892,9 @@ impl BoardInteraction for HAL<'_> { | ||||
|         unsafe { gpio_hold_en(light.pin()) }; | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn pump(& self, plant: usize, enable: bool) -> Result<()> { | ||||
|         match & self.board_hal { | ||||
|             BoardHal::V3 { shift_register, .. } => { | ||||
|     fn pump(&mut self, plant: usize, enable: bool) -> Result<()> { | ||||
|         match &mut self.board_hal { | ||||
|             V3 { shift_register, .. } => { | ||||
|                 let index = match plant { | ||||
|                     0 => PUMP1_BIT, | ||||
|                     1 => PUMP2_BIT, | ||||
| @@ -899,10 +909,14 @@ impl BoardInteraction for HAL<'_> { | ||||
|                 //currently infallible error, keep for future as result anyway | ||||
|                 shift_register.decompose()[index].set_state(enable.into())?; | ||||
|             } | ||||
|             BoardHal::V4 { .. } => { | ||||
|                 bail!("Not yet implemented") | ||||
|             V4 { pump_expander,  .. } => { | ||||
|                 if enable { | ||||
|                     pump_expander.pin_set_high(GPIOBank::Bank0, plant.try_into()?)?; | ||||
|                 } else { | ||||
|                     pump_expander.pin_set_low(GPIOBank::Bank0, plant.try_into()?)?; | ||||
|                 } | ||||
|             }, | ||||
|             &plant_hal::BoardHal::Initial { .. } => { | ||||
|             &mut Initial { .. } => { | ||||
|                 bail!("Board not configured yet") | ||||
|             } | ||||
|         } | ||||
| @@ -926,8 +940,8 @@ impl BoardInteraction for HAL<'_> { | ||||
|     fn consecutive_pump_count(&mut self, plant: usize) -> u32 { | ||||
|         unsafe { CONSECUTIVE_WATERING_PLANT[plant] } | ||||
|     } | ||||
|     fn fault(& self, plant: usize, enable: bool) -> Result<()>{ | ||||
|         match & self.board_hal { | ||||
|     fn fault(&mut self, plant: usize, enable: bool) -> Result<()>{ | ||||
|         match &mut self.board_hal { | ||||
|             V3 { shift_register, .. } => { | ||||
|                 let index = match plant { | ||||
|                     0 => FAULT_1, | ||||
| @@ -942,29 +956,31 @@ impl BoardInteraction for HAL<'_> { | ||||
|                 }; | ||||
|                 shift_register.decompose()[index] | ||||
|                     .set_state(enable.into())?; | ||||
|                 Ok(()) | ||||
|             } | ||||
|             V4 { pump_expander, .. } => { | ||||
|                 if enable { | ||||
|                     pump_expander.pin_set_high(GPIOBank::Bank1, plant.try_into()?)?; | ||||
|                 } else { | ||||
|                     pump_expander.pin_set_low(GPIOBank::Bank1, plant.try_into()?)?; | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|             BoardHal::V4 { .. } => { | ||||
|                 bail!("Not yet implemented") | ||||
|             } | ||||
|             &plant_hal::BoardHal::Initial { .. } => { | ||||
|             &mut Initial { .. } => { | ||||
|                 bail!("Board not configured yet") | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn low_voltage_in_cycle(&mut self) -> bool { | ||||
|         unsafe { LOW_VOLTAGE_DETECTED } | ||||
|     } | ||||
|     fn any_pump(&mut self, enable: bool) -> Result<()> { | ||||
|  | ||||
|         match &mut self.board_hal { | ||||
|             BoardHal::V3 { main_pump, .. } => { | ||||
|             V3 { main_pump, .. } => { | ||||
|                 main_pump.set_state(enable.into())?; | ||||
|             } | ||||
|             BoardHal::V4 { main_pump, .. } => { | ||||
|                 main_pump.set_state(enable.into())?; | ||||
|             V4 { .. } => { | ||||
|                 //does not exist in v4, ignore it | ||||
|             } | ||||
|             &mut plant_hal::BoardHal::Initial { .. } => { | ||||
|                 bail!("Board not configured yet") | ||||
| @@ -1002,39 +1018,39 @@ impl BoardInteraction for HAL<'_> { | ||||
|                     signal_counter.counter_pause()?; | ||||
|                     signal_counter.counter_clear()?; | ||||
|                     //Disable all | ||||
|                     shift_register.decompose()[MS_4].set_high()?; | ||||
|                     shift_register.decompose()[V3Constants::MS_4].set_high()?; | ||||
|  | ||||
|                     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, | ||||
|                             0 => V3Constants::SENSOR_A_1, | ||||
|                             1 => V3Constants::SENSOR_A_2, | ||||
|                             2 => V3Constants::SENSOR_A_3, | ||||
|                             3 => V3Constants::SENSOR_A_4, | ||||
|                             4 => V3Constants::SENSOR_A_5, | ||||
|                             5 => V3Constants::SENSOR_A_6, | ||||
|                             6 => V3Constants::SENSOR_A_7, | ||||
|                             7 => V3Constants::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, | ||||
|                             0 => V3Constants::SENSOR_B_1, | ||||
|                             1 => V3Constants::SENSOR_B_2, | ||||
|                             2 => V3Constants::SENSOR_B_3, | ||||
|                             3 => V3Constants::SENSOR_B_4, | ||||
|                             4 => V3Constants::SENSOR_B_5, | ||||
|                             5 => V3Constants::SENSOR_B_6, | ||||
|                             6 => V3Constants::SENSOR_B_7, | ||||
|                             7 => V3Constants::SENSOR_B_8, | ||||
|                             _ => bail!("Invalid plant id {}", plant), | ||||
|                         }, | ||||
|                     }; | ||||
|  | ||||
|  | ||||
|                     let is_bit_set = |b: u8| -> bool { sensor_channel & (1 << b) != 0 }; | ||||
|                     let pin_0 = &mut shift_register.decompose()[MS_0]; | ||||
|                     let pin_1 = &mut shift_register.decompose()[MS_1]; | ||||
|                     let pin_2 = &mut shift_register.decompose()[MS_2]; | ||||
|                     let pin_3 = &mut shift_register.decompose()[MS_3]; | ||||
|                     let pin_0 = &mut shift_register.decompose()[V3Constants::MS_0]; | ||||
|                     let pin_1 = &mut shift_register.decompose()[V3Constants::MS_1]; | ||||
|                     let pin_2 = &mut shift_register.decompose()[V3Constants::MS_2]; | ||||
|                     let pin_3 = &mut shift_register.decompose()[V3Constants::MS_3]; | ||||
|                     if is_bit_set(0) { | ||||
|                         pin_0.set_high()?; | ||||
|                     } else { | ||||
| @@ -1056,8 +1072,8 @@ impl BoardInteraction for HAL<'_> { | ||||
|                         pin_3.set_low()?; | ||||
|                     } | ||||
|  | ||||
|                     shift_register.decompose()[MS_4].set_low()?; | ||||
|                     shift_register.decompose()[SENSOR_ON].set_high()?; | ||||
|                     shift_register.decompose()[V3Constants::MS_4].set_low()?; | ||||
|                     shift_register.decompose()[V3Constants::SENSOR_ON].set_high()?; | ||||
|  | ||||
|                     let delay = Delay::new_default(); | ||||
|                     let measurement = 100; // TODO what is this scaling factor? what is its purpose? | ||||
| @@ -1068,8 +1084,8 @@ impl BoardInteraction for HAL<'_> { | ||||
|                     signal_counter.counter_resume()?; | ||||
|                     delay.delay_ms(measurement); | ||||
|                     signal_counter.counter_pause()?; | ||||
|                     shift_register.decompose()[MS_4].set_high()?; | ||||
|                     shift_register.decompose()[SENSOR_ON].set_low()?; | ||||
|                     shift_register.decompose()[V3Constants::MS_4].set_high()?; | ||||
|                     shift_register.decompose()[V3Constants::SENSOR_ON].set_low()?; | ||||
|                     delay.delay_ms(10); | ||||
|                     let unscaled = signal_counter.get_counter_value()? as i32; | ||||
|                     let hz = unscaled as f32 * factor; | ||||
| @@ -1088,6 +1104,91 @@ impl BoardInteraction for HAL<'_> { | ||||
|                 let median = results[mid]; | ||||
|                 Ok(median) | ||||
|             }, | ||||
|             V4 {sensor_expander, signal_counter, ..} => { | ||||
|                 let mut results = [0_f32; REPEAT_MOIST_MEASURE]; | ||||
|                 for repeat in 0..REPEAT_MOIST_MEASURE { | ||||
|                     signal_counter.counter_pause()?; | ||||
|                     signal_counter.counter_clear()?; | ||||
|  | ||||
|  | ||||
|                     const MS0: u8 = 1_u8; | ||||
|                     const MS1: u8 = 0_u8; | ||||
|                     const MS2: u8 = 3_u8; | ||||
|                     const MS3: u8 = 4_u8; | ||||
|                     const MS4: u8 = 2_u8; | ||||
|                     const SENSOR_ON: u8 = 5_u8; | ||||
|                     //Disable all | ||||
|                     sensor_expander.pin_set_high(GPIOBank::Bank0, MS4)?; | ||||
|  | ||||
|                     let sensor_channel = match sensor { | ||||
|                         Sensor::A =>{ | ||||
|                             plant as u32 | ||||
|                         }, | ||||
|                         Sensor::B => { | ||||
|                             (15 - plant) as u32 | ||||
|                         }, | ||||
|                     }; | ||||
|  | ||||
|  | ||||
|  | ||||
|                     let is_bit_set = |b: u8| -> bool { sensor_channel & (1 << b) != 0 }; | ||||
|                     if is_bit_set(0) { | ||||
|                         sensor_expander.pin_set_high(GPIOBank::Bank0, MS0)?; | ||||
|                     } else { | ||||
|                         sensor_expander.pin_set_low(GPIOBank::Bank0, MS0)?; | ||||
|                     } | ||||
|                     if is_bit_set(1) { | ||||
|                         sensor_expander.pin_set_high(GPIOBank::Bank0, MS1)?; | ||||
|                     } else { | ||||
|                         sensor_expander.pin_set_low(GPIOBank::Bank0, MS1)?; | ||||
|                     } | ||||
|                     if is_bit_set(2) { | ||||
|                         sensor_expander.pin_set_high(GPIOBank::Bank0, MS2)?; | ||||
|                     } else { | ||||
|                         sensor_expander.pin_set_low(GPIOBank::Bank0, MS2)?; | ||||
|                     } | ||||
|                     if is_bit_set(3) { | ||||
|                         sensor_expander.pin_set_high(GPIOBank::Bank0, MS3)?; | ||||
|                     } else { | ||||
|                         sensor_expander.pin_set_low(GPIOBank::Bank0, MS3)?; | ||||
|                     } | ||||
|  | ||||
|                     sensor_expander.pin_set_low(GPIOBank::Bank0, MS4)?; | ||||
|                     sensor_expander.pin_set_high(GPIOBank::Bank0, SENSOR_ON)?; | ||||
|  | ||||
|                     let delay = Delay::new_default(); | ||||
|                     let measurement = 100; // TODO what is this scaling factor? what is its purpose? | ||||
|                     let factor = 1000f32 / measurement as f32; | ||||
|  | ||||
|                     //give some time to stabilize | ||||
|                     delay.delay_ms(10); | ||||
|                     signal_counter.counter_resume()?; | ||||
|                     delay.delay_ms(measurement); | ||||
|                     signal_counter.counter_pause()?; | ||||
|                     sensor_expander.pin_set_high(GPIOBank::Bank0, MS4)?; | ||||
|                     sensor_expander.pin_set_low(GPIOBank::Bank0, SENSOR_ON)?; | ||||
|                     sensor_expander.pin_set_low(GPIOBank::Bank0, MS0); | ||||
|                     sensor_expander.pin_set_low(GPIOBank::Bank0, MS1); | ||||
|                     sensor_expander.pin_set_low(GPIOBank::Bank0, MS2); | ||||
|                     sensor_expander.pin_set_low(GPIOBank::Bank0, MS3); | ||||
|                     delay.delay_ms(10); | ||||
|                     let unscaled = signal_counter.get_counter_value()? as i32; | ||||
|                     let hz = unscaled as f32 * factor; | ||||
|                     log( | ||||
|                         LogMessage::RawMeasure, | ||||
|                         unscaled as u32, | ||||
|                         hz as u32, | ||||
|                         &plant.to_string(), | ||||
|                         &format!("{sensor:?}"), | ||||
|                     ); | ||||
|                     results[repeat] = hz; | ||||
|                 } | ||||
|                 results.sort_by(|a, b| a.partial_cmp(b).unwrap()); // floats don't seem to implement total_ord | ||||
|  | ||||
|                 let mid = results.len() / 2; | ||||
|                 let median = results[mid]; | ||||
|                 Ok(median) | ||||
|             } | ||||
|             _ => { | ||||
|                 bail!("Not implemented for this board") | ||||
|             } | ||||
| @@ -1534,12 +1635,12 @@ pub trait BoardInteraction { | ||||
|     fn set_low_voltage_in_cycle(&mut self); | ||||
|     fn clear_low_voltage_in_cycle(&mut self); | ||||
|     fn light(&mut self, enable: bool) -> Result<()>; | ||||
|     fn pump(&self, plant: usize, enable: bool) -> Result<()>; | ||||
|     fn pump(&mut self, plant: usize, enable: bool) -> Result<()>; | ||||
|     fn last_pump_time(&self, plant: usize) -> Option<DateTime<Utc>>; | ||||
|     fn store_last_pump_time(&mut self, plant: usize, time: DateTime<Utc>); | ||||
|     fn store_consecutive_pump_count(&mut self, plant: usize, count: u32); | ||||
|     fn consecutive_pump_count(&mut self, plant: usize) -> u32; | ||||
|     fn fault(&self, plant: usize, enable: bool) -> Result<()>; | ||||
|     fn fault(&mut self, plant: usize, enable: bool) -> Result<()>; | ||||
|     fn low_voltage_in_cycle(&mut self) -> bool; | ||||
|     fn any_pump(&mut self, enable: bool) -> Result<()>; | ||||
|     fn time(&mut self) -> Result<DateTime<Utc>>; | ||||
| @@ -1771,8 +1872,7 @@ impl PlantHal { | ||||
|         let config = esp.get_config(); | ||||
|         let hal = match config { | ||||
|             Result::Ok(config) => { | ||||
|                 let board_hal : BoardHal = match config.board_hardware { | ||||
|  | ||||
|                 let board_hal : BoardHal = match config.hardware.board { | ||||
|                     BoardVersion::INITIAL => { | ||||
|                         let mut general_fault = PinDriver::input_output(free_pins.gpio6.downgrade())?; | ||||
|                         general_fault.set_pull(Pull::Floating)?; | ||||
| @@ -1787,7 +1887,7 @@ impl PlantHal { | ||||
|                     BoardVersion::V4 => {PlantHal::create_v4(free_pins)?} | ||||
|                 }; | ||||
|  | ||||
|                 let battery_monitor : BatteryMonitor = match config.battery_hardware { | ||||
|                 let battery_monitor : BatteryMonitor = match config.hardware.battery { | ||||
|                     BatteryBoardVersion::Disabled => { BatteryMonitor::Disabled {}} | ||||
|                     BatteryBoardVersion::BQ34Z100G1 => { | ||||
|                         let mut battery_driver = Bq34z100g1Driver { | ||||
| @@ -1849,15 +1949,124 @@ impl PlantHal { | ||||
|     } | ||||
|  | ||||
|     fn create_v4(peripherals: FreePeripherals) -> Result<BoardHal<'static>> { | ||||
|         let mut awake = PinDriver::output(peripherals.gpio15.downgrade())?; | ||||
|         awake.set_high()?; | ||||
|  | ||||
|         let mut general_fault = PinDriver::input_output(peripherals.gpio6.downgrade())?; | ||||
|         general_fault.set_pull(Pull::Floating)?; | ||||
|         general_fault.set_low()?; | ||||
|  | ||||
|  | ||||
|         //temp remove me | ||||
|         general_fault.set_high()?; | ||||
|  | ||||
|         bail!("not implemented"); | ||||
|         println!("Init rtc driver"); | ||||
|         let mut rtc = Ds323x::new_ds3231(MutexDevice::new(&I2C_DRIVER)); | ||||
|  | ||||
|         println!("Init rtc eeprom driver"); | ||||
|         let mut eeprom = { | ||||
|             Eeprom24x::new_24x32( | ||||
|                 MutexDevice::new(&I2C_DRIVER), | ||||
|                 SlaveAddr::Alternative(true, true, true), | ||||
|             ) | ||||
|         }; | ||||
|  | ||||
|         let mut one_wire_pin = PinDriver::input_output_od(peripherals.gpio18.downgrade())?; | ||||
|         one_wire_pin.set_pull(Pull::Floating)?; | ||||
|  | ||||
|         let one_wire_bus = OneWire::new(one_wire_pin) | ||||
|             .map_err(|err| -> anyhow::Error { anyhow!("Missing attribute: {:?}", err) })?; | ||||
|  | ||||
|  | ||||
|         let rtc_time = rtc.datetime(); | ||||
|         match rtc_time { | ||||
|             OkStd(tt) => { | ||||
|                 println!("Rtc Module reports time at UTC {}", tt); | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 println!("Rtc Module could not be read {:?}", err); | ||||
|             } | ||||
|         } | ||||
|         match eeprom.read_byte(0) { | ||||
|             OkStd(byte) => { | ||||
|                 println!("Read first byte with status {}", byte); | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 println!("Eeprom could not read first byte {:?}", err); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         let mut signal_counter = PcntDriver::new( | ||||
|             peripherals.pcnt0, | ||||
|             Some(peripherals.gpio22), | ||||
|             Option::<AnyInputPin>::None, | ||||
|             Option::<AnyInputPin>::None, | ||||
|             Option::<AnyInputPin>::None, | ||||
|         )?; | ||||
|  | ||||
|         signal_counter.channel_config( | ||||
|             PcntChannel::Channel0, | ||||
|             PinIndex::Pin0, | ||||
|             PinIndex::Pin1, | ||||
|             &PcntChannelConfig { | ||||
|                 lctrl_mode: PcntControlMode::Keep, | ||||
|                 hctrl_mode: PcntControlMode::Keep, | ||||
|                 pos_mode: PcntCountMode::Increment, | ||||
|                 neg_mode: PcntCountMode::Hold, | ||||
|                 counter_h_lim: i16::MAX, | ||||
|                 counter_l_lim: 0, | ||||
|             }, | ||||
|         )?; | ||||
|  | ||||
|         let adc_config = AdcChannelConfig { | ||||
|             attenuation: attenuation::DB_11, | ||||
|             resolution: Resolution::Resolution12Bit, | ||||
|             calibration: esp_idf_hal::adc::oneshot::config::Calibration::Curve, | ||||
|         }; | ||||
|         let tank_driver = AdcDriver::new(peripherals.adc1)?; | ||||
|         let tank_channel: AdcChannelDriver<Gpio5, AdcDriver<esp_idf_hal::adc::ADC1>> = | ||||
|             AdcChannelDriver::new(tank_driver, peripherals.gpio5, &adc_config)?; | ||||
|  | ||||
|         let mut solar_is_day = PinDriver::input(peripherals.gpio7.downgrade())?; | ||||
|         solar_is_day.set_pull(Pull::Floating)?; | ||||
|  | ||||
|         let mut light = PinDriver::input_output(peripherals.gpio10.downgrade())?; | ||||
|         light.set_pull(Pull::Floating)?; | ||||
|  | ||||
|         let mut tank_power = PinDriver::input_output(peripherals.gpio11.downgrade())?; | ||||
|         tank_power.set_pull(Pull::Floating)?; | ||||
|  | ||||
|  | ||||
|         let mut pump_expander = Pca9535Immediate::new(MutexDevice::new(&I2C_DRIVER), 32); | ||||
|  | ||||
|         //todo error handing if init error | ||||
|         for pin in 0..8{ | ||||
|             let _ = pump_expander.pin_into_output(GPIOBank::Bank0, pin); | ||||
|             let _ = pump_expander.pin_into_output(GPIOBank::Bank1, pin); | ||||
|             let _ = pump_expander.pin_set_low(GPIOBank::Bank0, pin); | ||||
|             let _ = pump_expander.pin_set_low(GPIOBank::Bank1, pin); | ||||
|         } | ||||
|  | ||||
|         let mut sensor_expander = Pca9535Immediate::new(MutexDevice::new(&I2C_DRIVER), 34); | ||||
|         for pin in 0..8{ | ||||
|             let _ = sensor_expander.pin_into_output(GPIOBank::Bank0, pin); | ||||
|             let _ = sensor_expander.pin_into_output(GPIOBank::Bank1, pin); | ||||
|             let _ = sensor_expander.pin_set_low(GPIOBank::Bank0, pin); | ||||
|             let _ = sensor_expander.pin_set_low(GPIOBank::Bank1, pin); | ||||
|         } | ||||
|  | ||||
|         Ok(V4 { | ||||
|             tank_channel, | ||||
|             solar_is_day, | ||||
|             signal_counter, | ||||
|             light, | ||||
|             tank_power, | ||||
|             one_wire_bus, | ||||
|             rtc, | ||||
|             eeprom, | ||||
|             general_fault, | ||||
|             pump_expander, | ||||
|             sensor_expander | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn create_v3(peripherals: FreePeripherals) -> Result<BoardHal<'static>> { | ||||
| @@ -1879,16 +2088,16 @@ impl PlantHal { | ||||
|         let charging = &mut shift_register.decompose()[CHARGING]; | ||||
|         charging.set_high()?; | ||||
|  | ||||
|         let ms0 = &mut shift_register.decompose()[MS_0]; | ||||
|         let ms0 = &mut shift_register.decompose()[V3Constants::MS_0]; | ||||
|         ms0.set_low()?; | ||||
|         let ms1 = &mut shift_register.decompose()[MS_1]; | ||||
|         let ms1 = &mut shift_register.decompose()[V3Constants::MS_1]; | ||||
|         ms1.set_low()?; | ||||
|         let ms2 = &mut shift_register.decompose()[MS_2]; | ||||
|         let ms2 = &mut shift_register.decompose()[V3Constants::MS_2]; | ||||
|         ms2.set_low()?; | ||||
|         let ms3 = &mut shift_register.decompose()[MS_3]; | ||||
|         let ms3 = &mut shift_register.decompose()[V3Constants::MS_3]; | ||||
|         ms3.set_low()?; | ||||
|  | ||||
|         let ms4 = &mut shift_register.decompose()[MS_4]; | ||||
|         let ms4 = &mut shift_register.decompose()[V3Constants::MS_4]; | ||||
|         ms4.set_high()?; | ||||
|  | ||||
|         println!("Init battery driver"); | ||||
|   | ||||
| @@ -216,6 +216,7 @@ fn set_config( | ||||
| ) -> Result<Option<std::string::String>, anyhow::Error> { | ||||
|     let all = read_up_to_bytes_from_request(request, Some(3072))?; | ||||
|     let config: PlantControllerConfig = serde_json::from_slice(&all)?; | ||||
|  | ||||
|     let mut board = BOARD_ACCESS.lock().unwrap(); | ||||
|     board.esp.set_config(&config)?; | ||||
|  | ||||
| @@ -525,7 +526,7 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> { | ||||
|     server | ||||
|         .fn_handler("/file", Method::Post, move |mut request| { | ||||
|             let filename = query_param(request.uri(), "filename").unwrap(); | ||||
|             let lock = BOARD_ACCESS.lock().unwrap(); | ||||
|             let mut lock = BOARD_ACCESS.lock().unwrap(); | ||||
|             let file_handle = lock.esp.get_file_handle(&filename, true); | ||||
|             match file_handle { | ||||
|                 //TODO get free filesystem size, check against during write if not to large | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| interface LogArray  extends Array<LogEntry>{} | ||||
| export interface LogArray  extends Array<LogEntry>{} | ||||
|  | ||||
| interface LogEntry { | ||||
| export interface LogEntry { | ||||
|   timestamp: string, | ||||
|   message_id: number, | ||||
|   a: number, | ||||
| @@ -9,27 +9,28 @@ interface LogEntry { | ||||
|   txt_long: string | ||||
| } | ||||
|  | ||||
| interface LogLocalisation extends Array<LogLocalisationEntry>{} | ||||
| export interface LogLocalisation extends Array<LogLocalisationEntry>{} | ||||
|  | ||||
| interface LogLocalisationEntry { | ||||
| export interface LogLocalisationEntry { | ||||
|   msg_type: string, | ||||
|   message: string | ||||
| } | ||||
|  | ||||
| interface BackupHeader { | ||||
| export interface BackupHeader { | ||||
|   timestamp: string, | ||||
|   size: number | ||||
| } | ||||
|  | ||||
| interface NetworkConfig { | ||||
| export interface NetworkConfig { | ||||
|   ap_ssid: string, | ||||
|   ssid: string, | ||||
|   password: string, | ||||
|   mqtt_url: string, | ||||
|   base_topic: string | ||||
|   base_topic: string, | ||||
|   max_wait: number | ||||
| } | ||||
|  | ||||
| interface FileList { | ||||
| export interface FileList { | ||||
|   total: number, | ||||
|   used: number, | ||||
|   files: FileInfo[], | ||||
| @@ -37,12 +38,12 @@ interface FileList { | ||||
|   iter_error: string, | ||||
| } | ||||
|  | ||||
| interface FileInfo{ | ||||
| export interface FileInfo{ | ||||
|   filename: string, | ||||
|   size: number, | ||||
| } | ||||
|  | ||||
| interface NightLampConfig { | ||||
| export interface NightLampConfig { | ||||
|   enabled: boolean, | ||||
|   night_lamp_hour_start: number, | ||||
|   night_lamp_hour_end: number, | ||||
| @@ -51,11 +52,11 @@ interface NightLampConfig { | ||||
|   low_soc_restore: number | ||||
| } | ||||
|  | ||||
| interface NightLampCommand { | ||||
| export interface NightLampCommand { | ||||
|   active: boolean | ||||
| } | ||||
|  | ||||
| interface TankConfig { | ||||
| export interface TankConfig { | ||||
|   tank_sensor_enabled: boolean, | ||||
|   tank_allow_pumping_if_sensor_error: boolean, | ||||
|   tank_useable_ml: number, | ||||
| @@ -64,7 +65,26 @@ interface TankConfig { | ||||
|   tank_full_percent: number, | ||||
| } | ||||
|  | ||||
| interface PlantControllerConfig { | ||||
|  | ||||
| export enum BatteryBoardVersion { | ||||
|   Disabled = "Disabled", | ||||
|   BQ34Z100G1 = "BQ34Z100G1", | ||||
|   WchI2cSlave = "WchI2cSlave" | ||||
| } | ||||
| export enum BoardVersion{ | ||||
|     INITIAL = "INITIAL", | ||||
|     V3 = "V3", | ||||
|     V4 = "V4" | ||||
| } | ||||
|  | ||||
| export interface BoardHardware { | ||||
|   board: BoardVersion, | ||||
|   battery: BatteryBoardVersion, | ||||
| } | ||||
|  | ||||
| export interface PlantControllerConfig { | ||||
|   hardware: BoardHardware, | ||||
|  | ||||
|   network: NetworkConfig, | ||||
|   tank: TankConfig, | ||||
|   night_lamp: NightLampConfig, | ||||
| @@ -72,7 +92,7 @@ interface PlantControllerConfig { | ||||
|   timezone?: string, | ||||
| } | ||||
|  | ||||
| interface PlantConfig { | ||||
| export interface PlantConfig { | ||||
|   mode: string, | ||||
|   target_moisture: number, | ||||
|   pump_time_s: number, | ||||
| @@ -88,35 +108,35 @@ interface PlantConfig { | ||||
| } | ||||
|  | ||||
|  | ||||
| interface SSIDList { | ||||
| export interface SSIDList { | ||||
|   ssids: [string] | ||||
| } | ||||
|  | ||||
| interface TestPump { | ||||
| export interface TestPump { | ||||
|   pump: number | ||||
| } | ||||
|  | ||||
| interface SetTime { | ||||
| export interface SetTime { | ||||
|   time: string | ||||
| } | ||||
|  | ||||
| interface GetTime { | ||||
| export interface GetTime { | ||||
|   rtc: string, | ||||
|   native: string | ||||
| } | ||||
|  | ||||
| interface Moistures { | ||||
| export interface Moistures { | ||||
|   moisture_a: [string], | ||||
|   moisture_b: [string], | ||||
| } | ||||
|  | ||||
| interface VersionInfo { | ||||
| export interface VersionInfo { | ||||
|   git_hash: string, | ||||
|   build_time: string, | ||||
|   partition: string | ||||
| } | ||||
|  | ||||
| interface BatteryState { | ||||
| export interface BatteryState { | ||||
|   temperature: string | ||||
|   voltage_milli_volt: string, | ||||
|   current_milli_ampere: string, | ||||
| @@ -127,7 +147,7 @@ interface BatteryState { | ||||
|   state_of_health: string | ||||
| } | ||||
|  | ||||
| interface TankInfo { | ||||
| export interface TankInfo { | ||||
|   /// is there enough water in the tank | ||||
|   enough_water: boolean, | ||||
|   /// warning that water needs to be refilled soon | ||||
| @@ -145,4 +165,4 @@ interface TankInfo { | ||||
|   /// water temperature | ||||
|   water_temp: number | null, | ||||
|   temp_sensor_error: string | null | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {BatteryState} from "./api"; | ||||
|  | ||||
| export class BatteryView{ | ||||
|     voltage_milli_volt: HTMLSpanElement; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import {Controller} from "./main"; | ||||
|  | ||||
| import {FileInfo, FileList} from "./api"; | ||||
| const regex = /[^a-zA-Z0-9_.]/g; | ||||
|  | ||||
| function sanitize(str:string){ | ||||
|   | ||||
							
								
								
									
										20
									
								
								rust/src_webpack/src/hardware.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								rust/src_webpack/src/hardware.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| <style> | ||||
|   .boardkey{ | ||||
|     min-width: 200px; | ||||
|   } | ||||
|   .boardvalue{ | ||||
|     flex-grow: 1; | ||||
|   } | ||||
| </style> | ||||
|  | ||||
| <div class="subtitle">Hardware:</div> | ||||
| <div class="flexcontainer">  | ||||
|   <div class="boardkey">BoardRevision</div> | ||||
|     <select class="boardvalue" id="hardware_board_value"> | ||||
|     </select> | ||||
| </div> | ||||
| <div class="flexcontainer" style="text-decoration-line: line-through;"> | ||||
|     <div class="boardkey">BatteryMonitor</div> | ||||
|     <select class="boardvalue" id="hardware_battery_value"> | ||||
|     </select> | ||||
| </div> | ||||
							
								
								
									
										45
									
								
								rust/src_webpack/src/hardware.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								rust/src_webpack/src/hardware.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {BatteryBoardVersion, BoardHardware, BoardVersion} from "./api"; | ||||
|  | ||||
| export class HardwareConfigView { | ||||
|     private readonly hardware_board_value: HTMLSelectElement; | ||||
|     private readonly hardware_battery_value: HTMLSelectElement; | ||||
|     constructor(controller:Controller){ | ||||
|       (document.getElementById("hardwareview") as HTMLElement).innerHTML = require('./hardware.html') as string; | ||||
|  | ||||
|       this.hardware_board_value = document.getElementById("hardware_board_value") as HTMLSelectElement; | ||||
|       this.hardware_board_value.onchange = controller.configChanged | ||||
|  | ||||
|       Object.keys(BoardVersion).forEach(version => { | ||||
|         let option = document.createElement("option"); | ||||
|         if (version == BoardVersion.INITIAL.toString()){ | ||||
|           option.selected = true | ||||
|         } | ||||
|         option.innerText = version.toString(); | ||||
|         this.hardware_board_value.appendChild(option); | ||||
|       }) | ||||
|  | ||||
|       this.hardware_battery_value = document.getElementById("hardware_battery_value") as HTMLSelectElement; | ||||
|       this.hardware_battery_value.onchange = controller.configChanged | ||||
|       Object.keys(BatteryBoardVersion).forEach(version => { | ||||
|         let option = document.createElement("option"); | ||||
|         if (version == BatteryBoardVersion.Disabled.toString()){ | ||||
|           option.selected = true | ||||
|         } | ||||
|         option.innerText = version.toString(); | ||||
|         this.hardware_battery_value.appendChild(option); | ||||
|       }) | ||||
|     } | ||||
|    | ||||
|     setConfig(hardware: BoardHardware) { | ||||
|       this.hardware_board_value.value = hardware.board.toString() | ||||
|       this.hardware_battery_value.value = hardware.battery.toString() | ||||
|     } | ||||
|    | ||||
|     getConfig(): BoardHardware { | ||||
|       return { | ||||
|         board :  BoardVersion[this.hardware_board_value.value as keyof typeof BoardVersion], | ||||
|         battery :  BatteryBoardVersion[this.hardware_battery_value.value as keyof typeof BatteryBoardVersion], | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {LogArray, LogLocalisation} from "./api"; | ||||
|  | ||||
| export class LogView { | ||||
|   private readonly logpanel: HTMLElement; | ||||
|   | ||||
| @@ -138,6 +138,10 @@ | ||||
|  | ||||
|  | ||||
| <div class="container-xl"> | ||||
|   <div style="display:flex; flex-wrap: wrap;"> | ||||
|     <div id="hardwareview" class="subcontainer"></div> | ||||
|   </div> | ||||
|  | ||||
|   <div style="display:flex; flex-wrap: wrap;"> | ||||
|     <div id="firmwareview" class="subcontainer"> | ||||
|     </div> | ||||
|   | ||||
| @@ -17,6 +17,19 @@ import { OTAView } from "./ota"; | ||||
| import { BatteryView } from "./batteryview"; | ||||
| import { FileView } from './fileview'; | ||||
| import { LogView } from './log'; | ||||
| import {HardwareConfigView} from "./hardware"; | ||||
| import { | ||||
|   BackupHeader, | ||||
|   BatteryState, | ||||
|   GetTime, LogArray, LogLocalisation, | ||||
|   Moistures, | ||||
|   NightLampCommand, | ||||
|   PlantControllerConfig, | ||||
|   SetTime, SSIDList, TankInfo, | ||||
|   TestPump, | ||||
|   VersionInfo, | ||||
|   FileList | ||||
| } from "./api"; | ||||
|  | ||||
| export class Controller { | ||||
|   loadTankInfo() : Promise<void> { | ||||
| @@ -66,7 +79,7 @@ export class Controller { | ||||
|   } | ||||
|  | ||||
|   populateTimezones(): Promise<void> { | ||||
|     return fetch('/timezones') | ||||
|     return fetch(PUBLIC_URL+'/timezones') | ||||
|         .then(response => response.json()) | ||||
|         .then(json => json as string[]) | ||||
|         .then(timezones => { | ||||
| @@ -268,6 +281,12 @@ export class Controller { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   selfTest(){ | ||||
|     fetch(PUBLIC_URL + "/boardtest", { | ||||
|       method: "POST" | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   testNightLamp(active: boolean){ | ||||
|     var body: NightLampCommand = { | ||||
|       active: active | ||||
| @@ -313,6 +332,7 @@ export class Controller { | ||||
|  | ||||
|   getConfig(): PlantControllerConfig { | ||||
|     return { | ||||
|       hardware: controller.hardwareView.getConfig(), | ||||
|       network: controller.networkView.getConfig(), | ||||
|       tank: controller.tankView.getConfig(), | ||||
|       night_lamp: controller.nightLampView.getConfig(), | ||||
| @@ -360,6 +380,7 @@ export class Controller { | ||||
|     this.nightLampView.setConfig(current.night_lamp); | ||||
|     this.plantViews.setConfig(current.plants); | ||||
|     this.timeView.setTimeZone(current.timezone); | ||||
|     this.hardwareView.setConfig(current.hardware); | ||||
|   } | ||||
|  | ||||
|   measure_moisture() { | ||||
| @@ -437,6 +458,7 @@ export class Controller { | ||||
|   readonly timeView: TimeView; | ||||
|   readonly plantViews: PlantViews; | ||||
|   readonly networkView: NetworkConfigView; | ||||
|   readonly hardwareView: HardwareConfigView; | ||||
|   readonly tankView: TankConfigView; | ||||
|   readonly nightLampView: NightLampView; | ||||
|   readonly submitView: SubmitView; | ||||
| @@ -457,6 +479,7 @@ export class Controller { | ||||
|     this.progressview = new ProgressView(this) | ||||
|     this.fileview = new FileView(this) | ||||
|     this.logView = new LogView(this) | ||||
|     this.hardwareView = new HardwareConfigView(this) | ||||
|     this.rebootBtn = document.getElementById("reboot") as HTMLButtonElement | ||||
|     this.rebootBtn.onclick = () => { | ||||
|       controller.reboot(); | ||||
| @@ -466,6 +489,10 @@ export class Controller { | ||||
|       controller.exit(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   selftest() { | ||||
|  | ||||
|   } | ||||
| } | ||||
| const controller = new Controller(); | ||||
| controller.progressview.removeProgress("rebooting"); | ||||
| @@ -505,9 +532,6 @@ executeTasksSequentially().then(r => { | ||||
|   controller.progressview.removeProgress("initial") | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| controller.progressview.removeProgress("rebooting"); | ||||
|  | ||||
| window.addEventListener("beforeunload", (event) => { | ||||
|   | ||||
| @@ -42,6 +42,11 @@ | ||||
|                 </datalist> | ||||
|                 <input class="basicnetworkkeyssid2" type="button" id="scan" value="Scan"> | ||||
|             </div> | ||||
|  | ||||
|             <div class="flexcontainer"> | ||||
|                 <label class="basicnetworkkey" for="max_wait">Max wait:</label> | ||||
|                 <input class="basicnetworkvalue" type="number" id="max_wait"> | ||||
|             </div> | ||||
|          | ||||
|             <div class="flexcontainer"> | ||||
|                 <label class="basicnetworkkey" for="ssid">Password:</label> | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {NetworkConfig, SSIDList} from "./api"; | ||||
|  | ||||
| export class NetworkConfigView { | ||||
|     setScanResult(ssidList: SSIDList) { | ||||
| @@ -14,6 +15,7 @@ export class NetworkConfigView { | ||||
|     private readonly password: HTMLInputElement; | ||||
|     private readonly mqtt_url: HTMLInputElement; | ||||
|     private readonly base_topic: HTMLInputElement; | ||||
|     private readonly max_wait: HTMLInputElement; | ||||
|     private readonly ssidlist: HTMLElement; | ||||
|      | ||||
|     constructor(controller: Controller, publicIp: string) { | ||||
| @@ -28,6 +30,9 @@ export class NetworkConfigView { | ||||
|       this.ssid.onchange = controller.configChanged | ||||
|       this.password = (document.getElementById("password") as HTMLInputElement); | ||||
|       this.password.onchange = controller.configChanged | ||||
|       this.max_wait = (document.getElementById("max_wait") as HTMLInputElement); | ||||
|       this.max_wait.onchange = controller.configChanged | ||||
|  | ||||
|       this.mqtt_url = document.getElementById("mqtt_url") as HTMLInputElement; | ||||
|       this.mqtt_url.onchange = controller.configChanged | ||||
|       this.base_topic = document.getElementById("base_topic") as HTMLInputElement; | ||||
| @@ -47,10 +52,12 @@ export class NetworkConfigView { | ||||
|       this.password.value = network.password; | ||||
|       this.mqtt_url.value = network.mqtt_url; | ||||
|       this.base_topic.value = network.base_topic; | ||||
|       this.max_wait.value = network.max_wait.toString(); | ||||
|     } | ||||
|      | ||||
|     getConfig(): NetworkConfig { | ||||
|       return { | ||||
|         max_wait: +this.max_wait.value, | ||||
|         ap_ssid: this.ap_ssid.value, | ||||
|         ssid: this.ssid.value ?? null, | ||||
|         password: this.password.value ?? null, | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {NightLampConfig} from "./api"; | ||||
|  | ||||
| export class NightLampView { | ||||
|     private readonly night_lamp_only_when_dark: HTMLInputElement; | ||||
|   | ||||
| @@ -37,5 +37,5 @@ | ||||
|     </form> | ||||
| </div> | ||||
| <div class="display:flex"> | ||||
|     <input style="margin-left: 16px; margin-top: 8px;" class="col-6" type="button" id="test" value="Self-Test"> | ||||
|     <button style="margin-left: 16px; margin-top: 8px;" class="col-6" type="button" id="test">Self-Test</button> | ||||
| </div> | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {VersionInfo} from "./api"; | ||||
|  | ||||
| export class OTAView { | ||||
|     readonly file1Upload: HTMLInputElement; | ||||
| @@ -9,6 +10,8 @@ export class OTAView { | ||||
|     constructor(controller: Controller) { | ||||
|         (document.getElementById("firmwareview") as HTMLElement).innerHTML = require("./ota.html") | ||||
|  | ||||
|         let test  = document.getElementById("test") as HTMLButtonElement; | ||||
|  | ||||
|         this.firmware_buildtime = document.getElementById("firmware_buildtime") as HTMLDivElement; | ||||
|         this.firmware_githash = document.getElementById("firmware_githash") as HTMLDivElement; | ||||
|         this.firmware_partition = document.getElementById("firmware_partition") as HTMLDivElement; | ||||
| @@ -24,6 +27,10 @@ export class OTAView { | ||||
|             } | ||||
|             controller.uploadNewFirmware(selectedFile); | ||||
|         }; | ||||
|  | ||||
|         test.onclick = () => { | ||||
|             controller.selftest(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     setVersion(versionInfo: VersionInfo) { | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| import {PlantConfig} from "./api"; | ||||
|  | ||||
| const PLANT_COUNT = 8; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {BackupHeader} from "./api"; | ||||
|  | ||||
| export class SubmitView { | ||||
|   json: HTMLDivElement; | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { Controller } from "./main"; | ||||
| import {TankConfig, TankInfo} from "./api"; | ||||
|  | ||||
| export class TankConfigView { | ||||
|     private readonly tank_useable_ml: HTMLInputElement; | ||||
|   | ||||
| @@ -9,7 +9,7 @@ console.log("Dev server is " + isDevServer); | ||||
| var host; | ||||
| if (isDevServer){ | ||||
|   //ensure no trailing / | ||||
|   host = 'http://192.168.251.37'; | ||||
|   host = 'http://192.168.71.1'; | ||||
| } else { | ||||
|   host = ''; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user