Refactor Battery State for more robustness against missing BatteryMonitor #17
| @@ -1,7 +1,7 @@ | |||||||
| use serde::{Deserialize, Serialize}; |  | ||||||
| use std::str::FromStr; |  | ||||||
| use crate::hal::PLANT_COUNT; | use crate::hal::PLANT_COUNT; | ||||||
| use crate::plant_state::PlantWateringMode; | use crate::plant_state::PlantWateringMode; | ||||||
|  | use serde::{Deserialize, Serialize}; | ||||||
|  | use std::str::FromStr; | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] | #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] | ||||||
| #[serde(default)] | #[serde(default)] | ||||||
| @@ -11,7 +11,7 @@ pub struct NetworkConfig { | |||||||
|     pub password: Option<heapless::String<64>>, |     pub password: Option<heapless::String<64>>, | ||||||
|     pub mqtt_url: Option<heapless::String<128>>, |     pub mqtt_url: Option<heapless::String<128>>, | ||||||
|     pub base_topic: Option<heapless::String<64>>, |     pub base_topic: Option<heapless::String<64>>, | ||||||
|     pub max_wait: u32 |     pub max_wait: u32, | ||||||
| } | } | ||||||
| impl Default for NetworkConfig { | impl Default for NetworkConfig { | ||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
| @@ -21,7 +21,7 @@ impl Default for NetworkConfig { | |||||||
|             password: None, |             password: None, | ||||||
|             mqtt_url: None, |             mqtt_url: None, | ||||||
|             base_topic: None, |             base_topic: None, | ||||||
|             max_wait: 10000 |             max_wait: 10000, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -77,14 +77,14 @@ pub enum BatteryBoardVersion{ | |||||||
|     #[default] |     #[default] | ||||||
|     Disabled, |     Disabled, | ||||||
|     BQ34Z100G1, |     BQ34Z100G1, | ||||||
|     WchI2cSlave |     WchI2cSlave, | ||||||
| } | } | ||||||
| #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] | #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] | ||||||
| pub enum BoardVersion { | pub enum BoardVersion { | ||||||
|     #[default] |     #[default] | ||||||
|     INITIAL, |     INITIAL, | ||||||
|     V3, |     V3, | ||||||
|     V4 |     V4, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] | #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | use crate::to_string; | ||||||
| use anyhow::bail; | use anyhow::bail; | ||||||
| use bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver}; | use bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver}; | ||||||
| use embedded_hal_bus::i2c::MutexDevice; | use embedded_hal_bus::i2c::MutexDevice; | ||||||
| @@ -6,7 +7,6 @@ use esp_idf_hal::i2c::{I2cDriver, I2cError}; | |||||||
| use measurements::Temperature; | use measurements::Temperature; | ||||||
| use serde::Serialize; | use serde::Serialize; | ||||||
| use std::result::Result::Ok as OkStd; | use std::result::Result::Ok as OkStd; | ||||||
| use crate::to_string; |  | ||||||
|  |  | ||||||
| pub trait BatteryInteraction { | pub trait BatteryInteraction { | ||||||
|     fn state_charge_percent(&mut self) -> anyhow::Result<u8>; |     fn state_charge_percent(&mut self) -> anyhow::Result<u8>; | ||||||
| @@ -31,19 +31,14 @@ pub struct BatteryState { | |||||||
|     state_of_health: String, |     state_of_health: String, | ||||||
|     temperature: String, |     temperature: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub enum BatteryMonitor<'a> { | pub enum BatteryMonitor<'a> { | ||||||
|     Disabled { |     Disabled {}, | ||||||
|  |  | ||||||
|     }, |  | ||||||
|     BQ34Z100G1 { |     BQ34Z100G1 { | ||||||
|         battery_driver: Bq34z100g1Driver<MutexDevice<'a, I2cDriver<'a>>, Delay> |         battery_driver: Bq34z100g1Driver<MutexDevice<'a, I2cDriver<'a>>, Delay>, | ||||||
|     }, |     }, | ||||||
|     WchI2cSlave { |     WchI2cSlave {}, | ||||||
|  |  | ||||||
| } | } | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| impl BatteryInteraction for BatteryMonitor<'_> { | impl BatteryInteraction for BatteryMonitor<'_> { | ||||||
|     fn state_charge_percent(&mut self) -> anyhow::Result<u8> { |     fn state_charge_percent(&mut self) -> anyhow::Result<u8> { | ||||||
| @@ -53,7 +48,7 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|                     OkStd(r) => anyhow::Ok(r), |                     OkStd(r) => anyhow::Ok(r), | ||||||
|                     Err(err) => bail!("Error reading SoC {:?}", err), |                     Err(err) => bail!("Error reading SoC {:?}", err), | ||||||
|                 } |                 } | ||||||
|             }, |             } | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             } |             } | ||||||
| @@ -70,10 +65,10 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|                     OkStd(r) => anyhow::Ok(r), |                     OkStd(r) => anyhow::Ok(r), | ||||||
|                     Err(err) => bail!("Error reading remaining_milli_ampere_hour {:?}", err), |                     Err(err) => bail!("Error reading remaining_milli_ampere_hour {:?}", err), | ||||||
|                 } |                 } | ||||||
|             }, |             } | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -86,10 +81,10 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|                     OkStd(r) => anyhow::Ok(r), |                     OkStd(r) => anyhow::Ok(r), | ||||||
|                     Err(err) => bail!("Error reading max_milli_ampere_hour {:?}", err), |                     Err(err) => bail!("Error reading max_milli_ampere_hour {:?}", err), | ||||||
|                 } |                 } | ||||||
|             }, |             } | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -102,10 +97,10 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|                     OkStd(r) => anyhow::Ok(r), |                     OkStd(r) => anyhow::Ok(r), | ||||||
|                     Err(err) => bail!("Error reading design_milli_ampere_hour {:?}", err), |                     Err(err) => bail!("Error reading design_milli_ampere_hour {:?}", err), | ||||||
|                 } |                 } | ||||||
|             }, |             } | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -113,15 +108,13 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|     } |     } | ||||||
|     fn voltage_milli_volt(&mut self) -> anyhow::Result<u16> { |     fn voltage_milli_volt(&mut self) -> anyhow::Result<u16> { | ||||||
|         match self { |         match self { | ||||||
|             BatteryMonitor::BQ34Z100G1 { battery_driver} => { |             BatteryMonitor::BQ34Z100G1 { battery_driver } => match battery_driver.voltage() { | ||||||
|                 match battery_driver.voltage() { |  | ||||||
|                 OkStd(r) => anyhow::Ok(r), |                 OkStd(r) => anyhow::Ok(r), | ||||||
|                 Err(err) => bail!("Error reading voltage_milli_volt {:?}", err), |                 Err(err) => bail!("Error reading voltage_milli_volt {:?}", err), | ||||||
|                 } |  | ||||||
|             }, |             }, | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -134,10 +127,10 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|                     OkStd(r) => anyhow::Ok(r), |                     OkStd(r) => anyhow::Ok(r), | ||||||
|                     Err(err) => bail!("Error reading average_current_milli_ampere {:?}", err), |                     Err(err) => bail!("Error reading average_current_milli_ampere {:?}", err), | ||||||
|                 } |                 } | ||||||
|             }, |             } | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -145,15 +138,13 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|     } |     } | ||||||
|     fn cycle_count(&mut self) -> anyhow::Result<u16> { |     fn cycle_count(&mut self) -> anyhow::Result<u16> { | ||||||
|         match self { |         match self { | ||||||
|             BatteryMonitor::BQ34Z100G1 { battery_driver} => { |             BatteryMonitor::BQ34Z100G1 { battery_driver } => match battery_driver.cycle_count() { | ||||||
|                 match battery_driver.cycle_count() { |  | ||||||
|                 OkStd(r) => anyhow::Ok(r), |                 OkStd(r) => anyhow::Ok(r), | ||||||
|                 Err(err) => bail!("Error reading cycle_count {:?}", err), |                 Err(err) => bail!("Error reading cycle_count {:?}", err), | ||||||
|                 } |  | ||||||
|             }, |             }, | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -166,10 +157,10 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|                     OkStd(r) => anyhow::Ok(r as u8), |                     OkStd(r) => anyhow::Ok(r as u8), | ||||||
|                     Err(err) => bail!("Error reading state_health_percent {:?}", err), |                     Err(err) => bail!("Error reading state_health_percent {:?}", err), | ||||||
|                 } |                 } | ||||||
|             }, |             } | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -177,15 +168,13 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|     } |     } | ||||||
|     fn bat_temperature(&mut self) -> anyhow::Result<u16> { |     fn bat_temperature(&mut self) -> anyhow::Result<u16> { | ||||||
|         match self { |         match self { | ||||||
|             BatteryMonitor::BQ34Z100G1 { battery_driver} => { |             BatteryMonitor::BQ34Z100G1 { battery_driver } => match battery_driver.temperature() { | ||||||
|                 match battery_driver.temperature() { |  | ||||||
|                 OkStd(r) => anyhow::Ok(r), |                 OkStd(r) => anyhow::Ok(r), | ||||||
|                 Err(err) => bail!("Error reading bat_temperature {:?}", err), |                 Err(err) => bail!("Error reading bat_temperature {:?}", err), | ||||||
|                 } |  | ||||||
|             }, |             }, | ||||||
|             BatteryMonitor::WchI2cSlave { .. } => { |             BatteryMonitor::WchI2cSlave { .. } => { | ||||||
|                 bail!("Not implemented") |                 bail!("Not implemented") | ||||||
|             }, |             } | ||||||
|             &mut BatteryMonitor::Disabled {} => { |             &mut BatteryMonitor::Disabled {} => { | ||||||
|                 bail!("Battery monitor is disabled") |                 bail!("Battery monitor is disabled") | ||||||
|             } |             } | ||||||
| @@ -205,12 +194,8 @@ impl BatteryInteraction for BatteryMonitor<'_> { | |||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         match serde_json::to_string(&bat) { |         match serde_json::to_string(&bat) { | ||||||
|             Ok(state) => { |             Ok(state) => state, | ||||||
|                 state |             Err(err) => format!("{:?}", err).to_owned(), | ||||||
|             } |  | ||||||
|             Err(err) => { |  | ||||||
|                 format!("{:?}", err).to_owned() |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,10 +6,15 @@ use anyhow::{anyhow, bail, Context}; | |||||||
| use chrono::{DateTime, Utc}; | use chrono::{DateTime, Utc}; | ||||||
| use embedded_svc::ipv4::IpInfo; | use embedded_svc::ipv4::IpInfo; | ||||||
| use embedded_svc::mqtt::client::QoS::{AtLeastOnce, ExactlyOnce}; | use embedded_svc::mqtt::client::QoS::{AtLeastOnce, ExactlyOnce}; | ||||||
| use embedded_svc::wifi::{AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration}; | use embedded_svc::wifi::{ | ||||||
|  |     AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration, | ||||||
|  | }; | ||||||
| use esp_idf_hal::delay::Delay; | use esp_idf_hal::delay::Delay; | ||||||
| use esp_idf_hal::gpio::{Level, PinDriver}; | use esp_idf_hal::gpio::{Level, PinDriver}; | ||||||
| use esp_idf_svc::mqtt::client::{EspMqttClient, LwtConfiguration, MqttClientConfiguration}; | use esp_idf_svc::mqtt::client::{EspMqttClient, LwtConfiguration, MqttClientConfiguration}; | ||||||
|  | use esp_idf_svc::sntp; | ||||||
|  | use esp_idf_svc::sntp::SyncStatus; | ||||||
|  | use esp_idf_svc::systime::EspSystemTime; | ||||||
| use esp_idf_svc::wifi::config::{ScanConfig, ScanType}; | use esp_idf_svc::wifi::config::{ScanConfig, ScanType}; | ||||||
| use esp_idf_svc::wifi::EspWifi; | use esp_idf_svc::wifi::EspWifi; | ||||||
| use esp_idf_sys::{esp_spiffs_info, vTaskDelay}; | use esp_idf_sys::{esp_spiffs_info, vTaskDelay}; | ||||||
| @@ -23,10 +28,6 @@ use std::str::FromStr; | |||||||
| use std::sync::atomic::AtomicBool; | use std::sync::atomic::AtomicBool; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| use esp_idf_svc::sntp; |  | ||||||
| use esp_idf_svc::sntp::SyncStatus; |  | ||||||
| use esp_idf_svc::systime::EspSystemTime; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #[link_section = ".rtc.data"] | #[link_section = ".rtc.data"] | ||||||
| static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT]; | static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT]; | ||||||
| @@ -37,7 +38,6 @@ static mut LOW_VOLTAGE_DETECTED: bool = false; | |||||||
| #[link_section = ".rtc.data"] | #[link_section = ".rtc.data"] | ||||||
| static mut RESTART_TO_CONF: bool = false; | static mut RESTART_TO_CONF: bool = false; | ||||||
|  |  | ||||||
|  |  | ||||||
| #[derive(Serialize, Debug)] | #[derive(Serialize, Debug)] | ||||||
| pub struct FileInfo { | pub struct FileInfo { | ||||||
|     filename: String, |     filename: String, | ||||||
| @@ -61,16 +61,15 @@ pub struct FileSystemSizeInfo { | |||||||
|  |  | ||||||
| pub struct MqttClient<'a> { | pub struct MqttClient<'a> { | ||||||
|     mqtt_client: EspMqttClient<'a>, |     mqtt_client: EspMqttClient<'a>, | ||||||
|     base_topic: heapless::String<64> |     base_topic: heapless::String<64>, | ||||||
| } | } | ||||||
| pub struct ESP<'a> { | pub struct ESP<'a> { | ||||||
|     pub(crate) mqtt_client: Option<MqttClient<'a>>, |     pub(crate) mqtt_client: Option<MqttClient<'a>>, | ||||||
|     pub(crate) wifi_driver: EspWifi<'a>, |     pub(crate) wifi_driver: EspWifi<'a>, | ||||||
|     pub(crate) boot_button: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, |     pub(crate) boot_button: PinDriver<'a, esp_idf_hal::gpio::AnyIOPin, esp_idf_hal::gpio::Input>, | ||||||
|     pub(crate) delay: Delay |     pub(crate) delay: Delay, | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| impl ESP<'_> { | impl ESP<'_> { | ||||||
|     const SPIFFS_PARTITION_NAME: &'static str = "storage"; |     const SPIFFS_PARTITION_NAME: &'static str = "storage"; | ||||||
|     const CONFIG_FILE: &'static str = "/spiffs/config.cfg"; |     const CONFIG_FILE: &'static str = "/spiffs/config.cfg"; | ||||||
| @@ -131,9 +130,7 @@ impl ESP<'_> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub(crate) fn low_voltage_in_cycle(&mut self) -> bool { |     pub(crate) fn low_voltage_in_cycle(&mut self) -> bool { | ||||||
|         unsafe { |         unsafe { LOW_VOLTAGE_DETECTED } | ||||||
|             LOW_VOLTAGE_DETECTED |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     pub(crate) fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) { |     pub(crate) fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) { | ||||||
|         unsafe { |         unsafe { | ||||||
| @@ -154,12 +151,8 @@ impl ESP<'_> { | |||||||
|  |  | ||||||
|     pub(crate) fn wifi_ap(&mut self) -> anyhow::Result<()> { |     pub(crate) fn wifi_ap(&mut self) -> anyhow::Result<()> { | ||||||
|         let ssid = match self.load_config() { |         let ssid = match self.load_config() { | ||||||
|             Ok(config) => { |             Ok(config) => config.network.ap_ssid.clone(), | ||||||
|                 config.network.ap_ssid.clone() |             Err(_) => heapless::String::from_str("PlantCtrl Emergency Mode").unwrap(), | ||||||
|             } |  | ||||||
|             Err(_) => { |  | ||||||
|                 heapless::String::from_str("PlantCtrl Emergency Mode").unwrap() |  | ||||||
|             } |  | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let apconfig = AccessPointConfiguration { |         let apconfig = AccessPointConfiguration { | ||||||
| @@ -168,17 +161,17 @@ impl ESP<'_> { | |||||||
|             ssid_hidden: false, |             ssid_hidden: false, | ||||||
|             ..Default::default() |             ..Default::default() | ||||||
|         }; |         }; | ||||||
|         self.wifi_driver.set_configuration(&Configuration::AccessPoint(apconfig))?; |         self.wifi_driver | ||||||
|  |             .set_configuration(&Configuration::AccessPoint(apconfig))?; | ||||||
|         self.wifi_driver.start()?; |         self.wifi_driver.start()?; | ||||||
|         anyhow::Ok(()) |         anyhow::Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub(crate) fn wifi(&mut self, network_config: &NetworkConfig) -> anyhow::Result<IpInfo> { | ||||||
|     pub(crate) fn wifi( |         let ssid = network_config | ||||||
|         &mut self, |             .ssid | ||||||
|         network_config: &NetworkConfig |             .clone() | ||||||
|     ) -> anyhow::Result<IpInfo> { |             .ok_or(anyhow!("No ssid configured"))?; | ||||||
|         let ssid = network_config.ssid.clone().ok_or(anyhow!("No ssid configured"))?; |  | ||||||
|         let password = network_config.password.clone(); |         let password = network_config.password.clone(); | ||||||
|         let max_wait = network_config.max_wait; |         let max_wait = network_config.max_wait; | ||||||
|  |  | ||||||
| @@ -298,7 +291,6 @@ impl ESP<'_> { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     pub(crate) fn list_files(&self) -> FileList { |     pub(crate) fn list_files(&self) -> FileList { | ||||||
|         let storage = CString::new(Self::SPIFFS_PARTITION_NAME).unwrap(); |         let storage = CString::new(Self::SPIFFS_PARTITION_NAME).unwrap(); | ||||||
|  |  | ||||||
| @@ -546,7 +538,7 @@ impl ESP<'_> { | |||||||
|                                         println!("Round trip registered, proceeding"); |                                         println!("Round trip registered, proceeding"); | ||||||
|                                         self.mqtt_client = Some(MqttClient { |                                         self.mqtt_client = Some(MqttClient { | ||||||
|                                             mqtt_client: client, |                                             mqtt_client: client, | ||||||
|                                             base_topic: base_topic_copy |                                             base_topic: base_topic_copy, | ||||||
|                                         }); |                                         }); | ||||||
|                                         return anyhow::Ok(()); |                                         return anyhow::Ok(()); | ||||||
|                                     } |                                     } | ||||||
| @@ -569,11 +561,7 @@ impl ESP<'_> { | |||||||
|         } |         } | ||||||
|         bail!("Mqtt did not fire connection callback in time"); |         bail!("Mqtt did not fire connection callback in time"); | ||||||
|     } |     } | ||||||
|     pub(crate) fn mqtt_publish( |     pub(crate) fn mqtt_publish(&mut self, subtopic: &str, message: &[u8]) -> anyhow::Result<()> { | ||||||
|         &mut self, |  | ||||||
|         subtopic: &str, |  | ||||||
|         message: &[u8], |  | ||||||
|     ) -> anyhow::Result<()> { |  | ||||||
|         if self.mqtt_client.is_none() { |         if self.mqtt_client.is_none() { | ||||||
|             return anyhow::Ok(()); |             return anyhow::Ok(()); | ||||||
|         } |         } | ||||||
| @@ -587,10 +575,7 @@ impl ESP<'_> { | |||||||
|         } |         } | ||||||
|         let client = self.mqtt_client.as_mut().unwrap(); |         let client = self.mqtt_client.as_mut().unwrap(); | ||||||
|         let mut full_topic: heapless::String<256> = heapless::String::new(); |         let mut full_topic: heapless::String<256> = heapless::String::new(); | ||||||
|         if full_topic |         if full_topic.push_str(client.base_topic.as_str()).is_err() { | ||||||
|             .push_str(client.base_topic.as_str()) |  | ||||||
|             .is_err() |  | ||||||
|         { |  | ||||||
|             println!("Some error assembling full_topic 1"); |             println!("Some error assembling full_topic 1"); | ||||||
|             bail!("Some error assembling full_topic 1") |             bail!("Some error assembling full_topic 1") | ||||||
|         }; |         }; | ||||||
| @@ -598,7 +583,9 @@ impl ESP<'_> { | |||||||
|             println!("Some error assembling full_topic 2"); |             println!("Some error assembling full_topic 2"); | ||||||
|             bail!("Some error assembling full_topic 2") |             bail!("Some error assembling full_topic 2") | ||||||
|         }; |         }; | ||||||
|         let publish = client.mqtt_client.publish(&full_topic, ExactlyOnce, true, message); |         let publish = client | ||||||
|  |             .mqtt_client | ||||||
|  |             .publish(&full_topic, ExactlyOnce, true, message); | ||||||
|         Delay::new(10).delay_ms(50); |         Delay::new(10).delay_ms(50); | ||||||
|         match publish { |         match publish { | ||||||
|             OkStd(message_id) => { |             OkStd(message_id) => { | ||||||
|   | |||||||
| @@ -1,11 +1,11 @@ | |||||||
| use crate::config::{BoardHardware, PlantControllerConfig}; | use crate::config::{BoardHardware, PlantControllerConfig}; | ||||||
| use crate::hal::battery::{BatteryInteraction, BatteryMonitor}; | use crate::hal::battery::{BatteryInteraction, BatteryMonitor}; | ||||||
| use crate::hal::esp::ESP; | use crate::hal::esp::ESP; | ||||||
| use crate::hal::{deep_sleep, BackupHeader, BoardInteraction, Sensor, FreePeripherals}; | use crate::hal::{deep_sleep, BackupHeader, BoardInteraction, FreePeripherals, Sensor}; | ||||||
| use esp_idf_hal::gpio::{IOPin, Pull}; |  | ||||||
| use anyhow::{bail, Result}; | use anyhow::{bail, Result}; | ||||||
| use chrono::{DateTime, Utc}; | use chrono::{DateTime, Utc}; | ||||||
| use embedded_hal::digital::OutputPin; | use embedded_hal::digital::OutputPin; | ||||||
|  | use esp_idf_hal::gpio::{IOPin, Pull}; | ||||||
| use esp_idf_hal::gpio::{InputOutput, PinDriver}; | use esp_idf_hal::gpio::{InputOutput, PinDriver}; | ||||||
|  |  | ||||||
| pub struct Initial<'a> { | pub struct Initial<'a> { | ||||||
|   | |||||||
| @@ -305,7 +305,8 @@ impl PlantHal { | |||||||
|                     } |                     } | ||||||
|                     BatteryBoardVersion::WchI2cSlave => BatteryMonitor::WchI2cSlave {}, |                     BatteryBoardVersion::WchI2cSlave => BatteryMonitor::WchI2cSlave {}, | ||||||
|                 }; |                 }; | ||||||
|                 let battery_interaction = Box::new(battery_monitor) as Box<dyn BatteryInteraction + Send>; |                 let battery_interaction = | ||||||
|  |                     Box::new(battery_monitor) as Box<dyn BatteryInteraction + Send>; | ||||||
|  |  | ||||||
|                 let board_hal: Box<dyn BoardInteraction + Send> = match config.hardware.board { |                 let board_hal: Box<dyn BoardInteraction + Send> = match config.hardware.board { | ||||||
|                     BoardVersion::INITIAL => { |                     BoardVersion::INITIAL => { | ||||||
|   | |||||||
| @@ -23,12 +23,12 @@ use esp_idf_hal::pcnt::{ | |||||||
|     PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex, |     PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex, | ||||||
| }; | }; | ||||||
| use esp_idf_sys::{gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError}; | use esp_idf_sys::{gpio_hold_dis, gpio_hold_en, vTaskDelay, EspError}; | ||||||
| use one_wire_bus::OneWire; |  | ||||||
| use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; |  | ||||||
| use std::result::Result::Ok as OkStd; |  | ||||||
| use ina219::address::Address; | use ina219::address::Address; | ||||||
| use ina219::calibration::{Calibration, UnCalibrated}; | use ina219::calibration::{Calibration, UnCalibrated}; | ||||||
| use ina219::SyncIna219; | use ina219::SyncIna219; | ||||||
|  | use one_wire_bus::OneWire; | ||||||
|  | use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface}; | ||||||
|  | use std::result::Result::Ok as OkStd; | ||||||
|  |  | ||||||
| const MS0: u8 = 1_u8; | const MS0: u8 = 1_u8; | ||||||
| const MS1: u8 = 0_u8; | const MS1: u8 = 0_u8; | ||||||
| @@ -174,14 +174,19 @@ pub(crate) fn create_v4( | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     let mut mppt_ina = SyncIna219::new(MutexDevice::new(&I2C_DRIVER), Address::from_byte(68)?)?; |     let mut mppt_ina = SyncIna219::new(MutexDevice::new(&I2C_DRIVER), Address::from_byte(68)?)?; | ||||||
|     esp.delay.delay_ms(mppt_ina.configuration()?.conversion_time().unwrap().as_millis() as u32); |     esp.delay.delay_ms( | ||||||
|  |         mppt_ina | ||||||
|  |             .configuration()? | ||||||
|  |             .conversion_time() | ||||||
|  |             .unwrap() | ||||||
|  |             .as_millis() as u32, | ||||||
|  |     ); | ||||||
|     println!("Bus Voltage: {}", mppt_ina.bus_voltage()?); |     println!("Bus Voltage: {}", mppt_ina.bus_voltage()?); | ||||||
|     println!("Shunt Voltage: {}", mppt_ina.shunt_voltage()?); |     println!("Shunt Voltage: {}", mppt_ina.shunt_voltage()?); | ||||||
|     let volt = (mppt_ina.shunt_voltage()?.shunt_voltage_mv()) as f32 / 1000_f32; |     let volt = (mppt_ina.shunt_voltage()?.shunt_voltage_mv()) as f32 / 1000_f32; | ||||||
|     let current = volt / 0.05; |     let current = volt / 0.05; | ||||||
|     println!("Shunt Current: {}", current); |     println!("Shunt Current: {}", current); | ||||||
|  |  | ||||||
|      |  | ||||||
|     let v = V4 { |     let v = V4 { | ||||||
|         mppt_ina, |         mppt_ina, | ||||||
|         esp, |         esp, | ||||||
|   | |||||||
							
								
								
									
										239
									
								
								rust/src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								rust/src/main.rs
									
									
									
									
									
								
							| @@ -21,16 +21,16 @@ use std::{ | |||||||
|     sync::{atomic::AtomicBool, Arc, Mutex}, |     sync::{atomic::AtomicBool, Arc, Mutex}, | ||||||
| }; | }; | ||||||
| mod config; | mod config; | ||||||
| mod log; |  | ||||||
| mod hal; | mod hal; | ||||||
|  | mod log; | ||||||
| mod plant_state; | mod plant_state; | ||||||
| mod tank; | mod tank; | ||||||
|  |  | ||||||
|  | use crate::config::BoardVersion::INITIAL; | ||||||
|  | use crate::hal::battery::BatteryInteraction; | ||||||
|  | use crate::hal::{BoardInteraction, PlantHal, HAL, PLANT_COUNT}; | ||||||
| use plant_state::PlantState; | use plant_state::PlantState; | ||||||
| use tank::*; | use tank::*; | ||||||
| use crate::config::BoardVersion::INITIAL; |  | ||||||
| use crate::hal::{BoardInteraction, PlantHal, HAL, PLANT_COUNT}; |  | ||||||
| use crate::hal::battery::BatteryInteraction; |  | ||||||
| pub static BOARD_ACCESS: Lazy<Mutex<HAL>> = Lazy::new(|| PlantHal::create().unwrap()); | pub static BOARD_ACCESS: Lazy<Mutex<HAL>> = Lazy::new(|| PlantHal::create().unwrap()); | ||||||
| pub static STAY_ALIVE: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false)); | pub static STAY_ALIVE: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false)); | ||||||
|  |  | ||||||
| @@ -88,14 +88,16 @@ enum SensorError { | |||||||
| #[derive(Serialize, Debug, PartialEq)] | #[derive(Serialize, Debug, PartialEq)] | ||||||
| enum SntpMode { | enum SntpMode { | ||||||
|     OFFLINE, |     OFFLINE, | ||||||
|     SYNC{ |     SYNC { current: DateTime<Utc> }, | ||||||
|         current: DateTime<Utc> |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Serialize, Debug, PartialEq)] | #[derive(Serialize, Debug, PartialEq)] | ||||||
| enum NetworkMode { | enum NetworkMode { | ||||||
|     WIFI {sntp: SntpMode, mqtt: bool, ip_address: String}, |     WIFI { | ||||||
|  |         sntp: SntpMode, | ||||||
|  |         mqtt: bool, | ||||||
|  |         ip_address: String, | ||||||
|  |     }, | ||||||
|     OFFLINE, |     OFFLINE, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -150,10 +152,13 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|     }; |     }; | ||||||
|     log(LogMessage::PartitionState, 0, 0, "", ota_state_string); |     log(LogMessage::PartitionState, 0, 0, "", ota_state_string); | ||||||
|  |  | ||||||
|     let mut board = BOARD_ACCESS.lock().expect("Could not lock board no other lock should be able to exist during startup!"); |     let mut board = BOARD_ACCESS | ||||||
|  |         .lock() | ||||||
|  |         .expect("Could not lock board no other lock should be able to exist during startup!"); | ||||||
|     board.board_hal.general_fault(false); |     board.board_hal.general_fault(false); | ||||||
|  |  | ||||||
|     let cur = board.board_hal |     let cur = board | ||||||
|  |         .board_hal | ||||||
|         .get_rtc_time() |         .get_rtc_time() | ||||||
|         .or_else(|err| { |         .or_else(|err| { | ||||||
|             println!("rtc module error: {:?}", err); |             println!("rtc module error: {:?}", err); | ||||||
| @@ -172,7 +177,11 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     println!("cur is {}", cur); |     println!("cur is {}", cur); | ||||||
|     match board.board_hal.get_battery_monitor().average_current_milli_ampere() { |     match board | ||||||
|  |         .board_hal | ||||||
|  |         .get_battery_monitor() | ||||||
|  |         .average_current_milli_ampere() | ||||||
|  |     { | ||||||
|         Ok(charging) => { |         Ok(charging) => { | ||||||
|             let _ = board.board_hal.set_charge_indicator(charging > 20); |             let _ = board.board_hal.set_charge_indicator(charging > 20); | ||||||
|         } |         } | ||||||
| @@ -208,7 +217,9 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if board.board_hal.get_config().hardware.board == INITIAL && board.board_hal.get_config().network.ssid.is_none(){ |     if board.board_hal.get_config().hardware.board == INITIAL | ||||||
|  |         && board.board_hal.get_config().network.ssid.is_none() | ||||||
|  |     { | ||||||
|         let _ = board.board_hal.get_esp().wifi_ap(); |         let _ = board.board_hal.get_esp().wifi_ap(); | ||||||
|         drop(board); |         drop(board); | ||||||
|         let reboot_now = Arc::new(AtomicBool::new(false)); |         let reboot_now = Arc::new(AtomicBool::new(false)); | ||||||
| @@ -251,16 +262,30 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     if let NetworkMode::WIFI { ref ip_address, .. } = network_mode { |     if let NetworkMode::WIFI { ref ip_address, .. } = network_mode { | ||||||
|         publish_firmware_info(version, address, ota_state_string, &mut board, &ip_address, timezone_time); |         publish_firmware_info( | ||||||
|  |             version, | ||||||
|  |             address, | ||||||
|  |             ota_state_string, | ||||||
|  |             &mut board, | ||||||
|  |             &ip_address, | ||||||
|  |             timezone_time, | ||||||
|  |         ); | ||||||
|         publish_battery_state(&mut board); |         publish_battery_state(&mut board); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     log( |     log( | ||||||
|         LogMessage::StartupInfo, |         LogMessage::StartupInfo, | ||||||
|         matches!(network_mode, NetworkMode::WIFI { .. }) as u32, |         matches!(network_mode, NetworkMode::WIFI { .. }) as u32, | ||||||
|         matches!(network_mode, NetworkMode::WIFI { sntp: SntpMode::SYNC { .. }, .. }) as u32, |         matches!( | ||||||
|         matches!(network_mode, NetworkMode::WIFI { mqtt: true, .. }).to_string().as_str(), |             network_mode, | ||||||
|  |             NetworkMode::WIFI { | ||||||
|  |                 sntp: SntpMode::SYNC { .. }, | ||||||
|  |                 .. | ||||||
|  |             } | ||||||
|  |         ) as u32, | ||||||
|  |         matches!(network_mode, NetworkMode::WIFI { mqtt: true, .. }) | ||||||
|  |             .to_string() | ||||||
|  |             .as_str(), | ||||||
|         "", |         "", | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
| @@ -304,7 +329,10 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|             } |             } | ||||||
|             // disabled cannot trigger this because of wrapping if is_enabled |             // disabled cannot trigger this because of wrapping if is_enabled | ||||||
|             board.board_hal.general_fault(true); |             board.board_hal.general_fault(true); | ||||||
|         } else if tank_state.warn_level(&board.board_hal.get_config().tank).is_ok_and(|warn| warn) { |         } else if tank_state | ||||||
|  |             .warn_level(&board.board_hal.get_config().tank) | ||||||
|  |             .is_ok_and(|warn| warn) | ||||||
|  |         { | ||||||
|             log(LogMessage::TankWaterLevelLow, 0, 0, "", ""); |             log(LogMessage::TankWaterLevelLow, 0, 0, "", ""); | ||||||
|             board.board_hal.general_fault(true); |             board.board_hal.general_fault(true); | ||||||
|         } |         } | ||||||
| @@ -332,10 +360,17 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|         && !water_frozen; |         && !water_frozen; | ||||||
|     if pump_required { |     if pump_required { | ||||||
|         log(LogMessage::EnableMain, dry_run as u32, 0, "", ""); |         log(LogMessage::EnableMain, dry_run as u32, 0, "", ""); | ||||||
|         for (plant_id, (state, plant_config)) in plantstate.iter().zip(&board.board_hal.get_config().plants.clone()).enumerate() { |         for (plant_id, (state, plant_config)) in plantstate | ||||||
|  |             .iter() | ||||||
|  |             .zip(&board.board_hal.get_config().plants.clone()) | ||||||
|  |             .enumerate() | ||||||
|  |         { | ||||||
|             if state.needs_to_be_watered(plant_config, &timezone_time) { |             if state.needs_to_be_watered(plant_config, &timezone_time) { | ||||||
|                 let pump_count = board.board_hal.get_esp().consecutive_pump_count(plant_id) + 1; |                 let pump_count = board.board_hal.get_esp().consecutive_pump_count(plant_id) + 1; | ||||||
|                 board.board_hal.get_esp().store_consecutive_pump_count(plant_id, pump_count); |                 board | ||||||
|  |                     .board_hal | ||||||
|  |                     .get_esp() | ||||||
|  |                     .store_consecutive_pump_count(plant_id, pump_count); | ||||||
|  |  | ||||||
|                 let pump_ineffective = pump_count > plant_config.max_consecutive_pump_count as u32; |                 let pump_ineffective = pump_count > plant_config.max_consecutive_pump_count as u32; | ||||||
|                 if pump_ineffective { |                 if pump_ineffective { | ||||||
| @@ -355,7 +390,10 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|                     &dry_run.to_string(), |                     &dry_run.to_string(), | ||||||
|                     "", |                     "", | ||||||
|                 ); |                 ); | ||||||
|                 board.board_hal.get_esp().store_last_pump_time(plant_id, cur); |                 board | ||||||
|  |                     .board_hal | ||||||
|  |                     .get_esp() | ||||||
|  |                     .store_last_pump_time(plant_id, cur); | ||||||
|                 board.board_hal.get_esp().last_pump_time(plant_id); |                 board.board_hal.get_esp().last_pump_time(plant_id); | ||||||
|                 //state.active = true; |                 //state.active = true; | ||||||
|  |  | ||||||
| @@ -367,17 +405,23 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|                     board.board_hal.pump(plant_id, false)?; |                     board.board_hal.pump(plant_id, false)?; | ||||||
|                 } |                 } | ||||||
|                 pump_info(&mut board, plant_id, false, pump_ineffective); |                 pump_info(&mut board, plant_id, false, pump_ineffective); | ||||||
|  |  | ||||||
|             } else if !state.pump_in_timeout(plant_config, &timezone_time) { |             } else if !state.pump_in_timeout(plant_config, &timezone_time) { | ||||||
|                 // plant does not need to be watered and is not in timeout |                 // plant does not need to be watered and is not in timeout | ||||||
|                 // -> reset consecutive pump count |                 // -> reset consecutive pump count | ||||||
|                 board.board_hal.get_esp().store_consecutive_pump_count(plant_id, 0); |                 board | ||||||
|  |                     .board_hal | ||||||
|  |                     .get_esp() | ||||||
|  |                     .store_consecutive_pump_count(plant_id, 0); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     let is_day = board.board_hal.is_day(); |     let is_day = board.board_hal.is_day(); | ||||||
|     let state_of_charge = board.board_hal.get_battery_monitor().state_charge_percent().unwrap_or(0); |     let state_of_charge = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_battery_monitor() | ||||||
|  |         .state_charge_percent() | ||||||
|  |         .unwrap_or(0); | ||||||
|  |  | ||||||
|     let mut light_state = LightState { |     let mut light_state = LightState { | ||||||
|         enabled: board.board_hal.get_config().night_lamp.enabled, |         enabled: board.board_hal.get_config().night_lamp.enabled, | ||||||
| @@ -387,7 +431,11 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|         light_state.is_day = is_day; |         light_state.is_day = is_day; | ||||||
|         light_state.out_of_work_hour = !in_time_range( |         light_state.out_of_work_hour = !in_time_range( | ||||||
|             &timezone_time, |             &timezone_time, | ||||||
|             board.board_hal.get_config().night_lamp.night_lamp_hour_start, |             board | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_config() | ||||||
|  |                 .night_lamp | ||||||
|  |                 .night_lamp_hour_start, | ||||||
|             board.board_hal.get_config().night_lamp.night_lamp_hour_end, |             board.board_hal.get_config().night_lamp.night_lamp_hour_end, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
| @@ -399,7 +447,12 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|         light_state.battery_low = board.board_hal.get_esp().low_voltage_in_cycle(); |         light_state.battery_low = board.board_hal.get_esp().low_voltage_in_cycle(); | ||||||
|  |  | ||||||
|         if !light_state.out_of_work_hour { |         if !light_state.out_of_work_hour { | ||||||
|             if board.board_hal.get_config().night_lamp.night_lamp_only_when_dark { |             if board | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_config() | ||||||
|  |                 .night_lamp | ||||||
|  |                 .night_lamp_only_when_dark | ||||||
|  |             { | ||||||
|                 if !light_state.is_day { |                 if !light_state.is_day { | ||||||
|                     if light_state.battery_low { |                     if light_state.battery_low { | ||||||
|                         board.board_hal.light(false)?; |                         board.board_hal.light(false)?; | ||||||
| @@ -424,7 +477,10 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|  |  | ||||||
|     match serde_json::to_string(&light_state) { |     match serde_json::to_string(&light_state) { | ||||||
|         Ok(state) => { |         Ok(state) => { | ||||||
|             let _ = board.board_hal.get_esp().mqtt_publish( "/light", state.as_bytes()); |             let _ = board | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_esp() | ||||||
|  |                 .mqtt_publish("/light", state.as_bytes()); | ||||||
|         } |         } | ||||||
|         Err(err) => { |         Err(err) => { | ||||||
|             println!("Error publishing lightstate {}", err); |             println!("Error publishing lightstate {}", err); | ||||||
| @@ -432,16 +488,28 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let deep_sleep_duration_minutes: u32 = if state_of_charge < 10 { |     let deep_sleep_duration_minutes: u32 = if state_of_charge < 10 { | ||||||
|         let _ = board.board_hal.get_esp().mqtt_publish( "/deepsleep", "low Volt 12h".as_bytes()); |         let _ = board | ||||||
|  |             .board_hal | ||||||
|  |             .get_esp() | ||||||
|  |             .mqtt_publish("/deepsleep", "low Volt 12h".as_bytes()); | ||||||
|         12 * 60 |         12 * 60 | ||||||
|     } else if is_day { |     } else if is_day { | ||||||
|         let _ = board.board_hal.get_esp().mqtt_publish( "/deepsleep", "normal 20m".as_bytes()); |         let _ = board | ||||||
|  |             .board_hal | ||||||
|  |             .get_esp() | ||||||
|  |             .mqtt_publish("/deepsleep", "normal 20m".as_bytes()); | ||||||
|         20 |         20 | ||||||
|     } else { |     } else { | ||||||
|         let _ = board.board_hal.get_esp().mqtt_publish( "/deepsleep", "night 1h".as_bytes()); |         let _ = board | ||||||
|  |             .board_hal | ||||||
|  |             .get_esp() | ||||||
|  |             .mqtt_publish("/deepsleep", "night 1h".as_bytes()); | ||||||
|         60 |         60 | ||||||
|     }; |     }; | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( "/state", "sleep".as_bytes()); |     let _ = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|  |         .mqtt_publish("/state", "sleep".as_bytes()); | ||||||
|  |  | ||||||
|     //determine next event |     //determine next event | ||||||
|     //is light out of work trigger soon? |     //is light out of work trigger soon? | ||||||
| @@ -462,7 +530,9 @@ fn safe_main() -> anyhow::Result<()> { | |||||||
|         wait_infinity(WaitType::MqttConfig, reboot_now.clone()); |         wait_infinity(WaitType::MqttConfig, reboot_now.clone()); | ||||||
|     } |     } | ||||||
|     board.board_hal.get_esp().set_restart_to_conf(false); |     board.board_hal.get_esp().set_restart_to_conf(false); | ||||||
|     board.board_hal.deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64); |     board | ||||||
|  |         .board_hal | ||||||
|  |         .deep_sleep(1000 * 1000 * 60 * deep_sleep_duration_minutes as u64); | ||||||
| } | } | ||||||
|  |  | ||||||
| fn obtain_tank_temperature(board: &mut MutexGuard<HAL>) -> anyhow::Result<f32> { | fn obtain_tank_temperature(board: &mut MutexGuard<HAL>) -> anyhow::Result<f32> { | ||||||
| @@ -487,10 +557,19 @@ fn obtain_tank_temperature(board: &mut MutexGuard<HAL>) -> anyhow::Result<f32> { | |||||||
|     water_temp |     water_temp | ||||||
| } | } | ||||||
|  |  | ||||||
| fn publish_tank_state(board: &mut MutexGuard<HAL>, tank_state: &TankState, water_temp: &anyhow::Result<f32>) { | fn publish_tank_state( | ||||||
|     match serde_json::to_string(&tank_state.as_mqtt_info(&board.board_hal.get_config().tank, water_temp)) { |     board: &mut MutexGuard<HAL>, | ||||||
|  |     tank_state: &TankState, | ||||||
|  |     water_temp: &anyhow::Result<f32>, | ||||||
|  | ) { | ||||||
|  |     match serde_json::to_string( | ||||||
|  |         &tank_state.as_mqtt_info(&board.board_hal.get_config().tank, water_temp), | ||||||
|  |     ) { | ||||||
|         Ok(state) => { |         Ok(state) => { | ||||||
|             let _ = board.board_hal.get_esp().mqtt_publish("/water", state.as_bytes()); |             let _ = board | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_esp() | ||||||
|  |                 .mqtt_publish("/water", state.as_bytes()); | ||||||
|         } |         } | ||||||
|         Err(err) => { |         Err(err) => { | ||||||
|             println!("Error publishing tankstate {}", err); |             println!("Error publishing tankstate {}", err); | ||||||
| @@ -498,12 +577,23 @@ fn publish_tank_state(board: &mut MutexGuard<HAL>, tank_state: &TankState, water | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| fn publish_plant_states(board: &mut MutexGuard<HAL>, timezone_time: &DateTime<Tz>, plantstate: &[PlantState; 8]) { | fn publish_plant_states( | ||||||
|     for (plant_id, (plant_state, plant_conf)) in plantstate.iter().zip(& board.board_hal.get_config().plants.clone()).enumerate() { |     board: &mut MutexGuard<HAL>, | ||||||
|  |     timezone_time: &DateTime<Tz>, | ||||||
|  |     plantstate: &[PlantState; 8], | ||||||
|  | ) { | ||||||
|  |     for (plant_id, (plant_state, plant_conf)) in plantstate | ||||||
|  |         .iter() | ||||||
|  |         .zip(&board.board_hal.get_config().plants.clone()) | ||||||
|  |         .enumerate() | ||||||
|  |     { | ||||||
|         match serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, &timezone_time)) { |         match serde_json::to_string(&plant_state.to_mqtt_info(plant_conf, &timezone_time)) { | ||||||
|             Ok(state) => { |             Ok(state) => { | ||||||
|                 let plant_topic = format!("/plant{}", plant_id + 1); |                 let plant_topic = format!("/plant{}", plant_id + 1); | ||||||
|                 let _ = board.board_hal.get_esp().mqtt_publish(&plant_topic, state.as_bytes()); |                 let _ = board | ||||||
|  |                     .board_hal | ||||||
|  |                     .get_esp() | ||||||
|  |                     .mqtt_publish(&plant_topic, state.as_bytes()); | ||||||
|                 //reduce speed as else messages will be dropped |                 //reduce speed as else messages will be dropped | ||||||
|                 board.board_hal.get_esp().delay.delay_ms(200); |                 board.board_hal.get_esp().delay.delay_ms(200); | ||||||
|             } |             } | ||||||
| @@ -514,23 +604,42 @@ fn publish_plant_states(board: &mut MutexGuard<HAL>, timezone_time: &DateTime<Tz | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn publish_firmware_info(version: VersionInfo, address: u32, ota_state_string: &str, board: &mut MutexGuard<HAL>, ip_address: &String, timezone_time: DateTime<Tz>) { | fn publish_firmware_info( | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish("/firmware/address", ip_address.as_bytes()); |     version: VersionInfo, | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( "/firmware/githash", version.git_hash.as_bytes()); |     address: u32, | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( |     ota_state_string: &str, | ||||||
|         "/firmware/buildtime", |     board: &mut MutexGuard<HAL>, | ||||||
|         version.build_time.as_bytes(), |     ip_address: &String, | ||||||
|     ); |     timezone_time: DateTime<Tz>, | ||||||
|  | ) { | ||||||
|  |     let _ = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|  |         .mqtt_publish("/firmware/address", ip_address.as_bytes()); | ||||||
|  |     let _ = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|  |         .mqtt_publish("/firmware/githash", version.git_hash.as_bytes()); | ||||||
|  |     let _ = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|  |         .mqtt_publish("/firmware/buildtime", version.build_time.as_bytes()); | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( |     let _ = board.board_hal.get_esp().mqtt_publish( | ||||||
|         "/firmware/last_online", |         "/firmware/last_online", | ||||||
|         timezone_time.to_rfc3339().as_bytes(), |         timezone_time.to_rfc3339().as_bytes(), | ||||||
|     ); |     ); | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( "/firmware/ota_state", ota_state_string.as_bytes()); |     let _ = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|  |         .mqtt_publish("/firmware/ota_state", ota_state_string.as_bytes()); | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( |     let _ = board.board_hal.get_esp().mqtt_publish( | ||||||
|         "/firmware/partition_address", |         "/firmware/partition_address", | ||||||
|         format!("{:#06x}", address).as_bytes(), |         format!("{:#06x}", address).as_bytes(), | ||||||
|     ); |     ); | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( "/state", "online".as_bytes()); |     let _ = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|  |         .mqtt_publish("/state", "online".as_bytes()); | ||||||
| } | } | ||||||
|  |  | ||||||
| fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<HAL>) -> NetworkMode { | fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<HAL>) -> NetworkMode { | ||||||
| @@ -567,7 +676,7 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<HAL>) -> NetworkMode{ | |||||||
|             NetworkMode::WIFI { |             NetworkMode::WIFI { | ||||||
|                 sntp: sntp_mode, |                 sntp: sntp_mode, | ||||||
|                 mqtt: mqtt_connected, |                 mqtt: mqtt_connected, | ||||||
|                 ip_address: ip_info.ip.to_string() |                 ip_address: ip_info.ip.to_string(), | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Err(_) => { |         Err(_) => { | ||||||
| @@ -578,15 +687,23 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<HAL>) -> NetworkMode{ | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn pump_info(board: &mut MutexGuard<HAL>, plant_id: usize, pump_active: bool, pump_ineffective: bool)  { | fn pump_info( | ||||||
|  |     board: &mut MutexGuard<HAL>, | ||||||
|  |     plant_id: usize, | ||||||
|  |     pump_active: bool, | ||||||
|  |     pump_ineffective: bool, | ||||||
|  | ) { | ||||||
|     let pump_info = PumpInfo { |     let pump_info = PumpInfo { | ||||||
|         enabled: pump_active, |         enabled: pump_active, | ||||||
|         pump_ineffective |         pump_ineffective, | ||||||
|     }; |     }; | ||||||
|     let pump_topic = format!("/pump{}", plant_id + 1); |     let pump_topic = format!("/pump{}", plant_id + 1); | ||||||
|     match serde_json::to_string(&pump_info) { |     match serde_json::to_string(&pump_info) { | ||||||
|         Ok(state) => { |         Ok(state) => { | ||||||
|             let _ = board.board_hal.get_esp().mqtt_publish(&pump_topic, state.as_bytes()); |             let _ = board | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_esp() | ||||||
|  |                 .mqtt_publish(&pump_topic, state.as_bytes()); | ||||||
|             //reduce speed as else messages will be dropped |             //reduce speed as else messages will be dropped | ||||||
|             Delay::new_default().delay_ms(200); |             Delay::new_default().delay_ms(200); | ||||||
|         } |         } | ||||||
| @@ -596,11 +713,12 @@ fn pump_info(board: &mut MutexGuard<HAL>, plant_id: usize, pump_active: bool, pu | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| fn publish_battery_state( | fn publish_battery_state(board: &mut MutexGuard<'_, HAL<'_>>) { | ||||||
|     board: &mut MutexGuard<'_, HAL<'_>> |  | ||||||
| ) { |  | ||||||
|     let state = board.board_hal.get_battery_monitor().get_battery_state(); |     let state = board.board_hal.get_battery_monitor().get_battery_state(); | ||||||
|     let _ = board.board_hal.get_esp().mqtt_publish( "/battery", state.as_bytes()); |     let _ = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|  |         .mqtt_publish("/battery", state.as_bytes()); | ||||||
| } | } | ||||||
|  |  | ||||||
| fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! { | fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! { | ||||||
| @@ -611,7 +729,11 @@ fn wait_infinity(wait_type: WaitType, reboot_now: Arc<AtomicBool>) -> ! { | |||||||
|     loop { |     loop { | ||||||
|         unsafe { |         unsafe { | ||||||
|             let mut board = BOARD_ACCESS.lock().unwrap(); |             let mut board = BOARD_ACCESS.lock().unwrap(); | ||||||
|             if let Ok(charging) = board.board_hal.get_battery_monitor().average_current_milli_ampere() { |             if let Ok(charging) = board | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_battery_monitor() | ||||||
|  |                 .average_current_milli_ampere() | ||||||
|  |             { | ||||||
|                 let _ = board.board_hal.set_charge_indicator(charging > 20); |                 let _ = board.board_hal.set_charge_indicator(charging > 20); | ||||||
|             } |             } | ||||||
|             match wait_type { |             match wait_type { | ||||||
| @@ -673,7 +795,12 @@ fn main() { | |||||||
|         // timeout, this is just a fallback |         // timeout, this is just a fallback | ||||||
|         Ok(_) => { |         Ok(_) => { | ||||||
|             println!("Main app finished, restarting"); |             println!("Main app finished, restarting"); | ||||||
|             BOARD_ACCESS.lock().unwrap().board_hal.get_esp().set_restart_to_conf(false); |             BOARD_ACCESS | ||||||
|  |                 .lock() | ||||||
|  |                 .unwrap() | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_esp() | ||||||
|  |                 .set_restart_to_conf(false); | ||||||
|             BOARD_ACCESS.lock().unwrap().board_hal.deep_sleep(1); |             BOARD_ACCESS.lock().unwrap().board_hal.deep_sleep(1); | ||||||
|         } |         } | ||||||
|         // if safe_main exists with an error, rollback to a known good ota version |         // if safe_main exists with an error, rollback to a known good ota version | ||||||
|   | |||||||
| @@ -2,8 +2,8 @@ use chrono::{DateTime, TimeDelta, Utc}; | |||||||
| use chrono_tz::Tz; | use chrono_tz::Tz; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use crate::{config::PlantConfig, in_time_range}; |  | ||||||
| use crate::hal::{BoardInteraction, Sensor, HAL}; | use crate::hal::{BoardInteraction, Sensor, HAL}; | ||||||
|  | use crate::{config::PlantConfig, in_time_range}; | ||||||
|  |  | ||||||
| const MOIST_SENSOR_MAX_FREQUENCY: f32 = 7500.; // 60kHz (500Hz margin) | const MOIST_SENSOR_MAX_FREQUENCY: f32 = 7500.; // 60kHz (500Hz margin) | ||||||
| const MOIST_SENSOR_MIN_FREQUENCY: f32 = 150.; // this is really, really dry, think like cactus levels | const MOIST_SENSOR_MIN_FREQUENCY: f32 = 150.; // this is really, really dry, think like cactus levels | ||||||
| @@ -112,10 +112,7 @@ fn map_range_moisture( | |||||||
| } | } | ||||||
|  |  | ||||||
| impl PlantState { | impl PlantState { | ||||||
|     pub fn read_hardware_state( |     pub fn read_hardware_state(plant_id: usize, board: &mut HAL) -> Self { | ||||||
|         plant_id: usize, |  | ||||||
|         board: &mut HAL |  | ||||||
|     ) -> Self { |  | ||||||
|         let sensor_a = if board.board_hal.get_config().plants[plant_id].sensor_a { |         let sensor_a = if board.board_hal.get_config().plants[plant_id].sensor_a { | ||||||
|             match board.board_hal.measure_moisture_hz(plant_id, Sensor::A) { |             match board.board_hal.measure_moisture_hz(plant_id, Sensor::A) { | ||||||
|                 Ok(raw) => match map_range_moisture( |                 Ok(raw) => match map_range_moisture( | ||||||
|   | |||||||
| @@ -114,11 +114,7 @@ impl TankState { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn as_mqtt_info( |     pub fn as_mqtt_info(&self, config: &TankConfig, water_temp: &anyhow::Result<f32>) -> TankInfo { | ||||||
|         &self, |  | ||||||
|         config: &TankConfig, |  | ||||||
|         water_temp: &anyhow::Result<f32>, |  | ||||||
|     ) -> TankInfo { |  | ||||||
|         let mut tank_err: Option<TankError> = None; |         let mut tank_err: Option<TankError> = None; | ||||||
|         let left_ml = match self.left_ml(config) { |         let left_ml = match self.left_ml(config) { | ||||||
|             Err(err) => { |             Err(err) => { | ||||||
| @@ -155,9 +151,7 @@ impl TankState { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn determine_tank_state( | pub fn determine_tank_state(board: &mut std::sync::MutexGuard<'_, HAL<'_>>) -> TankState { | ||||||
|     board: &mut std::sync::MutexGuard<'_, HAL<'_>> |  | ||||||
| ) -> TankState { |  | ||||||
|     if board.board_hal.get_config().tank.tank_sensor_enabled { |     if board.board_hal.get_config().tank.tank_sensor_enabled { | ||||||
|         match board.board_hal.tank_sensor_voltage() { |         match board.board_hal.tank_sensor_voltage() { | ||||||
|             Ok(raw_sensor_value_mv) => TankState::Present(raw_sensor_value_mv), |             Ok(raw_sensor_value_mv) => TankState::Present(raw_sensor_value_mv), | ||||||
|   | |||||||
| @@ -2,8 +2,7 @@ | |||||||
|  |  | ||||||
| use crate::hal::battery::BatteryInteraction; | use crate::hal::battery::BatteryInteraction; | ||||||
| use crate::{ | use crate::{ | ||||||
|     determine_tank_state, get_version, log::LogMessage, |     determine_tank_state, get_version, log::LogMessage, plant_state::PlantState, BOARD_ACCESS, | ||||||
|     plant_state::PlantState, BOARD_ACCESS, |  | ||||||
| }; | }; | ||||||
| use anyhow::bail; | use anyhow::bail; | ||||||
| use chrono::DateTime; | use chrono::DateTime; | ||||||
| @@ -83,11 +82,14 @@ fn get_time( | |||||||
|     _request: &mut Request<&mut EspHttpConnection>, |     _request: &mut Request<&mut EspHttpConnection>, | ||||||
| ) -> Result<Option<std::string::String>, anyhow::Error> { | ) -> Result<Option<std::string::String>, anyhow::Error> { | ||||||
|     let mut board = BOARD_ACCESS.lock().expect("board access"); |     let mut board = BOARD_ACCESS.lock().expect("board access"); | ||||||
|     let native = board.board_hal.get_esp() |     let native = board | ||||||
|  |         .board_hal | ||||||
|  |         .get_esp() | ||||||
|         .time() |         .time() | ||||||
|         .map(|t| t.to_rfc3339()) |         .map(|t| t.to_rfc3339()) | ||||||
|         .unwrap_or("error".to_string()); |         .unwrap_or("error".to_string()); | ||||||
|     let rtc = board.board_hal |     let rtc = board | ||||||
|  |         .board_hal | ||||||
|         .get_rtc_time() |         .get_rtc_time() | ||||||
|         .map(|t| t.to_rfc3339()) |         .map(|t| t.to_rfc3339()) | ||||||
|         .unwrap_or("error".to_string()); |         .unwrap_or("error".to_string()); | ||||||
| @@ -116,35 +118,28 @@ fn get_live_moisture( | |||||||
|     _request: &mut Request<&mut EspHttpConnection>, |     _request: &mut Request<&mut EspHttpConnection>, | ||||||
| ) -> Result<Option<std::string::String>, anyhow::Error> { | ) -> Result<Option<std::string::String>, anyhow::Error> { | ||||||
|     let mut board = BOARD_ACCESS.lock().expect("Should never fail"); |     let mut board = BOARD_ACCESS.lock().expect("Should never fail"); | ||||||
|     let plant_state = Vec::from_iter( |     let plant_state = | ||||||
|         (0..PLANT_COUNT).map(|i| PlantState::read_hardware_state(i, &mut board)), |         Vec::from_iter((0..PLANT_COUNT).map(|i| PlantState::read_hardware_state(i, &mut board))); | ||||||
|     ); |     let a = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_a { | ||||||
|     let a = Vec::from_iter( |  | ||||||
|         plant_state |  | ||||||
|             .iter() |  | ||||||
|             .map(|s| { |  | ||||||
|                 match &s.sensor_a  { |  | ||||||
|         MoistureSensorState::Disabled => "disabled".to_string(), |         MoistureSensorState::Disabled => "disabled".to_string(), | ||||||
|                     MoistureSensorState::MoistureValue {raw_hz, moisture_percent } => { |         MoistureSensorState::MoistureValue { | ||||||
|  |             raw_hz, | ||||||
|  |             moisture_percent, | ||||||
|  |         } => { | ||||||
|             format!("{moisture_percent:.2}% {raw_hz}hz",) |             format!("{moisture_percent:.2}% {raw_hz}hz",) | ||||||
|         } |         } | ||||||
|         MoistureSensorState::SensorError(err) => format!("{err:?}"), |         MoistureSensorState::SensorError(err) => format!("{err:?}"), | ||||||
|                 } |     })); | ||||||
|             }) |     let b = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_b { | ||||||
|     ); |  | ||||||
|     let b = Vec::from_iter( |  | ||||||
|         plant_state |  | ||||||
|             .iter() |  | ||||||
|             .map(|s| { |  | ||||||
|                 match &s.sensor_b  { |  | ||||||
|         MoistureSensorState::Disabled => "disabled".to_string(), |         MoistureSensorState::Disabled => "disabled".to_string(), | ||||||
|                     MoistureSensorState::MoistureValue {raw_hz, moisture_percent } => { |         MoistureSensorState::MoistureValue { | ||||||
|  |             raw_hz, | ||||||
|  |             moisture_percent, | ||||||
|  |         } => { | ||||||
|             format!("{moisture_percent:.2}% {raw_hz}hz",) |             format!("{moisture_percent:.2}% {raw_hz}hz",) | ||||||
|         } |         } | ||||||
|         MoistureSensorState::SensorError(err) => format!("{err:?}"), |         MoistureSensorState::SensorError(err) => format!("{err:?}"), | ||||||
|                 } |     })); | ||||||
|             }) |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     let data = Moistures { |     let data = Moistures { | ||||||
|         moisture_a: a, |         moisture_a: a, | ||||||
| @@ -267,9 +262,10 @@ fn tank_info( | |||||||
|     let tank_info = determine_tank_state(&mut board); |     let tank_info = determine_tank_state(&mut board); | ||||||
|     //should be multsampled |     //should be multsampled | ||||||
|     let water_temp = board.board_hal.water_temperature_c(); |     let water_temp = board.board_hal.water_temperature_c(); | ||||||
|     Ok(Some(serde_json::to_string( |     Ok(Some(serde_json::to_string(&tank_info.as_mqtt_info( | ||||||
|         &tank_info.as_mqtt_info(&board.board_hal.get_config().tank, &water_temp), |         &board.board_hal.get_config().tank, | ||||||
|     )?)) |         &water_temp, | ||||||
|  |     ))?)) | ||||||
| } | } | ||||||
|  |  | ||||||
| fn night_lamp_test( | fn night_lamp_test( | ||||||
| @@ -297,7 +293,9 @@ fn wifi_scan( | |||||||
| fn list_files( | fn list_files( | ||||||
|     _request: &mut Request<&mut EspHttpConnection>, |     _request: &mut Request<&mut EspHttpConnection>, | ||||||
| ) -> Result<Option<std::string::String>, anyhow::Error> { | ) -> Result<Option<std::string::String>, anyhow::Error> { | ||||||
|     let mut board = BOARD_ACCESS.lock().expect("It should be possible to lock the board for exclusive fs access"); |     let mut board = BOARD_ACCESS | ||||||
|  |         .lock() | ||||||
|  |         .expect("It should be possible to lock the board for exclusive fs access"); | ||||||
|     let result = board.board_hal.get_esp().list_files(); |     let result = board.board_hal.get_esp().list_files(); | ||||||
|     let file_list_json = serde_json::to_string(&result)?; |     let file_list_json = serde_json::to_string(&result)?; | ||||||
|     anyhow::Ok(Some(file_list_json)) |     anyhow::Ok(Some(file_list_json)) | ||||||
| @@ -469,7 +467,12 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> { | |||||||
|     let reboot_now_for_reboot = reboot_now.clone(); |     let reboot_now_for_reboot = reboot_now.clone(); | ||||||
|     server |     server | ||||||
|         .fn_handler("/reboot", Method::Post, move |_| { |         .fn_handler("/reboot", Method::Post, move |_| { | ||||||
|             BOARD_ACCESS.lock().unwrap().board_hal.get_esp().set_restart_to_conf(true); |             BOARD_ACCESS | ||||||
|  |                 .lock() | ||||||
|  |                 .unwrap() | ||||||
|  |                 .board_hal | ||||||
|  |                 .get_esp() | ||||||
|  |                 .set_restart_to_conf(true); | ||||||
|             reboot_now_for_reboot.store(true, std::sync::atomic::Ordering::Relaxed); |             reboot_now_for_reboot.store(true, std::sync::atomic::Ordering::Relaxed); | ||||||
|             anyhow::Ok(()) |             anyhow::Ok(()) | ||||||
|         }) |         }) | ||||||
| @@ -490,7 +493,8 @@ pub fn httpd(reboot_now: Arc<AtomicBool>) -> Box<EspHttpServer<'static>> { | |||||||
|             let file_handle = BOARD_ACCESS |             let file_handle = BOARD_ACCESS | ||||||
|                 .lock() |                 .lock() | ||||||
|                 .unwrap() |                 .unwrap() | ||||||
|                 .board_hal.get_esp() |                 .board_hal | ||||||
|  |                 .get_esp() | ||||||
|                 .get_file_handle(&filename, false); |                 .get_file_handle(&filename, false); | ||||||
|             match file_handle { |             match file_handle { | ||||||
|                 Ok(mut file_handle) => { |                 Ok(mut file_handle) => { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user