diff --git a/rust/src/config.rs b/rust/src/config.rs index 519be87..f8768b4 100644 --- a/rust/src/config.rs +++ b/rust/src/config.rs @@ -1,7 +1,7 @@ -use serde::{Deserialize, Serialize}; -use std::str::FromStr; use crate::hal::PLANT_COUNT; use crate::plant_state::PlantWateringMode; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(default)] @@ -11,7 +11,7 @@ pub struct NetworkConfig { pub password: Option>, pub mqtt_url: Option>, pub base_topic: Option>, - pub max_wait: u32 + pub max_wait: u32, } impl Default for NetworkConfig { fn default() -> Self { @@ -21,7 +21,7 @@ impl Default for NetworkConfig { password: None, mqtt_url: None, base_topic: None, - max_wait: 10000 + max_wait: 10000, } } } @@ -73,18 +73,18 @@ impl Default for TankConfig { } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] -pub enum BatteryBoardVersion{ +pub enum BatteryBoardVersion { #[default] Disabled, BQ34Z100G1, - WchI2cSlave + WchI2cSlave, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] -pub enum BoardVersion{ +pub enum BoardVersion { #[default] INITIAL, V3, - V4 + V4, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] diff --git a/rust/src/hal/battery.rs b/rust/src/hal/battery.rs index 42619f1..50e76b2 100644 --- a/rust/src/hal/battery.rs +++ b/rust/src/hal/battery.rs @@ -1,217 +1,157 @@ -use anyhow::bail; +use crate::to_string; +use anyhow::anyhow; use bq34z100::{Bq34Z100Error, Bq34z100g1, Bq34z100g1Driver}; use embedded_hal_bus::i2c::MutexDevice; use esp_idf_hal::delay::Delay; use esp_idf_hal::i2c::{I2cDriver, I2cError}; use measurements::Temperature; use serde::Serialize; -use std::result::Result::Ok as OkStd; -use crate::to_string; pub trait BatteryInteraction { - fn state_charge_percent(&mut self) -> anyhow::Result; - fn remaining_milli_ampere_hour(&mut self) -> anyhow::Result; - fn max_milli_ampere_hour(&mut self) -> anyhow::Result; - fn design_milli_ampere_hour(&mut self) -> anyhow::Result; - fn voltage_milli_volt(&mut self) -> anyhow::Result; - fn average_current_milli_ampere(&mut self) -> anyhow::Result; - fn cycle_count(&mut self) -> anyhow::Result; - fn state_health_percent(&mut self) -> anyhow::Result; - fn bat_temperature(&mut self) -> anyhow::Result; - fn get_battery_state(&mut self) -> String; + fn state_charge_percent(&mut self) -> Result; + fn remaining_milli_ampere_hour(&mut self) -> Result; + fn max_milli_ampere_hour(&mut self) -> Result; + fn design_milli_ampere_hour(&mut self) -> Result; + fn voltage_milli_volt(&mut self) -> Result; + fn average_current_milli_ampere(&mut self) -> Result; + fn cycle_count(&mut self) -> Result; + fn state_health_percent(&mut self) -> Result; + fn bat_temperature(&mut self) -> Result; + fn get_battery_state(&mut self) -> Result; } -#[derive(Serialize)] -pub struct BatteryState { - voltage_milli_volt: String, - current_milli_ampere: String, - cycle_count: String, - design_milli_ampere: String, - remaining_milli_ampere: String, - state_of_charge: String, - state_of_health: String, - temperature: String, + +#[derive(Debug, Serialize)] +pub struct BatteryInfo { + pub voltage_milli_volt: u16, + pub average_current_milli_ampere: i16, + pub cycle_count: u16, + pub design_milli_ampere_hour: u16, + pub remaining_milli_ampere_hour: u16, + pub state_of_charge: f32, + pub state_of_health: u16, + pub temperature: u16, } -pub enum BatteryMonitor<'a> { - Disabled { - }, - BQ34Z100G1 { - battery_driver: Bq34z100g1Driver>, Delay> - }, - WchI2cSlave { +#[derive(Debug, Serialize)] +pub enum BatteryError { + NoBatteryMonitor, + CommunicationError(String), +} +impl From> for BatteryError { + fn from(err: Bq34Z100Error) -> Self { + BatteryError::CommunicationError( + anyhow!("failed to communicate with battery monitor: {:?}", err).to_string(), + ) } } +#[derive(Debug, Serialize)] +pub enum BatteryState { + Unknown, + Info(BatteryInfo), +} +/// If no battery monitor is installed this implementation will be used +pub struct NoBatteryMonitor {} -impl BatteryInteraction for BatteryMonitor<'_> { - fn state_charge_percent(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.state_of_charge() { - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading SoC {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - } - BatteryMonitor::Disabled {} => { - bail!("Battery monitor is disabled") - } - } +impl BatteryInteraction for NoBatteryMonitor { + fn state_charge_percent(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) } - fn remaining_milli_ampere_hour(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.remaining_capacity(){ - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading remaining_milli_ampere_hour {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } - } - fn max_milli_ampere_hour(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.full_charge_capacity() { - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading max_milli_ampere_hour {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } - } - fn design_milli_ampere_hour(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.design_capacity() { - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading design_milli_ampere_hour {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } - } - fn voltage_milli_volt(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.voltage() { - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading voltage_milli_volt {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } - } - fn average_current_milli_ampere(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.average_current() { - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading average_current_milli_ampere {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } - } - fn cycle_count(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.cycle_count() { - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading cycle_count {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } - } - fn state_health_percent(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.state_of_health() { - OkStd(r) => anyhow::Ok(r as u8), - Err(err) => bail!("Error reading state_health_percent {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } - } - fn bat_temperature(&mut self) -> anyhow::Result { - match self { - BatteryMonitor::BQ34Z100G1 { battery_driver} => { - match battery_driver.temperature() { - OkStd(r) => anyhow::Ok(r), - Err(err) => bail!("Error reading bat_temperature {:?}", err), - } - }, - BatteryMonitor::WchI2cSlave { .. } => { - bail!("Not implemented") - }, - &mut BatteryMonitor::Disabled { } => { - bail!("Battery monitor is disabled") - } - } + fn remaining_milli_ampere_hour(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) } - fn get_battery_state(&mut self) -> String { - let bat = BatteryState { - voltage_milli_volt: to_string(self.voltage_milli_volt()), - current_milli_ampere: to_string(self.average_current_milli_ampere()), - cycle_count: to_string(self.cycle_count()), - design_milli_ampere: to_string(self.design_milli_ampere_hour()), - remaining_milli_ampere: to_string(self.remaining_milli_ampere_hour()), - state_of_charge: to_string(self.state_charge_percent()), - state_of_health: to_string(self.state_health_percent()), - temperature: to_string(self.bat_temperature()), - }; + fn max_milli_ampere_hour(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) + } - match serde_json::to_string(&bat) { - Ok(state) => { - state - } - Err(err) => { - format!("{:?}", err).to_owned() - } - } + fn design_milli_ampere_hour(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) + } + + fn voltage_milli_volt(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) + } + + fn average_current_milli_ampere(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) + } + + fn cycle_count(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) + } + + fn state_health_percent(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) + } + + fn bat_temperature(&mut self) -> Result { + Err(BatteryError::NoBatteryMonitor) + } + + fn get_battery_state(&mut self) -> Result { + Ok(BatteryState::Unknown) + } +} + +//TODO implement this battery monitor kind once controller is complete +pub struct WchI2cSlave {} + +pub struct BQ34Z100G1<'a> { + pub battery_driver: Bq34z100g1Driver>, Delay>, +} + +impl BatteryInteraction for BQ34Z100G1<'_> { + fn state_charge_percent(&mut self) -> Result { + Ok(self.battery_driver.state_of_charge().map(f32::from)?) + } + + fn remaining_milli_ampere_hour(&mut self) -> Result { + Ok(self.battery_driver.remaining_capacity()?) + } + + fn max_milli_ampere_hour(&mut self) -> Result { + Ok(self.battery_driver.full_charge_capacity()?) + } + + fn design_milli_ampere_hour(&mut self) -> Result { + Ok(self.battery_driver.design_capacity()?) + } + + fn voltage_milli_volt(&mut self) -> Result { + Ok(self.battery_driver.voltage()?) + } + + fn average_current_milli_ampere(&mut self) -> Result { + Ok(self.battery_driver.average_current()?) + } + + fn cycle_count(&mut self) -> Result { + Ok(self.battery_driver.cycle_count()?) + } + + fn state_health_percent(&mut self) -> Result { + Ok(self.battery_driver.state_of_health()?) + } + + fn bat_temperature(&mut self) -> Result { + Ok(self.battery_driver.temperature()?) + } + + fn get_battery_state(&mut self) -> Result { + Ok(BatteryState::Info(BatteryInfo { + voltage_milli_volt: self.voltage_milli_volt()?, + average_current_milli_ampere: self.average_current_milli_ampere()?, + cycle_count: self.cycle_count()?, + design_milli_ampere_hour: self.design_milli_ampere_hour()?, + remaining_milli_ampere_hour: self.remaining_milli_ampere_hour()?, + state_of_charge: self.state_charge_percent()?, + state_of_health: self.state_health_percent()?, + temperature: self.bat_temperature()?, + })) } } diff --git a/rust/src/hal/esp.rs b/rust/src/hal/esp.rs index b0811f7..70ff6b8 100644 --- a/rust/src/hal/esp.rs +++ b/rust/src/hal/esp.rs @@ -6,10 +6,15 @@ use anyhow::{anyhow, bail, Context}; use chrono::{DateTime, Utc}; use embedded_svc::ipv4::IpInfo; 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::gpio::{Level, PinDriver}; 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::EspWifi; use esp_idf_sys::{esp_spiffs_info, vTaskDelay}; @@ -23,10 +28,6 @@ use std::str::FromStr; use std::sync::atomic::AtomicBool; use std::sync::Arc; 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"] 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"] static mut RESTART_TO_CONF: bool = false; - #[derive(Serialize, Debug)] pub struct FileInfo { filename: String, @@ -61,16 +61,15 @@ pub struct FileSystemSizeInfo { pub struct MqttClient<'a> { mqtt_client: EspMqttClient<'a>, - base_topic: heapless::String<64> + base_topic: heapless::String<64>, } pub struct ESP<'a> { pub(crate) mqtt_client: Option>, pub(crate) wifi_driver: EspWifi<'a>, 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<'_> { const SPIFFS_PARTITION_NAME: &'static str = "storage"; const CONFIG_FILE: &'static str = "/spiffs/config.cfg"; @@ -131,9 +130,7 @@ impl ESP<'_> { } pub(crate) fn low_voltage_in_cycle(&mut self) -> bool { - unsafe { - LOW_VOLTAGE_DETECTED - } + unsafe { LOW_VOLTAGE_DETECTED } } pub(crate) fn store_consecutive_pump_count(&mut self, plant: usize, count: u32) { unsafe { @@ -153,13 +150,9 @@ impl ESP<'_> { } pub(crate) fn wifi_ap(&mut self) -> anyhow::Result<()> { - let ssid = match self.load_config(){ - Ok(config) => { - config.network.ap_ssid.clone() - } - Err(_) => { - heapless::String::from_str("PlantCtrl Emergency Mode").unwrap() - } + let ssid = match self.load_config() { + Ok(config) => config.network.ap_ssid.clone(), + Err(_) => heapless::String::from_str("PlantCtrl Emergency Mode").unwrap(), }; let apconfig = AccessPointConfiguration { @@ -168,17 +161,17 @@ impl ESP<'_> { ssid_hidden: false, ..Default::default() }; - self.wifi_driver.set_configuration(&Configuration::AccessPoint(apconfig))?; + self.wifi_driver + .set_configuration(&Configuration::AccessPoint(apconfig))?; self.wifi_driver.start()?; anyhow::Ok(()) } - - pub(crate) fn wifi( - &mut self, - network_config: &NetworkConfig - ) -> anyhow::Result { - let ssid = network_config.ssid.clone().ok_or(anyhow!("No ssid configured"))?; + pub(crate) fn wifi(&mut self, network_config: &NetworkConfig) -> anyhow::Result { + let ssid = network_config + .ssid + .clone() + .ok_or(anyhow!("No ssid configured"))?; let password = network_config.password.clone(); let max_wait = network_config.max_wait; @@ -298,7 +291,6 @@ impl ESP<'_> { }) } - pub(crate) fn list_files(&self) -> FileList { let storage = CString::new(Self::SPIFFS_PARTITION_NAME).unwrap(); @@ -367,7 +359,7 @@ impl ESP<'_> { }) } - pub(crate) fn init_rtc_deepsleep_memory(&self, init_rtc_store: bool, to_config_mode: bool){ + pub(crate) fn init_rtc_deepsleep_memory(&self, init_rtc_store: bool, to_config_mode: bool) { if init_rtc_store { unsafe { LAST_WATERING_TIMESTAMP = [0; PLANT_COUNT]; @@ -544,9 +536,9 @@ impl ESP<'_> { match round_trip_ok.load(std::sync::atomic::Ordering::Relaxed) { true => { println!("Round trip registered, proceeding"); - self.mqtt_client = Some(MqttClient{ + self.mqtt_client = Some(MqttClient { mqtt_client: client, - base_topic: base_topic_copy + base_topic: base_topic_copy, }); return anyhow::Ok(()); } @@ -569,11 +561,7 @@ impl ESP<'_> { } bail!("Mqtt did not fire connection callback in time"); } - pub(crate) fn mqtt_publish( - &mut self, - subtopic: &str, - message: &[u8], - ) -> anyhow::Result<()> { + pub(crate) fn mqtt_publish(&mut self, subtopic: &str, message: &[u8]) -> anyhow::Result<()> { if self.mqtt_client.is_none() { return anyhow::Ok(()); } @@ -587,10 +575,7 @@ impl ESP<'_> { } let client = self.mqtt_client.as_mut().unwrap(); let mut full_topic: heapless::String<256> = heapless::String::new(); - if full_topic - .push_str(client.base_topic.as_str()) - .is_err() - { + if full_topic.push_str(client.base_topic.as_str()).is_err() { println!("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"); 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); match publish { OkStd(message_id) => { @@ -621,4 +608,4 @@ impl ESP<'_> { } } } -} \ No newline at end of file +} diff --git a/rust/src/hal/initial_hal.rs b/rust/src/hal/initial_hal.rs index 2325e5e..f11e416 100644 --- a/rust/src/hal/initial_hal.rs +++ b/rust/src/hal/initial_hal.rs @@ -1,11 +1,11 @@ use crate::config::{BoardHardware, PlantControllerConfig}; -use crate::hal::battery::{BatteryInteraction, BatteryMonitor}; +use crate::hal::battery::{BatteryInteraction, NoBatteryMonitor}; use crate::hal::esp::ESP; -use crate::hal::{deep_sleep, BackupHeader, BoardInteraction, Sensor, FreePeripherals}; -use esp_idf_hal::gpio::{IOPin, Pull}; +use crate::hal::{deep_sleep, BackupHeader, BoardInteraction, FreePeripherals, Sensor}; use anyhow::{bail, Result}; use chrono::{DateTime, Utc}; use embedded_hal::digital::OutputPin; +use esp_idf_hal::gpio::{IOPin, Pull}; use esp_idf_hal::gpio::{InputOutput, PinDriver}; pub struct Initial<'a> { @@ -32,7 +32,7 @@ pub(crate) fn create_initial_board( general_fault, config, esp, - battery: Box::new(BatteryMonitor::Disabled {}), + battery: Box::new(NoBatteryMonitor {}), }; Ok(Box::new(v)) } diff --git a/rust/src/hal/mod.rs b/rust/src/hal/mod.rs index a70ba24..232664c 100644 --- a/rust/src/hal/mod.rs +++ b/rust/src/hal/mod.rs @@ -4,6 +4,7 @@ mod initial_hal; mod v3_hal; mod v4_hal; +use battery::BQ34Z100G1; use bq34z100::Bq34z100g1Driver; use crate::log::LogMessage; @@ -35,7 +36,7 @@ use std::sync::Mutex; use std::time::Duration; use crate::config::{BatteryBoardVersion, BoardVersion, PlantControllerConfig}; -use crate::hal::battery::{print_battery_bq34z100, BatteryInteraction, BatteryMonitor}; +use crate::hal::battery::{print_battery_bq34z100, BatteryInteraction, NoBatteryMonitor}; use crate::hal::esp::ESP; use crate::hal::initial_hal::Initial; use crate::log::log; @@ -280,32 +281,35 @@ impl PlantHal { let hal = match config { Result::Ok(config) => { - let battery_monitor: BatteryMonitor = match config.hardware.battery { - BatteryBoardVersion::Disabled => BatteryMonitor::Disabled {}, - BatteryBoardVersion::BQ34Z100G1 => { - let mut battery_driver = Bq34z100g1Driver { - i2c: MutexDevice::new(&I2C_DRIVER), - delay: Delay::new(0), - flash_block_data: [0; 32], - }; - let status = print_battery_bq34z100(&mut battery_driver); - match status { - OkStd(_) => {} - Err(err) => { - log( - LogMessage::BatteryCommunicationError, - 0u32, - 0, - "", - &format!("{err:?})"), - ); + let battery_interaction: Box = + match config.hardware.battery { + BatteryBoardVersion::Disabled => Box::new(NoBatteryMonitor {}), + BatteryBoardVersion::BQ34Z100G1 => { + let mut battery_driver = Bq34z100g1Driver { + i2c: MutexDevice::new(&I2C_DRIVER), + delay: Delay::new(0), + flash_block_data: [0; 32], + }; + let status = print_battery_bq34z100(&mut battery_driver); + match status { + OkStd(_) => {} + Err(err) => { + log( + LogMessage::BatteryCommunicationError, + 0u32, + 0, + "", + &format!("{err:?})"), + ); + } } + Box::new(BQ34Z100G1 { battery_driver }) } - BatteryMonitor::BQ34Z100G1 { battery_driver } - } - BatteryBoardVersion::WchI2cSlave => BatteryMonitor::WchI2cSlave {}, - }; - let battery_interaction = Box::new(battery_monitor) as Box; + BatteryBoardVersion::WchI2cSlave => { + // TODO use correct implementation once availible + Box::new(NoBatteryMonitor {}) + } + }; let board_hal: Box = match config.hardware.board { BoardVersion::INITIAL => { diff --git a/rust/src/hal/v3_hal.rs b/rust/src/hal/v3_hal.rs index 1a32f24..ee2fbfe 100644 --- a/rust/src/hal/v3_hal.rs +++ b/rust/src/hal/v3_hal.rs @@ -1,5 +1,5 @@ use crate::config::PlantControllerConfig; -use crate::hal::battery::{BatteryInteraction, BatteryMonitor}; +use crate::hal::battery::BatteryInteraction; use crate::hal::esp::ESP; use crate::hal::{ deep_sleep, BackupHeader, BoardInteraction, FreePeripherals, Sensor, V3Constants, I2C_DRIVER, diff --git a/rust/src/hal/v4_hal.rs b/rust/src/hal/v4_hal.rs index f4e1cc6..b63141a 100644 --- a/rust/src/hal/v4_hal.rs +++ b/rust/src/hal/v4_hal.rs @@ -1,5 +1,5 @@ use crate::config::PlantControllerConfig; -use crate::hal::battery::{BatteryInteraction, BatteryMonitor}; +use crate::hal::battery::BatteryInteraction; use crate::hal::esp::ESP; use crate::hal::{ deep_sleep, BackupHeader, BoardInteraction, FreePeripherals, Sensor, I2C_DRIVER, PLANT_COUNT, @@ -23,12 +23,12 @@ use esp_idf_hal::pcnt::{ PcntChannel, PcntChannelConfig, PcntControlMode, PcntCountMode, PcntDriver, PinIndex, }; 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::calibration::{Calibration, UnCalibrated}; 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 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)?)?; - 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!("Shunt Voltage: {}", mppt_ina.shunt_voltage()?); 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); - - + let v = V4 { mppt_ina, esp, diff --git a/rust/src/main.rs b/rust/src/main.rs index 8a0be13..d2a63d1 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -12,6 +12,7 @@ use esp_idf_sys::{ esp_ota_img_states_t_ESP_OTA_IMG_VALID, vTaskDelay, }; use esp_ota::{mark_app_valid, rollback_and_reboot}; +use hal::battery::BatteryState; use log::{log, LogMessage}; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; @@ -21,16 +22,16 @@ use std::{ sync::{atomic::AtomicBool, Arc, Mutex}, }; mod config; -mod log; mod hal; +mod log; mod plant_state; 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 tank::*; -use crate::config::BoardVersion::INITIAL; -use crate::hal::{BoardInteraction, PlantHal, HAL, PLANT_COUNT}; -use crate::hal::battery::BatteryInteraction; pub static BOARD_ACCESS: Lazy> = Lazy::new(|| PlantHal::create().unwrap()); pub static STAY_ALIVE: Lazy = Lazy::new(|| AtomicBool::new(false)); @@ -72,7 +73,7 @@ struct LightState { #[derive(Serialize, Deserialize, Debug, PartialEq, Default)] ///mqtt stuct to track pump activities -struct PumpInfo{ +struct PumpInfo { enabled: bool, pump_ineffective: bool, } @@ -88,14 +89,16 @@ enum SensorError { #[derive(Serialize, Debug, PartialEq)] enum SntpMode { OFFLINE, - SYNC{ - current: DateTime - } + SYNC { current: DateTime }, } #[derive(Serialize, Debug, PartialEq)] -enum NetworkMode{ - WIFI {sntp: SntpMode, mqtt: bool, ip_address: String}, +enum NetworkMode { + WIFI { + sntp: SntpMode, + mqtt: bool, + ip_address: String, + }, OFFLINE, } @@ -150,10 +153,13 @@ fn safe_main() -> anyhow::Result<()> { }; 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); - let cur = board.board_hal + let cur = board + .board_hal .get_rtc_time() .or_else(|err| { println!("rtc module error: {:?}", err); @@ -172,7 +178,11 @@ fn safe_main() -> anyhow::Result<()> { } 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) => { let _ = board.board_hal.set_charge_indicator(charging > 20); } @@ -208,7 +218,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(); drop(board); let reboot_now = Arc::new(AtomicBool::new(false)); @@ -234,7 +246,7 @@ fn safe_main() -> anyhow::Result<()> { } } - let timezone = match & board.board_hal.get_config().timezone { + let timezone = match &board.board_hal.get_config().timezone { Some(tz_str) => tz_str.parse::().unwrap_or_else(|_| { println!("Invalid timezone '{}', falling back to UTC", tz_str); UTC @@ -251,16 +263,30 @@ fn safe_main() -> anyhow::Result<()> { ); 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); } - log( LogMessage::StartupInfo, matches!(network_mode, NetworkMode::WIFI { .. }) as u32, - matches!(network_mode, NetworkMode::WIFI { sntp: SntpMode::SYNC { .. }, .. }) as u32, - matches!(network_mode, NetworkMode::WIFI { mqtt: true, .. }).to_string().as_str(), + matches!( + network_mode, + NetworkMode::WIFI { + sntp: SntpMode::SYNC { .. }, + .. + } + ) as u32, + matches!(network_mode, NetworkMode::WIFI { mqtt: true, .. }) + .to_string() + .as_str(), "", ); @@ -304,7 +330,10 @@ fn safe_main() -> anyhow::Result<()> { } // disabled cannot trigger this because of wrapping if is_enabled 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, "", ""); board.board_hal.general_fault(true); } @@ -332,10 +361,17 @@ fn safe_main() -> anyhow::Result<()> { && !water_frozen; if pump_required { 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) { 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; if pump_ineffective { @@ -343,7 +379,7 @@ fn safe_main() -> anyhow::Result<()> { LogMessage::ConsecutivePumpCountLimit, pump_count, plant_config.max_consecutive_pump_count as u32, - &(plant_id+1).to_string(), + &(plant_id + 1).to_string(), "", ); board.board_hal.fault(plant_id, true)?; @@ -355,29 +391,45 @@ fn safe_main() -> anyhow::Result<()> { &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); //state.active = true; - pump_info(&mut board, plant_id, true, pump_ineffective); + pump_info(&mut board, plant_id, true, pump_ineffective); if !dry_run { board.board_hal.pump(plant_id, true)?; Delay::new_default().delay_ms(1000 * plant_config.pump_time_s as u32); 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) { // plant does not need to be watered and is not in timeout // -> 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 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.); + + /// try to load full battery state if failed the battery state is unknown + let battery_state = board + .board_hal + .get_battery_monitor() + .get_battery_state() + .unwrap_or(hal::battery::BatteryState::Unknown); let mut light_state = LightState { enabled: board.board_hal.get_config().night_lamp.enabled, @@ -387,19 +439,42 @@ fn safe_main() -> anyhow::Result<()> { light_state.is_day = is_day; light_state.out_of_work_hour = !in_time_range( &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, ); - if state_of_charge < board.board_hal.get_config().night_lamp.low_soc_cutoff { + if state_of_charge + < board + .board_hal + .get_config() + .night_lamp + .low_soc_cutoff + .into() + { board.board_hal.get_esp().set_low_voltage_in_cycle(); - } else if state_of_charge > board.board_hal.get_config().night_lamp.low_soc_restore { + } else if state_of_charge + > board + .board_hal + .get_config() + .night_lamp + .low_soc_restore + .into() + { board.board_hal.get_esp().clear_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 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.battery_low { board.board_hal.light(false)?; @@ -424,24 +499,41 @@ fn safe_main() -> anyhow::Result<()> { match serde_json::to_string(&light_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) => { println!("Error publishing lightstate {}", err); } }; - 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()); - 12 * 60 - } else if is_day { - let _ = board.board_hal.get_esp().mqtt_publish( "/deepsleep", "normal 20m".as_bytes()); - 20 - } else { - let _ = board.board_hal.get_esp().mqtt_publish( "/deepsleep", "night 1h".as_bytes()); - 60 - }; - let _ = board.board_hal.get_esp().mqtt_publish( "/state", "sleep".as_bytes()); + let deep_sleep_duration_minutes: u32 = + // if battery soc is unknown assume battery has enough change + if state_of_charge < 10.0 && !matches!(battery_state, BatteryState::Unknown) { + let _ = board + .board_hal + .get_esp() + .mqtt_publish("/deepsleep", "low Volt 12h".as_bytes()); + 12 * 60 + } else if is_day { + let _ = board + .board_hal + .get_esp() + .mqtt_publish("/deepsleep", "normal 20m".as_bytes()); + 20 + } else { + let _ = board + .board_hal + .get_esp() + .mqtt_publish("/deepsleep", "night 1h".as_bytes()); + 60 + }; + let _ = board + .board_hal + .get_esp() + .mqtt_publish("/state", "sleep".as_bytes()); //determine next event //is light out of work trigger soon? @@ -462,7 +554,9 @@ fn safe_main() -> anyhow::Result<()> { wait_infinity(WaitType::MqttConfig, reboot_now.clone()); } 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) -> anyhow::Result { @@ -487,10 +581,19 @@ fn obtain_tank_temperature(board: &mut MutexGuard) -> anyhow::Result { water_temp } -fn publish_tank_state(board: &mut MutexGuard, tank_state: &TankState, water_temp: &anyhow::Result) { - match serde_json::to_string(&tank_state.as_mqtt_info(&board.board_hal.get_config().tank, water_temp)) { +fn publish_tank_state( + board: &mut MutexGuard, + tank_state: &TankState, + water_temp: &anyhow::Result, +) { + match serde_json::to_string( + &tank_state.as_mqtt_info(&board.board_hal.get_config().tank, water_temp), + ) { 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) => { println!("Error publishing tankstate {}", err); @@ -498,12 +601,23 @@ fn publish_tank_state(board: &mut MutexGuard, tank_state: &TankState, water }; } -fn publish_plant_states(board: &mut MutexGuard, timezone_time: &DateTime, plantstate: &[PlantState; 8]) { - for (plant_id, (plant_state, plant_conf)) in plantstate.iter().zip(& board.board_hal.get_config().plants.clone()).enumerate() { +fn publish_plant_states( + board: &mut MutexGuard, + timezone_time: &DateTime, + 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)) { Ok(state) => { 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 board.board_hal.get_esp().delay.delay_ms(200); } @@ -514,26 +628,45 @@ fn publish_plant_states(board: &mut MutexGuard, timezone_time: &DateTime, ip_address: &String, timezone_time: DateTime) { - 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(), - ); +fn publish_firmware_info( + version: VersionInfo, + address: u32, + ota_state_string: &str, + board: &mut MutexGuard, + ip_address: &String, + timezone_time: DateTime, +) { + 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( "/firmware/last_online", 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( "/firmware/partition_address", 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) -> NetworkMode{ +fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard) -> NetworkMode { let nw_conf = &board.board_hal.get_config().network.clone(); match board.board_hal.get_esp().wifi(nw_conf) { Ok(ip_info) => { @@ -541,7 +674,7 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard) -> NetworkMode{ Ok(new_time) => { println!("Using time from sntp"); let _ = board.board_hal.set_rtc_time(&new_time); - SntpMode::SYNC {current: new_time} + SntpMode::SYNC { current: new_time } } Err(err) => { println!("sntp error: {}", err); @@ -567,7 +700,7 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard) -> NetworkMode{ NetworkMode::WIFI { sntp: sntp_mode, mqtt: mqtt_connected, - ip_address: ip_info.ip.to_string() + ip_address: ip_info.ip.to_string(), } } Err(_) => { @@ -578,15 +711,23 @@ fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard) -> NetworkMode{ } } -fn pump_info(board: &mut MutexGuard, plant_id: usize, pump_active: bool, pump_ineffective: bool) { +fn pump_info( + board: &mut MutexGuard, + plant_id: usize, + pump_active: bool, + pump_ineffective: bool, +) { let pump_info = PumpInfo { enabled: pump_active, - pump_ineffective + pump_ineffective, }; let pump_topic = format!("/pump{}", plant_id + 1); match serde_json::to_string(&pump_info) { 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 Delay::new_default().delay_ms(200); } @@ -596,11 +737,15 @@ fn pump_info(board: &mut MutexGuard, plant_id: usize, pump_active: bool, pu }; } -fn publish_battery_state( - board: &mut MutexGuard<'_, HAL<'_>> -) { +fn publish_battery_state(board: &mut MutexGuard<'_, HAL<'_>>) { let state = board.board_hal.get_battery_monitor().get_battery_state(); - let _ = board.board_hal.get_esp().mqtt_publish( "/battery", state.as_bytes()); + if let Ok(serialized_battery_state_bytes) = serde_json::to_string(&state).map(|s| s.into_bytes()) + { + let _ = board + .board_hal + .get_esp() + .mqtt_publish("/battery", &serialized_battery_state_bytes); + } } fn wait_infinity(wait_type: WaitType, reboot_now: Arc) -> ! { @@ -611,7 +756,11 @@ fn wait_infinity(wait_type: WaitType, reboot_now: Arc) -> ! { loop { unsafe { 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); } match wait_type { @@ -673,7 +822,12 @@ fn main() { // timeout, this is just a fallback Ok(_) => { 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); } // if safe_main exists with an error, rollback to a known good ota version diff --git a/rust/src/plant_state.rs b/rust/src/plant_state.rs index 2495fb9..e3272ee 100644 --- a/rust/src/plant_state.rs +++ b/rust/src/plant_state.rs @@ -2,8 +2,8 @@ use chrono::{DateTime, TimeDelta, Utc}; use chrono_tz::Tz; use serde::{Deserialize, Serialize}; -use crate::{config::PlantConfig, in_time_range}; 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_MIN_FREQUENCY: f32 = 150.; // this is really, really dry, think like cactus levels @@ -112,10 +112,7 @@ fn map_range_moisture( } impl PlantState { - pub fn read_hardware_state( - plant_id: usize, - board: &mut HAL - ) -> Self { + pub fn read_hardware_state(plant_id: usize, board: &mut HAL) -> Self { 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) { Ok(raw) => match map_range_moisture( diff --git a/rust/src/tank.rs b/rust/src/tank.rs index 9f3aec9..fde2936 100644 --- a/rust/src/tank.rs +++ b/rust/src/tank.rs @@ -114,11 +114,7 @@ impl TankState { } } - pub fn as_mqtt_info( - &self, - config: &TankConfig, - water_temp: &anyhow::Result, - ) -> TankInfo { + pub fn as_mqtt_info(&self, config: &TankConfig, water_temp: &anyhow::Result) -> TankInfo { let mut tank_err: Option = None; let left_ml = match self.left_ml(config) { Err(err) => { @@ -155,9 +151,7 @@ impl TankState { } } -pub fn determine_tank_state( - board: &mut std::sync::MutexGuard<'_, HAL<'_>> -) -> TankState { +pub fn determine_tank_state(board: &mut std::sync::MutexGuard<'_, HAL<'_>>) -> TankState { if board.board_hal.get_config().tank.tank_sensor_enabled { match board.board_hal.tank_sensor_voltage() { Ok(raw_sensor_value_mv) => TankState::Present(raw_sensor_value_mv), diff --git a/rust/src/webserver/webserver.rs b/rust/src/webserver/webserver.rs index f8872a3..53ca85d 100644 --- a/rust/src/webserver/webserver.rs +++ b/rust/src/webserver/webserver.rs @@ -2,8 +2,7 @@ use crate::hal::battery::BatteryInteraction; use crate::{ - determine_tank_state, get_version, log::LogMessage, - plant_state::PlantState, BOARD_ACCESS, + determine_tank_state, get_version, log::LogMessage, plant_state::PlantState, BOARD_ACCESS, }; use anyhow::bail; use chrono::DateTime; @@ -83,11 +82,14 @@ fn get_time( _request: &mut Request<&mut EspHttpConnection>, ) -> Result, anyhow::Error> { let mut board = BOARD_ACCESS.lock().expect("board access"); - let native = board.board_hal.get_esp() + let native = board + .board_hal + .get_esp() .time() .map(|t| t.to_rfc3339()) .unwrap_or("error".to_string()); - let rtc = board.board_hal + let rtc = board + .board_hal .get_rtc_time() .map(|t| t.to_rfc3339()) .unwrap_or("error".to_string()); @@ -116,35 +118,28 @@ fn get_live_moisture( _request: &mut Request<&mut EspHttpConnection>, ) -> Result, anyhow::Error> { let mut board = BOARD_ACCESS.lock().expect("Should never fail"); - let plant_state = 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 { - MoistureSensorState::Disabled => "disabled".to_string(), - MoistureSensorState::MoistureValue {raw_hz, moisture_percent } => { - format!("{moisture_percent:.2}% {raw_hz}hz",) - } - MoistureSensorState::SensorError(err) => format!("{err:?}"), - } - }) - ); - let b = Vec::from_iter( - plant_state - .iter() - .map(|s| { - match &s.sensor_b { - MoistureSensorState::Disabled => "disabled".to_string(), - MoistureSensorState::MoistureValue {raw_hz, moisture_percent } => { - format!("{moisture_percent:.2}% {raw_hz}hz",) - } - MoistureSensorState::SensorError(err) => format!("{err:?}"), - } - }) - ); + let plant_state = + 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 { + MoistureSensorState::Disabled => "disabled".to_string(), + MoistureSensorState::MoistureValue { + raw_hz, + moisture_percent, + } => { + format!("{moisture_percent:.2}% {raw_hz}hz",) + } + MoistureSensorState::SensorError(err) => format!("{err:?}"), + })); + let b = Vec::from_iter(plant_state.iter().map(|s| match &s.sensor_b { + MoistureSensorState::Disabled => "disabled".to_string(), + MoistureSensorState::MoistureValue { + raw_hz, + moisture_percent, + } => { + format!("{moisture_percent:.2}% {raw_hz}hz",) + } + MoistureSensorState::SensorError(err) => format!("{err:?}"), + })); let data = Moistures { moisture_a: a, @@ -228,7 +223,7 @@ fn get_battery_state( ) -> Result, anyhow::Error> { let mut board = BOARD_ACCESS.lock().expect("board access"); let battery_state = board.board_hal.get_battery_monitor().get_battery_state(); - anyhow::Ok(Some(battery_state)) + anyhow::Ok(Some(serde_json::to_string(&battery_state)?)) } fn get_log( @@ -267,9 +262,10 @@ fn tank_info( let tank_info = determine_tank_state(&mut board); //should be multsampled let water_temp = board.board_hal.water_temperature_c(); - Ok(Some(serde_json::to_string( - &tank_info.as_mqtt_info(&board.board_hal.get_config().tank, &water_temp), - )?)) + Ok(Some(serde_json::to_string(&tank_info.as_mqtt_info( + &board.board_hal.get_config().tank, + &water_temp, + ))?)) } fn night_lamp_test( @@ -297,7 +293,9 @@ fn wifi_scan( fn list_files( _request: &mut Request<&mut EspHttpConnection>, ) -> Result, 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 file_list_json = serde_json::to_string(&result)?; anyhow::Ok(Some(file_list_json)) @@ -469,7 +467,12 @@ pub fn httpd(reboot_now: Arc) -> Box> { let reboot_now_for_reboot = reboot_now.clone(); server .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); anyhow::Ok(()) }) @@ -490,7 +493,8 @@ pub fn httpd(reboot_now: Arc) -> Box> { let file_handle = BOARD_ACCESS .lock() .unwrap() - .board_hal.get_esp() + .board_hal + .get_esp() .get_file_handle(&filename, false); match file_handle { Ok(mut file_handle) => {