use anyhow::bail; 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; } #[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, } pub enum BatteryMonitor<'a> { Disabled { }, BQ34Z100G1 { battery_driver: Bq34z100g1Driver>, Delay> }, WchI2cSlave { } } 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") } } } 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 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()), }; match serde_json::to_string(&bat) { Ok(state) => { state } Err(err) => { format!("{:?}", err).to_owned() } } } } pub fn print_battery_bq34z100( battery_driver: &mut Bq34z100g1Driver>, Delay>, ) -> anyhow::Result<(), Bq34Z100Error> { println!("Try communicating with battery"); let fwversion = battery_driver.fw_version().unwrap_or_else(|e| { println!("Firmware {:?}", e); 0 }); println!("fw version is {}", fwversion); let design_capacity = battery_driver.design_capacity().unwrap_or_else(|e| { println!("Design capacity {:?}", e); 0 }); println!("Design Capacity {}", design_capacity); if design_capacity == 1000 { println!("Still stock configuring battery, readouts are likely to be wrong!"); } let flags = battery_driver.get_flags_decoded()?; println!("Flags {:?}", flags); let chem_id = battery_driver.chem_id().unwrap_or_else(|e| { println!("Chemid {:?}", e); 0 }); let bat_temp = battery_driver.internal_temperature().unwrap_or_else(|e| { println!("Bat Temp {:?}", e); 0 }); let temp_c = Temperature::from_kelvin(bat_temp as f64 / 10_f64).as_celsius(); let voltage = battery_driver.voltage().unwrap_or_else(|e| { println!("Bat volt {:?}", e); 0 }); let current = battery_driver.current().unwrap_or_else(|e| { println!("Bat current {:?}", e); 0 }); let state = battery_driver.state_of_charge().unwrap_or_else(|e| { println!("Bat Soc {:?}", e); 0 }); let charge_voltage = battery_driver.charge_voltage().unwrap_or_else(|e| { println!("Bat Charge Volt {:?}", e); 0 }); let charge_current = battery_driver.charge_current().unwrap_or_else(|e| { println!("Bat Charge Current {:?}", e); 0 }); println!("ChemId: {} Current voltage {} and current {} with charge {}% and temp {} CVolt: {} CCur {}", chem_id, voltage, current, state, temp_c, charge_voltage, charge_current); let _ = battery_driver.unsealed(); let _ = battery_driver.it_enable(); anyhow::Result::Ok(()) }