Add scaled remaining capacity calculation

This commit is contained in:
amarofarinha 2024-10-23 01:28:00 +01:00
parent 7ea97cea6f
commit ced16495a0
10 changed files with 49 additions and 17 deletions

View file

@ -291,7 +291,7 @@ void core_loop(void* task_time_us) {
#ifdef DOUBLE_BATTERY
update_values_battery2();
#endif
update_SOC(); // Check if real or calculated SOC% value should be sent
update_scaled_values(); // Check if real or calculated SOC% value should be sent
#ifndef SERIAL_LINK_RECEIVER
update_machineryprotection(); // Check safeties (Not on serial link reciever board)
#endif
@ -834,7 +834,7 @@ void handle_contactors() {
#endif // CONTACTOR_CONTROL
}
void update_SOC() {
void update_scaled_values() {
if (datalayer.battery.settings.soc_scaling_active) {
/** SOC Scaling
*
@ -864,23 +864,40 @@ void update_SOC() {
calc_soc = 10000 * (calc_soc - datalayer.battery.settings.min_percentage);
calc_soc = calc_soc / (datalayer.battery.settings.max_percentage - datalayer.battery.settings.min_percentage);
datalayer.battery.status.reported_soc = calc_soc;
// Calculate the scaled remaining capacity in Wh
if (datalayer.battery.info.total_capacity_Wh > 0) {
uint32_t calc_capacity;
// remove % capacity not used in min_percentage to total_capacity_Wh
calc_capacity = datalayer.battery.settings.min_percentage * datalayer.battery.info.total_capacity_Wh / 10000;
calc_capacity = datalayer.battery.status.remaining_capacity_Wh - calc_capacity;
datalayer.battery.status.reported_remaining_capacity_Wh = calc_capacity;
} else {
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
}
} else { // No SOC window wanted. Set scaled to same as real.
datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc;
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
}
#ifdef DOUBLE_BATTERY
// Perform extra SOC sanity checks on double battery setups
if (datalayer.battery.status.real_soc < 100) { //If this battery is under 1.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc;
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
}
if (datalayer.battery2.status.real_soc < 100) { //If this battery is under 1.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery2.status.real_soc;
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery2.status.remaining_capacity_Wh;
}
if (datalayer.battery.status.real_soc > 9900) { //If this battery is over 99.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery.status.real_soc;
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
}
if (datalayer.battery2.status.real_soc > 9900) { //If this battery is over 99.00%, use this as SOC instead of average
datalayer.battery.status.reported_soc = datalayer.battery2.status.real_soc;
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery2.status.remaining_capacity_Wh;
}
#endif //DOUBLE_BATTERY
}

View file

@ -43,6 +43,12 @@ typedef struct {
/** uint32_t */
/** Remaining energy capacity in Watt-hours */
uint32_t remaining_capacity_Wh;
/** The remaining capacity reported to the inverter based on min percentage setting, in Watt-hours
* This value will either be scaled or not scaled depending on the value of
* battery.settings.soc_scaling_active
*/
uint32_t reported_remaining_capacity_Wh;
/** Maximum allowed battery discharge power in Watts */
uint32_t max_discharge_power_W = 0;
/** Maximum allowed battery charge power in Watts */

View file

@ -55,8 +55,10 @@ SensorConfig sensorConfigs[] = {
{"cell_min_voltage", "Battery Emulator Cell Min Voltage", "{{ value_json.cell_min_voltage }}", "V", "voltage"},
{"battery_voltage", "Battery Emulator Battery Voltage", "{{ value_json.battery_voltage }}", "V", "voltage"},
{"total_capacity", "Battery Emulator Battery Total Capacity", "{{ value_json.total_capacity }}", "Wh", "energy"},
{"remaining_capacity", "Battery Emulator Battery Remaining Capacity", "{{ value_json.remaining_capacity }}", "Wh",
{"remaining_capacity", "Battery Emulator Battery Remaining Capacity (scaled)", "{{ value_json.remaining_capacity }}", "Wh",
"energy"},
{"remaining_capacity_real", "Battery Emulator Battery Remaining Capacity (real)",
"{{ value_json.remaining_capacity_real }}", "Wh", "energy"},
{"max_discharge_power", "Battery Emulator Battery Max Discharge Power", "{{ value_json.max_discharge_power }}", "W",
"power"},
{"max_charge_power", "Battery Emulator Battery Max Charge Power", "{{ value_json.max_charge_power }}", "W",
@ -141,7 +143,8 @@ static void publish_common_info(void) {
doc["cell_min_voltage"] = ((float)datalayer.battery.status.cell_min_voltage_mV) / 1000.0;
}
doc["total_capacity"] = ((float)datalayer.battery.info.total_capacity_Wh);
doc["remaining_capacity"] = ((float)datalayer.battery.status.remaining_capacity_Wh);
doc["remaining_capacity_real"] = ((float)datalayer.battery.status.remaining_capacity_Wh);
doc["remaining_capacity"] = ((float)datalayer.battery.status.reported_remaining_capacity_Wh);
doc["max_discharge_power"] = ((float)datalayer.battery.status.max_discharge_power_W);
doc["max_charge_power"] = ((float)datalayer.battery.status.max_charge_power_W);
}

View file

@ -653,7 +653,9 @@ String processor(const String& var) {
content += "<h4 style='color: white;'>Current: " + String(currentFloat, 1) + " A</h4>";
content += formatPowerValue("Power", powerFloat, "", 1);
content += formatPowerValue("Total capacity", datalayer.battery.info.total_capacity_Wh, "h", 0);
content += formatPowerValue("Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1);
content += formatPowerValue("Real Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1);
content +=
formatPowerValue("Scaled Remaining capacity", datalayer.battery.status.reported_remaining_capacity_Wh, "h", 1);
if (emulator_pause_status == NORMAL) {
content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1);

View file

@ -84,7 +84,8 @@ void handle_update_data_modbusp301_byd() {
mbPV[302] = 128 + bms_char_dis_status;
mbPV[303] = datalayer.battery.status.reported_soc;
mbPV[304] = std::min(datalayer.battery.info.total_capacity_Wh, static_cast<uint32_t>(60000u)); //Cap to 60kWh
mbPV[305] = std::min(datalayer.battery.status.remaining_capacity_Wh, static_cast<uint32_t>(60000u)); //Cap to 60kWh
mbPV[305] =
std::min(datalayer.battery.status.reported_remaining_capacity_Wh, static_cast<uint32_t>(60000u)); //Cap to 60kWh
mbPV[306] = std::min(max_discharge_W, static_cast<uint32_t>(30000u)); //Cap to 30000 if exceeding
mbPV[307] = std::min(max_charge_W, static_cast<uint32_t>(30000u)); //Cap to 30000 if exceeding
mbPV[310] = datalayer.battery.status.voltage_dV;

View file

@ -108,7 +108,8 @@ void update_values_can_inverter() { //This function maps all the values fetched
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0
ampere_hours_remaining = ((datalayer.battery.status.remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
ampere_hours_remaining =
((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
}

View file

@ -436,8 +436,8 @@ void update_values_can_inverter() { //This function maps all the CAN values fet
FOXESS_1873.data.u8[3] = (datalayer.battery.status.current_dA >> 8);
FOXESS_1873.data.u8[4] = (uint8_t)(datalayer.battery.status.reported_soc / 100); //SOC (0-100%)
FOXESS_1873.data.u8[5] = 0x00;
FOXESS_1873.data.u8[6] = (uint8_t)(datalayer.battery.status.remaining_capacity_Wh / 10);
FOXESS_1873.data.u8[7] = ((datalayer.battery.status.remaining_capacity_Wh / 10) >> 8);
FOXESS_1873.data.u8[6] = (uint8_t)(datalayer.battery.status.reported_remaining_capacity_Wh / 10);
FOXESS_1873.data.u8[7] = ((datalayer.battery.status.reported_remaining_capacity_Wh / 10) >> 8);
//BMS_CellData
FOXESS_1874.data.u8[0] = (int8_t)datalayer.battery.status.temperature_max_dC;

View file

@ -105,7 +105,8 @@ void update_values_can_inverter() { //This function maps all the values fetched
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0
ampere_hours_remaining = ((datalayer.battery.status.remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
ampere_hours_remaining =
((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
}

View file

@ -149,7 +149,8 @@ void update_values_can_inverter() { //This function maps all the values fetched
temperature_average =
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
ampere_hours_remaining = ((datalayer.battery.status.remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
ampere_hours_remaining =
((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
ampere_hours_max = ((datalayer.battery.info.total_capacity_Wh / datalayer.battery.status.voltage_dV) *
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)

View file

@ -144,10 +144,10 @@ void update_values_can_inverter() { //This function maps all the values fetched
capped_capacity_Wh = datalayer.battery.info.total_capacity_Wh;
}
// Batteries might be larger than uint16_t value can take
if (datalayer.battery.status.remaining_capacity_Wh > 65000) {
if (datalayer.battery.status.reported_remaining_capacity_Wh > 65000) {
capped_remaining_capacity_Wh = 65000;
} else {
capped_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
capped_remaining_capacity_Wh = datalayer.battery.status.reported_remaining_capacity_Wh;
}
//Put the values into the CAN messages