mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 10:49:42 +02:00
Add scaled remaining capacity calculation
This commit is contained in:
parent
7ea97cea6f
commit
ced16495a0
10 changed files with 49 additions and 17 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue