Skip to content

Commit

Permalink
Change logic of state of health calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartpittaway committed Mar 8, 2024
1 parent a3b4131 commit 40ba550
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 36 deletions.
6 changes: 3 additions & 3 deletions ESPController/include/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
29 changes: 15 additions & 14 deletions ESPController/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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());
}
}
}
}
25 changes: 12 additions & 13 deletions ESPController/src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<String>().c_str(), sizeof(settings->homeassist_apikey));

Expand Down
2 changes: 1 addition & 1 deletion ESPController/src/webserver_json_post.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down
2 changes: 1 addition & 1 deletion ESPController/src/webserver_json_requests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions ESPController/web_src/default.htm
Original file line number Diff line number Diff line change
Expand Up @@ -1035,13 +1035,15 @@ <h1 id="v0">Charge/Discharge configuration</h1>
<label for="nominalbatcap">Nominal Battery Capacity (Amp-hours)</label>
<input id="nominalbatcap" name="nominalbatcap" value="" type="number" min="1" max="9999" step="1" />
</div>
<p>State of Health</p>

<div>
<label for="expected_cycles">Expected battery lifetime/cycles (at DOD)</label>
<label for="expected_cycles">Expected battery lifetime/cycles</label>
<input id="expected_cycles" name="expected_cycles" value="" type="number" min="100" max="99999" step="1" />
</div>
<div>
<label for="dischargedepth">Discharge depth %% (DOD)</label>
<input id="dischargedepth" name="dischargedepth" value="" type="number" min="10" max="100" step="1" />
<label for="eol_capacity">End of life capacity (%%)</label>
<input id="eol_capacity" name="eol_capacity" value="" type="number" min="10" max="100" step="1" />
</div>
<div>
<label for="total_ah_charge">Lifetime amp-hours charge (in)</label>
Expand Down
2 changes: 1 addition & 1 deletion ESPController/web_src/pagecode.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 40ba550

Please sign in to comment.