diff --git a/Software/MainBoard/.idea/MainBoard.iml b/Software/MainBoard/.idea/MainBoard.iml index f8e3774..7ee6b6c 100644 --- a/Software/MainBoard/.idea/MainBoard.iml +++ b/Software/MainBoard/.idea/MainBoard.iml @@ -3,6 +3,7 @@ + diff --git a/Software/MainBoard/rust/Cargo.toml b/Software/MainBoard/rust/Cargo.toml index cf4c5f7..34e4b80 100644 --- a/Software/MainBoard/rust/Cargo.toml +++ b/Software/MainBoard/rust/Cargo.toml @@ -95,12 +95,12 @@ embedded-can = "0.4.1" nb = "1.1.0" # Concrete hardware drivers and sensors/IO expanders +lib-bms-protocol = {git = "https://gitea.wlandt.de/judge/ch32-bms.git" , default-features = false } onewire = "0.4.0" ds323x = "0.7.0" eeprom24x = "0.7.2" pca9535 = { version = "2.0.0" } ina219 = { version = "0.2.0" } -bq34z100 = { version = "0.4.0", default-features = false } # Storage and filesystem littlefs2 = { version = "0.6.1", features = ["c-stubs", "alloc"] } diff --git a/Software/MainBoard/rust/src/config.rs b/Software/MainBoard/rust/src/config.rs index f437d44..5dd6a7b 100644 --- a/Software/MainBoard/rust/src/config.rs +++ b/Software/MainBoard/rust/src/config.rs @@ -83,7 +83,6 @@ impl Default for TankConfig { pub enum BatteryBoardVersion { #[default] Disabled, - BQ34Z100G1, WchI2cSlave, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] diff --git a/Software/MainBoard/rust/src/fat_error.rs b/Software/MainBoard/rust/src/fat_error.rs index 96bbe11..5e6bbe0 100644 --- a/Software/MainBoard/rust/src/fat_error.rs +++ b/Software/MainBoard/rust/src/fat_error.rs @@ -2,6 +2,7 @@ use alloc::format; use alloc::string::{String, ToString}; use core::convert::Infallible; use core::fmt; +use core::fmt::Debug; use core::str::Utf8Error; use embassy_embedded_hal::shared_bus::I2cDeviceError; use embassy_executor::SpawnError; @@ -12,6 +13,7 @@ use esp_hal::pcnt::unit::{InvalidHighLimit, InvalidLowLimit}; use esp_hal::twai::EspTwaiError; use esp_radio::wifi::WifiError; use ina219::errors::{BusVoltageReadError, ShuntVoltageReadError}; +use lib_bms_protocol::BmsProtocolError; use littlefs2_core::PathError; use onewire::Error; use pca9535::ExpanderError; @@ -19,6 +21,9 @@ use pca9535::ExpanderError; //All error superconstruct #[derive(Debug)] pub enum FatError { + BMSError { + error: String, + }, OneWireError { error: Error, }, @@ -100,6 +105,7 @@ impl fmt::Display for FatError { write!(f, "CanBusError {error:?}") } FatError::SNTPError { error } => write!(f, "SNTPError {error:?}"), + FatError::BMSError { error } => write!(f, "BMSError, {error}"), } } } @@ -316,3 +322,14 @@ impl From for FatError { FatError::SNTPError { error: value } } } + + +impl From for FatError{ + fn from(value: BmsProtocolError) -> Self { + match value { + BmsProtocolError::I2cCommunicationError => { + FatError::String{error: "I2C communication error".to_string()} + } + } + } +} \ No newline at end of file diff --git a/Software/MainBoard/rust/src/hal/battery.rs b/Software/MainBoard/rust/src/hal/battery.rs index e3c7592..a387ac0 100644 --- a/Software/MainBoard/rust/src/hal/battery.rs +++ b/Software/MainBoard/rust/src/hal/battery.rs @@ -1,39 +1,30 @@ -use crate::fat_error::{FatError, FatResult}; use crate::hal::Box; +use crate::fat_error::{FatError, FatResult}; use async_trait::async_trait; -use bq34z100::{Bq34z100g1, Bq34z100g1Driver, Flags}; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use esp_hal::delay::Delay; use esp_hal::i2c::master::I2c; use esp_hal::Blocking; -use measurements::Temperature; +use lib_bms_protocol::{BatteryState as bstate, BmsReadable, Config, FirmwareVersion, ProtocolVersion}; use serde::Serialize; #[async_trait(?Send)] pub trait BatteryInteraction { - async fn state_charge_percent(&mut self) -> FatResult; - async fn remaining_milli_ampere_hour(&mut self) -> FatResult; - async fn max_milli_ampere_hour(&mut self) -> FatResult; - async fn design_milli_ampere_hour(&mut self) -> FatResult; - async fn voltage_milli_volt(&mut self) -> FatResult; - async fn average_current_milli_ampere(&mut self) -> FatResult; - async fn cycle_count(&mut self) -> FatResult; - async fn state_health_percent(&mut self) -> FatResult; - async fn bat_temperature(&mut self) -> FatResult; - async fn get_battery_state(&mut self) -> FatResult; + async fn get_state(&mut self) -> FatResult; + async fn get_firmware(&mut self) -> FatResult; + async fn get_protocol(&mut self) -> FatResult; + async fn reset(&mut self) -> FatResult<()>; } #[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 voltage_milli_volt: u32, + pub average_current_milli_ampere: i32, + pub design_milli_ampere_hour: u32, + pub remaining_milli_ampere_hour: u32, + pub state_of_charge: u8, + pub state_of_health: u32, + pub temperature: i32, } #[derive(Debug, Serialize)] @@ -46,213 +37,62 @@ pub enum BatteryState { pub struct NoBatteryMonitor {} #[async_trait(?Send)] impl BatteryInteraction for NoBatteryMonitor { - async fn state_charge_percent(&mut self) -> FatResult { - // No monitor configured: assume full battery for lightstate logic - Ok(100.0) - } - - async fn remaining_milli_ampere_hour(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn max_milli_ampere_hour(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn design_milli_ampere_hour(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn voltage_milli_volt(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn average_current_milli_ampere(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn cycle_count(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn state_health_percent(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn bat_temperature(&mut self) -> FatResult { - Err(FatError::NoBatteryMonitor) - } - - async fn get_battery_state(&mut self) -> FatResult { + async fn get_state(&mut self) -> FatResult { Ok(BatteryState::Unknown) } + + async fn get_firmware(&mut self) -> FatResult { + Err(FatError::NoBatteryMonitor) + } + + async fn get_protocol(&mut self) -> FatResult { + Err(FatError::NoBatteryMonitor) + } + + async fn reset(&mut self) -> FatResult<()> { + Err(FatError::NoBatteryMonitor) + } } //TODO implement this battery monitor kind once controller is complete #[allow(dead_code)] pub struct WchI2cSlave {} -pub type I2cDev = I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Blocking>>; - -pub struct BQ34Z100G1 { - pub battery_driver: Bq34z100g1Driver, +pub struct WCHI2CSlave<'a> { + pub(crate) i2c: I2cDevice<'a, CriticalSectionRawMutex, I2c<'a, Blocking>> } #[async_trait(?Send)] -impl BatteryInteraction for BQ34Z100G1 { - async fn state_charge_percent(&mut self) -> FatResult { - self.battery_driver - .state_of_charge() - .map(|v| v as f32) - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } +impl BatteryInteraction for WCHI2CSlave<'_> { - async fn remaining_milli_ampere_hour(&mut self) -> FatResult { - self.battery_driver - .remaining_capacity() - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } - async fn max_milli_ampere_hour(&mut self) -> FatResult { - self.battery_driver - .full_charge_capacity() - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } + async fn get_state(&mut self) -> FatResult { + let state = bstate::read_from_i2c(&mut self.i2c)?; + let config = Config::read_from_i2c(&mut self.i2c)?; - async fn design_milli_ampere_hour(&mut self) -> FatResult { - self.battery_driver - .design_capacity() - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } + let state_of_charge = (state.remaining_capacity_mah * 100 / state.lifetime_capacity_mah) as u8; + let state_of_health = state.lifetime_capacity_mah / config.capacity_mah * 100; - async fn voltage_milli_volt(&mut self) -> FatResult { - self.battery_driver.voltage().map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } - - async fn average_current_milli_ampere(&mut self) -> FatResult { - self.battery_driver - .average_current() - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } - - async fn cycle_count(&mut self) -> FatResult { - self.battery_driver - .cycle_count() - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } - - async fn state_health_percent(&mut self) -> FatResult { - self.battery_driver - .state_of_health() - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } - - async fn bat_temperature(&mut self) -> FatResult { - self.battery_driver - .temperature() - .map_err(|e| FatError::String { - error: alloc::format!("{e:?}"), - }) - } - - async fn get_battery_state(&mut self) -> FatResult { Ok(BatteryState::Info(BatteryInfo { - voltage_milli_volt: self.voltage_milli_volt().await?, - average_current_milli_ampere: self.average_current_milli_ampere().await?, - cycle_count: self.cycle_count().await?, - design_milli_ampere_hour: self.design_milli_ampere_hour().await?, - remaining_milli_ampere_hour: self.remaining_milli_ampere_hour().await?, - state_of_charge: self.state_charge_percent().await?, - state_of_health: self.state_health_percent().await?, - temperature: self.bat_temperature().await?, + voltage_milli_volt: state.current_mv, + average_current_milli_ampere: 1337, + design_milli_ampere_hour: config.capacity_mah, + remaining_milli_ampere_hour: state.remaining_capacity_mah, + state_of_charge, + state_of_health, + temperature: state.temperature_celcius, })) } -} -pub fn print_battery_bq34z100( - battery_driver: &mut Bq34z100g1Driver>, Delay>, -) -> FatResult<()> { - log::info!("Try communicating with battery"); - let fwversion = battery_driver.fw_version().unwrap_or_else(|e| { - log::info!("Firmware {e:?}"); - 0 - }); - log::info!("fw version is {fwversion}"); - - let design_capacity = battery_driver.design_capacity().unwrap_or_else(|e| { - log::info!("Design capacity {e:?}"); - 0 - }); - log::info!("Design Capacity {design_capacity}"); - if design_capacity == 1000 { - log::info!("Still stock configuring battery, readouts are likely to be wrong!"); + async fn get_firmware(&mut self) -> FatResult { + todo!() } - let flags = battery_driver.get_flags_decoded().unwrap_or(Flags { - fast_charge_allowed: false, - full_chage: false, - charging_not_allowed: false, - charge_inhibit: false, - bat_low: false, - bat_high: false, - over_temp_discharge: false, - over_temp_charge: false, - discharge: false, - state_of_charge_f: false, - state_of_charge_1: false, - cf: false, - ocv_taken: false, - }); - log::info!("Flags {flags:?}"); + async fn get_protocol(&mut self) -> FatResult { + todo!() + } - let chem_id = battery_driver.chem_id().unwrap_or_else(|e| { - log::info!("Chemid {e:?}"); - 0 - }); - - let bat_temp = battery_driver.internal_temperature().unwrap_or_else(|e| { - log::info!("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| { - log::info!("Bat volt {e:?}"); - 0 - }); - let current = battery_driver.current().unwrap_or_else(|e| { - log::info!("Bat current {e:?}"); - 0 - }); - let state = battery_driver.state_of_charge().unwrap_or_else(|e| { - log::info!("Bat Soc {e:?}"); - 0 - }); - let charge_voltage = battery_driver.charge_voltage().unwrap_or_else(|e| { - log::info!("Bat Charge Volt {e:?}"); - 0 - }); - let charge_current = battery_driver.charge_current().unwrap_or_else(|e| { - log::info!("Bat Charge Current {e:?}"); - 0 - }); - log::info!("ChemId: {chem_id} Current voltage {voltage} and current {current} with charge {state}% and temp {temp_c} CVolt: {charge_voltage} CCur {charge_current}"); - let _ = battery_driver.unsealed(); - let _ = battery_driver.it_enable(); - Ok(()) -} + async fn reset(&mut self) -> FatResult<()> { + todo!() + } +} \ No newline at end of file diff --git a/Software/MainBoard/rust/src/hal/mod.rs b/Software/MainBoard/rust/src/hal/mod.rs index 04e2175..e0515a1 100644 --- a/Software/MainBoard/rust/src/hal/mod.rs +++ b/Software/MainBoard/rust/src/hal/mod.rs @@ -1,3 +1,4 @@ +use lib_bms_protocol::BmsReadable; pub(crate) mod battery; // mod can_api; // replaced by external canapi crate pub mod esp; @@ -8,6 +9,7 @@ mod shared_flash; mod v4_hal; mod water; +use lib_bms_protocol::ProtocolVersion; use crate::alloc::string::ToString; use crate::hal::rtc::{DS3231Module, RTCModuleInteraction}; use esp_hal::peripherals::Peripherals; @@ -50,7 +52,6 @@ use alloc::format; use alloc::sync::Arc; use async_trait::async_trait; use bincode::{Decode, Encode}; -use bq34z100::Bq34z100g1Driver; use canapi::SensorSlot; use chrono::{DateTime, FixedOffset, Utc}; use core::cell::RefCell; @@ -72,7 +73,7 @@ use esp_hal::gpio::{Input, InputConfig, Pull}; use measurements::{Current, Voltage}; use crate::fat_error::{ContextExt, FatError, FatResult}; -use crate::hal::battery::{print_battery_bq34z100, BQ34Z100G1}; +use crate::hal::battery::{WCHI2CSlave}; use crate::hal::little_fs2storage_adapter::LittleFs2Filesystem; use crate::hal::water::TankSensor; use crate::log::LOG_ACCESS; @@ -485,6 +486,7 @@ impl PlantHal { let i2c_bus = I2C_DRIVER.get().await; let rtc_device = I2cDevice::new(i2c_bus); + let mut bms_device = I2cDevice::new(i2c_bus); let eeprom_device = I2cDevice::new(i2c_bus); let mut rtc: Ds323x< @@ -519,35 +521,18 @@ impl PlantHal { let battery_interaction: Box = match config.hardware.battery { BatteryBoardVersion::Disabled => Box::new(NoBatteryMonitor {}), - BatteryBoardVersion::BQ34Z100G1 => { - let battery_device = I2cDevice::new(I2C_DRIVER.get().await); - let mut battery_driver = Bq34z100g1Driver { - i2c: battery_device, - delay: Delay::new(), - flash_block_data: [0; 32], - }; - let status = print_battery_bq34z100(&mut battery_driver); - match status { - Ok(_) => {} - Err(err) => { - LOG_ACCESS - .lock() - .await - .log( - LogMessage::BatteryCommunicationError, - 0u32, - 0, - "", - &format!("{err:?})"), - ) - .await; - } - } - Box::new(BQ34Z100G1 { battery_driver }) - } BatteryBoardVersion::WchI2cSlave => { - // TODO use correct implementation once availible - Box::new(NoBatteryMonitor {}) + let version = ProtocolVersion::read_from_i2c(&mut bms_device); + let version_val = match version { + Ok(v) => unsafe { core::mem::transmute::(v) }, + Err(_) => 0, + }; + if version_val == 1 { + Box::new(WCHI2CSlave { i2c: bms_device }) + } else { + //todo should be an error variant instead? + Box::new(NoBatteryMonitor {}) + } } }; diff --git a/Software/MainBoard/rust/src/log/mod.rs b/Software/MainBoard/rust/src/log/mod.rs index a340ace..33a15a5 100644 --- a/Software/MainBoard/rust/src/log/mod.rs +++ b/Software/MainBoard/rust/src/log/mod.rs @@ -280,6 +280,8 @@ pub enum LogMessage { PumpOpenLoopCurrent, #[strum(serialize = "Pump Open current sensor required but did not work: ${number_a}")] PumpMissingSensorCurrent, + #[strum(serialize = "MPPT Current sensor could not be reached")] + MPPTError, } #[derive(Serialize)] diff --git a/Software/MainBoard/rust/src/main.rs b/Software/MainBoard/rust/src/main.rs index 19c311a..6d7b94e 100644 --- a/Software/MainBoard/rust/src/main.rs +++ b/Software/MainBoard/rust/src/main.rs @@ -492,22 +492,18 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { info!("state of charg"); let is_day = board.board_hal.is_day(); - let state_of_charge = board - .board_hal - .get_battery_monitor() - .state_charge_percent() - .await - .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() - .await - .unwrap_or(BatteryState::Unknown); - + let battery_state = board.board_hal.get_battery_monitor().get_state().await.unwrap_or(BatteryState::Unknown); info!("Battery state is {battery_state:?}"); + + let state_of_charge = match &battery_state { + BatteryState::Unknown => { + 0 + } + BatteryState::Info(data) => { + data.state_of_charge + } + }; + let mut light_state = LightState { enabled: board.board_hal.get_config().night_lamp.enabled, ..Default::default() @@ -530,7 +526,6 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { .get_config() .night_lamp .low_soc_cutoff - .into() { board.board_hal.get_esp().set_low_voltage_in_cycle(); info!("Set low voltage in cycle"); @@ -540,7 +535,6 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { .get_config() .night_lamp .low_soc_restore - .into() { board.board_hal.get_esp().clear_low_voltage_in_cycle(); info!("Clear low voltage in cycle"); @@ -591,7 +585,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> { 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) { + if state_of_charge < 10 && !matches!(battery_state, BatteryState::Unknown) { let _ = board .board_hal .get_esp() @@ -756,24 +750,19 @@ pub async fn do_secure_pump( async fn update_charge_indicator( board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>, ) { + //FIXME add config and code to allow power supply mode, in this case this is a nop //we have mppt controller, ask it for charging current if let Ok(current) = board.board_hal.get_mptt_current().await { let _ = board .board_hal .set_charge_indicator(current.as_milliamperes() > 20_f64) .await; - } - //fallback to battery controller and ask it instead - else if let Ok(charging) = board - .board_hal - .get_battery_monitor() - .average_current_milli_ampere() - .await - { - let _ = board.board_hal.set_charge_indicator(charging > 20).await; } else { //who knows + board.board_hal.general_fault(true).await; + log(LogMessage::MPPTError, 0, 0, "", "").await; let _ = board.board_hal.set_charge_indicator(false).await; + } } @@ -959,7 +948,7 @@ async fn publish_battery_state( let state = board .board_hal .get_battery_monitor() - .get_battery_state() + .get_state() .await; let value = match state { Ok(state) => { diff --git a/Software/MainBoard/rust/src/webserver/get_json.rs b/Software/MainBoard/rust/src/webserver/get_json.rs index 186449f..e801b35 100644 --- a/Software/MainBoard/rust/src/webserver/get_json.rs +++ b/Software/MainBoard/rust/src/webserver/get_json.rs @@ -131,7 +131,7 @@ pub(crate) async fn get_battery_state( let battery_state = board .board_hal .get_battery_monitor() - .get_battery_state() + .get_state() .await?; Ok(Some(serde_json::to_string(&battery_state)?)) } diff --git a/Software/MainBoard/rust/src_webpack/src/api.ts b/Software/MainBoard/rust/src_webpack/src/api.ts index 7087375..660b912 100644 --- a/Software/MainBoard/rust/src_webpack/src/api.ts +++ b/Software/MainBoard/rust/src_webpack/src/api.ts @@ -167,7 +167,6 @@ export interface BatteryState { temperature: string voltage_milli_volt: string, current_milli_ampere: string, - cycle_count: string, design_milli_ampere: string, remaining_milli_ampere: string, state_of_charge: string, diff --git a/Software/MainBoard/rust/src_webpack/src/batteryview.html b/Software/MainBoard/rust/src_webpack/src/batteryview.html index b605242..c443c51 100644 --- a/Software/MainBoard/rust/src_webpack/src/batteryview.html +++ b/Software/MainBoard/rust/src_webpack/src/batteryview.html @@ -23,10 +23,6 @@ mA: -
- Cycles: - -
design mA: diff --git a/Software/MainBoard/rust/src_webpack/src/batteryview.ts b/Software/MainBoard/rust/src_webpack/src/batteryview.ts index 1dcbaeb..b91faea 100644 --- a/Software/MainBoard/rust/src_webpack/src/batteryview.ts +++ b/Software/MainBoard/rust/src_webpack/src/batteryview.ts @@ -4,7 +4,6 @@ import {BatteryState} from "./api"; export class BatteryView{ voltage_milli_volt: HTMLSpanElement; current_milli_ampere: HTMLSpanElement; - cycle_count: HTMLSpanElement; design_milli_ampere: HTMLSpanElement; remaining_milli_ampere: HTMLSpanElement; state_of_charge: HTMLSpanElement; @@ -18,7 +17,6 @@ export class BatteryView{ (document.getElementById("batteryview") as HTMLElement).innerHTML = require("./batteryview.html") this.voltage_milli_volt = document.getElementById("battery_voltage_milli_volt") as HTMLSpanElement; this.current_milli_ampere = document.getElementById("battery_current_milli_ampere") as HTMLSpanElement; - this.cycle_count = document.getElementById("battery_cycle_count") as HTMLSpanElement; this.design_milli_ampere = document.getElementById("battery_design_milli_ampere") as HTMLSpanElement; this.remaining_milli_ampere = document.getElementById("battery_remaining_milli_ampere") as HTMLSpanElement; this.state_of_charge = document.getElementById("battery_state_of_charge") as HTMLSpanElement; @@ -41,7 +39,6 @@ export class BatteryView{ if (batterystate == null) { this.voltage_milli_volt.innerText = "N/A" this.current_milli_ampere.innerText = "N/A" - this.cycle_count.innerText = "N/A" this.design_milli_ampere.innerText = "N/A" this.remaining_milli_ampere.innerText = "N/A" this.state_of_charge.innerText = "N/A" @@ -50,12 +47,11 @@ export class BatteryView{ } else { this.voltage_milli_volt.innerText = String(+batterystate.voltage_milli_volt/1000) this.current_milli_ampere.innerText = batterystate.current_milli_ampere - this.cycle_count.innerText = batterystate.cycle_count this.design_milli_ampere.innerText = batterystate.design_milli_ampere this.remaining_milli_ampere.innerText = batterystate.remaining_milli_ampere this.state_of_charge.innerText = batterystate.state_of_charge this.state_of_health.innerText = batterystate.state_of_health - this.temperature.innerText = String(+batterystate.temperature / 100) + this.temperature.innerText = String(+batterystate.temperature) }