diff --git a/ESPController/include/defines.h b/ESPController/include/defines.h index 235e54c..2488da3 100644 --- a/ESPController/include/defines.h +++ b/ESPController/include/defines.h @@ -264,10 +264,10 @@ struct diybms_eeprom_settings uint32_t soh_total_milliamphour_in; /// @brief State of health variables - total expected lifetime cycles of battery (6000) uint16_t soh_lifetime_battery_cycles; + /// @brief State of health variables - expected remaining capacity (%) at end of life/max cycles + uint8_t soh_eol_capacity; /// @brief State of health variables - estimated number of cycles - uint16_t soh_estimated_battery_cycles; - /// @brief State of health variables - discharge depth (80%) - uint8_t soh_discharge_depth; + uint16_t soh_estimated_battery_cycles; /// @brief Calculated percentage calculation of health float soh_percent; }; diff --git a/ESPController/src/main.cpp b/ESPController/src/main.cpp index b9d0423..e8e027a 100644 --- a/ESPController/src/main.cpp +++ b/ESPController/src/main.cpp @@ -3220,17 +3220,16 @@ void send_ext_canbus_message(const uint32_t identifier, const uint8_t *buffer, c void CalculateStateOfHealth(diybms_eeprom_settings *settings) { - // Value indicating what a typical discharge cycle looks like in amp-hours (normally 80% of cell for LFP) - float depth = 1000.0F * ((float)settings->nominalbatcap / 100.0F * (float)settings->soh_discharge_depth); - float in = (float)settings->soh_total_milliamphour_in / depth; - float out = (float)settings->soh_total_milliamphour_out / depth; - // Take worst case + float batcap_mah = 1000.0F * settings->nominalbatcap; + float in = (float)settings->soh_total_milliamphour_in / batcap_mah; + float out = (float)settings->soh_total_milliamphour_out / batcap_mah; + // Take worst case number of cycles float cycles = max(in, out); - settings->soh_percent = 100 - ((cycles / (float)settings->soh_lifetime_battery_cycles) * 100.0F); - settings->soh_estimated_battery_cycles = (uint16_t)round(cycles); + settings->soh_percent = 100.0F - ((100.0F - settings->soh_eol_capacity) * (cycles / (float)settings->soh_lifetime_battery_cycles)); + ESP_LOGI(TAG, "State of health calc %f %, estimated cycles=%f", settings->soh_percent, cycles); } @@ -3921,15 +3920,13 @@ ESP32 Chip model = %u, Rev %u, Cores=%u, Features=%u)", uint32_t in; uint32_t out; - if (GetStateOfCharge(&in,&out)) + if (GetStateOfCharge(&in, &out)) { - currentmon_internal.SetSOCByMilliAmpCounter(in,out); + currentmon_internal.SetSOCByMilliAmpCounter(in, out); } currentmon_internal.TakeReadings(); - - CalculateStateOfHealth(&mysettings); } else @@ -4242,11 +4239,15 @@ void loop() // Report again in 60 seconds heaptimer = currentMillis + 60000; - //Once per minute, store the state of charge into flash, just in case the controller is rebooted and we can restore this value - //on power up. + // Once per minute, store the state of charge into flash, just in case the controller is rebooted and we can restore this value + // on power up. if (mysettings.currentMonitoringEnabled && mysettings.currentMonitoringDevice == CurrentMonitorDevice::DIYBMS_CURRENT_MON_INTERNAL) { - SaveStateOfCharge(currentmon_internal.raw_milliamphour_in(),currentmon_internal.raw_milliamphour_out()); + // Avoid writing zero SoC into flash + if (currentmon_internal.calc_state_of_charge() > 1.0F) + { + SaveStateOfCharge(currentmon_internal.raw_milliamphour_in(), currentmon_internal.raw_milliamphour_out()); + } } } } diff --git a/ESPController/src/settings.cpp b/ESPController/src/settings.cpp index 4cc9d46..73434d5 100644 --- a/ESPController/src/settings.cpp +++ b/ESPController/src/settings.cpp @@ -95,7 +95,10 @@ static const char soh_total_milliamphour_out_JSONKEY[] = "soh_mah_out"; static const char soh_total_milliamphour_in_JSONKEY[] = "soh_mah_in"; static const char soh_lifetime_battery_cycles_JSONKEY[] = "soh_batcycle"; -static const char soh_discharge_depth_JSONKEY[] = "soh_disdepth"; + +static const char soh_eol_capacity_JSONKEY[] = "soh_eol_capacity"; + + /* NVS KEYS THESE STRINGS ARE USED TO HOLD THE PARAMETER IN NVS FLASH, MAXIMUM LENGTH OF 16 CHARACTERS @@ -192,7 +195,7 @@ static const char homeassist_apikey_NVSKEY[] = "haapikey"; static const char soh_total_milliamphour_out_NVSKEY[] = "soh_mah_out"; static const char soh_total_milliamphour_in_NVSKEY[] = "soh_mah_in"; static const char soh_lifetime_battery_cycles_NVSKEY[] = "soh_batcycle"; -static const char soh_discharge_depth_NVSKEY[] = "soh_disdepth"; +static const char soh_eol_capacity_NVSKEY[] = "soh_eol_cap"; static const char soc_milliamphour_out_NVSKEY[] = "soc_mah_out"; static const char soc_milliamphour_in_NVSKEY[] = "soc_mah_in"; @@ -523,7 +526,7 @@ void SaveConfiguration(const diybms_eeprom_settings *settings) MACRO_NVSWRITE(soh_total_milliamphour_out) MACRO_NVSWRITE(soh_total_milliamphour_in) MACRO_NVSWRITE(soh_lifetime_battery_cycles) - MACRO_NVSWRITE_UINT8(soh_discharge_depth) + MACRO_NVSWRITE_UINT8(soh_eol_capacity) ESP_ERROR_CHECK(nvs_commit(nvs_handle)); nvs_close(nvs_handle); @@ -659,8 +662,7 @@ void LoadConfiguration(diybms_eeprom_settings *settings) MACRO_NVSREAD(soh_total_milliamphour_out) MACRO_NVSREAD(soh_total_milliamphour_in) MACRO_NVSREAD(soh_lifetime_battery_cycles) - MACRO_NVSREAD_UINT8(soh_discharge_depth) - + MACRO_NVSREAD_UINT8(soh_eol_capacity) nvs_close(nvs_handle); } @@ -848,7 +850,7 @@ void DefaultConfiguration(diybms_eeprom_settings *_myset) _myset->soh_total_milliamphour_out = 0; _myset->soh_total_milliamphour_in = 0; _myset->soh_lifetime_battery_cycles = 6000; - _myset->soh_discharge_depth = 80; + _myset->soh_eol_capacity = 80; _myset->soh_percent = 100.0F; } @@ -1064,11 +1066,6 @@ void ValidateConfiguration(diybms_eeprom_settings *settings) { settings->stateofchargeresumevalue = settings->stateofchargeresumevalue; } - - if (settings->soh_discharge_depth == 0 || settings->soh_discharge_depth > 100) - { - settings->soh_discharge_depth = 80; - } } // Builds up a JSON document which mirrors the parameters inside "diybms_eeprom_settings" @@ -1222,7 +1219,8 @@ void GenerateSettingsJSONDocument(JsonDocument &doc, diybms_eeprom_settings *set root[soh_total_milliamphour_out_JSONKEY] = settings->soh_total_milliamphour_out; root[soh_total_milliamphour_in_JSONKEY] = settings->soh_total_milliamphour_in; root[soh_lifetime_battery_cycles_JSONKEY] = settings->soh_lifetime_battery_cycles; - root[soh_discharge_depth_JSONKEY] = settings->soh_discharge_depth; + root[soh_eol_capacity_JSONKEY] = settings->soh_eol_capacity; + } void JSONToSettings(JsonDocument &doc, diybms_eeprom_settings *settings) @@ -1319,7 +1317,8 @@ void JSONToSettings(JsonDocument &doc, diybms_eeprom_settings *settings) settings->soh_total_milliamphour_out = root[soh_total_milliamphour_out_JSONKEY]; settings->soh_total_milliamphour_in = root[soh_total_milliamphour_in_JSONKEY]; settings->soh_lifetime_battery_cycles = root[soh_lifetime_battery_cycles_JSONKEY]; - settings->soh_discharge_depth = root[soh_discharge_depth_JSONKEY]; + settings->soh_eol_capacity=root[soh_eol_capacity_JSONKEY]; + strncpy(settings->homeassist_apikey, root[homeassist_apikey_JSONKEY].as().c_str(), sizeof(settings->homeassist_apikey)); diff --git a/ESPController/src/webserver_json_post.cpp b/ESPController/src/webserver_json_post.cpp index f397827..9881970 100644 --- a/ESPController/src/webserver_json_post.cpp +++ b/ESPController/src/webserver_json_post.cpp @@ -579,7 +579,7 @@ esp_err_t post_savechargeconfig_json_handler(httpd_req_t *req, bool urlEncoded) } GetKeyValue(httpbuf, "expected_cycles", &mysettings.soh_lifetime_battery_cycles, urlEncoded); - GetKeyValue(httpbuf, "dischargedepth", &mysettings.soh_discharge_depth, urlEncoded); + GetKeyValue(httpbuf, "eol_capacity", &mysettings.soh_eol_capacity, urlEncoded); if (GetKeyValue(httpbuf, "total_ah_discharge", &mysettings.soh_total_milliamphour_out, urlEncoded)) { diff --git a/ESPController/src/webserver_json_requests.cpp b/ESPController/src/webserver_json_requests.cpp index 2178a38..ce82aae 100644 --- a/ESPController/src/webserver_json_requests.cpp +++ b/ESPController/src/webserver_json_requests.cpp @@ -605,8 +605,8 @@ esp_err_t content_handler_chargeconfig(httpd_req_t *req) settings["equip_addr"] = mysettings.canbus_equipment_addr; settings["nominalbatcap"] = mysettings.nominalbatcap; - settings["dischargedepth"] = mysettings.soh_discharge_depth; settings["expectedlifetime_cycles"] = mysettings.soh_lifetime_battery_cycles; + settings["eol_capacity"] = mysettings.soh_eol_capacity; settings["total_mah_charge"] = mysettings.soh_total_milliamphour_in; settings["total_mah_discharge"] = mysettings.soh_total_milliamphour_out; settings["estimatebatterycycle"] = mysettings.soh_estimated_battery_cycles; diff --git a/ESPController/web_src/default.htm b/ESPController/web_src/default.htm index e96fec7..fd11ada 100644 --- a/ESPController/web_src/default.htm +++ b/ESPController/web_src/default.htm @@ -1035,13 +1035,15 @@

Charge/Discharge configuration

+

State of Health

+
- +
- - + +
diff --git a/ESPController/web_src/pagecode.js b/ESPController/web_src/pagecode.js index 894d8ef..2eda424 100644 --- a/ESPController/web_src/pagecode.js +++ b/ESPController/web_src/pagecode.js @@ -2004,7 +2004,7 @@ $(function () { $("#nominalbatcap").val(data.chargeconfig.nominalbatcap); $("#expected_cycles").val(data.chargeconfig.expectedlifetime_cycles); - $("#dischargedepth").val(data.chargeconfig.dischargedepth); + $("#eol_capacity").val(data.chargeconfig.eol_capacity); $("#total_ah_charge").val(Math.trunc(data.chargeconfig.total_mah_charge / 1000)); $("#total_ah_discharge").val(Math.trunc(data.chargeconfig.total_mah_discharge / 1000)); $("#estimate_bat_cycle").val(data.chargeconfig.estimatebatterycycle);