Refactor Battery State for more robustness against missing BatteryMonitor #17
| @@ -32,7 +32,7 @@ pub(crate) fn create_initial_board( | ||||
|         general_fault, | ||||
|         config, | ||||
|         esp, | ||||
|         battery: Box::new(NoBatteryMonitor{}), | ||||
|         battery: Box::new(NoBatteryMonitor {}), | ||||
|     }; | ||||
|     Ok(Box::new(v)) | ||||
| } | ||||
|   | ||||
| @@ -281,34 +281,35 @@ impl PlantHal { | ||||
|  | ||||
|         let hal = match config { | ||||
|             Result::Ok(config) => { | ||||
|                 let battery_interaction: Box<dyn BatteryInteraction + Send> = 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:?})"), | ||||
|                                 ); | ||||
|                 let battery_interaction: Box<dyn BatteryInteraction + Send> = | ||||
|                     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 }) | ||||
|                         } | ||||
|                         Box::new(BQ34Z100G1 { battery_driver }) | ||||
|                     } | ||||
|                     BatteryBoardVersion::WchI2cSlave => { | ||||
|                         // TODO use correct implementation once availible | ||||
|                         Box::new(NoBatteryMonitor{}) | ||||
|                     }, | ||||
|                 }; | ||||
|                         BatteryBoardVersion::WchI2cSlave => { | ||||
|                             // TODO use correct implementation once availible | ||||
|                             Box::new(NoBatteryMonitor {}) | ||||
|                         } | ||||
|                     }; | ||||
|  | ||||
|                 let board_hal: Box<dyn BoardInteraction + Send> = match config.hardware.board { | ||||
|                     BoardVersion::INITIAL => { | ||||
|   | ||||
| @@ -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}; | ||||
| @@ -421,7 +422,14 @@ fn safe_main() -> anyhow::Result<()> { | ||||
|         .board_hal | ||||
|         .get_battery_monitor() | ||||
|         .state_charge_percent() | ||||
|         .unwrap_or(0); | ||||
|         .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, | ||||
| @@ -439,9 +447,23 @@ fn safe_main() -> anyhow::Result<()> { | ||||
|             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(); | ||||
| @@ -487,25 +509,27 @@ fn safe_main() -> anyhow::Result<()> { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     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 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() | ||||
| @@ -715,10 +739,13 @@ fn pump_info( | ||||
|  | ||||
| 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<AtomicBool>) -> ! { | ||||
|   | ||||
| @@ -223,7 +223,7 @@ fn get_battery_state( | ||||
| ) -> Result<Option<std::string::String>, 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( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user