mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Add reported_total_capacity_Wh and use it for SOLAX. Cleanup scaled values on webpage (#1002)
* Add reported_total_capacity_Wh and soh to SOLAX messages. * Improve display of scaled values on webpage. * Additionally also improve display of temperatures, cell voltages and combine voltage and current on one line. * Refactor formatPowerValue function.
This commit is contained in:
parent
63222b4c77
commit
97c942e313
5 changed files with 79 additions and 35 deletions
|
@ -462,6 +462,10 @@ void update_calculated_values() {
|
||||||
} else {
|
} else {
|
||||||
datalayer.battery.status.reported_remaining_capacity_Wh = 0;
|
datalayer.battery.status.reported_remaining_capacity_Wh = 0;
|
||||||
}
|
}
|
||||||
|
datalayer.battery.info.reported_total_capacity_Wh =
|
||||||
|
(datalayer.battery.info.total_capacity_Wh *
|
||||||
|
(datalayer.battery.settings.max_percentage - datalayer.battery.settings.min_percentage)) /
|
||||||
|
10000;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
|
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
|
||||||
|
|
|
@ -7,6 +7,7 @@ typedef struct {
|
||||||
/** uint32_t */
|
/** uint32_t */
|
||||||
/** Total energy capacity in Watt-hours */
|
/** Total energy capacity in Watt-hours */
|
||||||
uint32_t total_capacity_Wh = BATTERY_WH_MAX;
|
uint32_t total_capacity_Wh = BATTERY_WH_MAX;
|
||||||
|
uint32_t reported_total_capacity_Wh = BATTERY_WH_MAX;
|
||||||
|
|
||||||
/** uint16_t */
|
/** uint16_t */
|
||||||
/** The maximum intended packvoltage, in deciVolt. 4900 = 490.0 V */
|
/** The maximum intended packvoltage, in deciVolt. 4900 = 490.0 V */
|
||||||
|
|
|
@ -1054,16 +1054,30 @@ String processor(const String& var) {
|
||||||
uint16_t cell_delta_mv =
|
uint16_t cell_delta_mv =
|
||||||
datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV;
|
datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV;
|
||||||
|
|
||||||
content += "<h4 style='color: white;'>Real SOC: " + String(socRealFloat, 2) + "%</h4>";
|
if (datalayer.battery.settings.soc_scaling_active)
|
||||||
content += "<h4 style='color: white;'>Scaled SOC: " + String(socScaledFloat, 2) + "%</h4>";
|
content += "<h4 style='color: white;'>Scaled SOC: " + String(socScaledFloat, 2) +
|
||||||
|
"% (real: " + String(socRealFloat, 2) + "%)</h4>";
|
||||||
|
else
|
||||||
|
content += "<h4 style='color: white;'>SOC: " + String(socRealFloat, 2) + "%</h4>";
|
||||||
|
|
||||||
content += "<h4 style='color: white;'>SOH: " + String(sohFloat, 2) + "%</h4>";
|
content += "<h4 style='color: white;'>SOH: " + String(sohFloat, 2) + "%</h4>";
|
||||||
content += "<h4 style='color: white;'>Voltage: " + String(voltageFloat, 1) + " V</h4>";
|
content += "<h4 style='color: white;'>Voltage: " + String(voltageFloat, 1) +
|
||||||
content += "<h4 style='color: white;'>Current: " + String(currentFloat, 1) + " A</h4>";
|
" V Current: " + String(currentFloat, 1) + " A</h4>";
|
||||||
content += formatPowerValue("Power", powerFloat, "", 1);
|
content += formatPowerValue("Power", powerFloat, "", 1);
|
||||||
|
|
||||||
|
if (datalayer.battery.settings.soc_scaling_active)
|
||||||
|
content += "<h4 style='color: white;'>Scaled total capacity: " +
|
||||||
|
formatPowerValue(datalayer.battery.info.reported_total_capacity_Wh, "h", 1) +
|
||||||
|
" (real: " + formatPowerValue(datalayer.battery.info.total_capacity_Wh, "h", 1) + ")</h4>";
|
||||||
|
else
|
||||||
content += formatPowerValue("Total capacity", datalayer.battery.info.total_capacity_Wh, "h", 1);
|
content += formatPowerValue("Total capacity", datalayer.battery.info.total_capacity_Wh, "h", 1);
|
||||||
content += formatPowerValue("Real Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1);
|
|
||||||
content +=
|
if (datalayer.battery.settings.soc_scaling_active)
|
||||||
formatPowerValue("Scaled Remaining capacity", datalayer.battery.status.reported_remaining_capacity_Wh, "h", 1);
|
content += "<h4 style='color: white;'>Scaled remaining capacity: " +
|
||||||
|
formatPowerValue(datalayer.battery.status.reported_remaining_capacity_Wh, "h", 1) +
|
||||||
|
" (real: " + formatPowerValue(datalayer.battery.status.remaining_capacity_Wh, "h", 1) + ")</h4>";
|
||||||
|
else
|
||||||
|
content += formatPowerValue("Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1);
|
||||||
|
|
||||||
if (datalayer.system.settings.equipment_stop_active) {
|
if (datalayer.system.settings.equipment_stop_active) {
|
||||||
content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1, "red");
|
content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1, "red");
|
||||||
|
@ -1087,15 +1101,15 @@ String processor(const String& var) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content += "<h4>Cell max: " + String(datalayer.battery.status.cell_max_voltage_mV) + " mV</h4>";
|
content += "<h4>Cell min/max: " + String(datalayer.battery.status.cell_min_voltage_mV) + " mV / " +
|
||||||
content += "<h4>Cell min: " + String(datalayer.battery.status.cell_min_voltage_mV) + " mV</h4>";
|
String(datalayer.battery.status.cell_max_voltage_mV) + " mV</h4>";
|
||||||
if (cell_delta_mv > datalayer.battery.info.max_cell_voltage_deviation_mV) {
|
if (cell_delta_mv > datalayer.battery.info.max_cell_voltage_deviation_mV) {
|
||||||
content += "<h4 style='color: red;'>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
content += "<h4 style='color: red;'>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
||||||
} else {
|
} else {
|
||||||
content += "<h4>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
content += "<h4>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
||||||
}
|
}
|
||||||
content += "<h4>Temperature max: " + String(tempMaxFloat, 1) + " °C</h4>";
|
content +=
|
||||||
content += "<h4>Temperature min: " + String(tempMinFloat, 1) + " °C</h4>";
|
"<h4>Temperature min/max: " + String(tempMinFloat, 1) + " °C / " + String(tempMaxFloat, 1) + " °C</h4>";
|
||||||
|
|
||||||
content += "<h4>System status: ";
|
content += "<h4>System status: ";
|
||||||
switch (datalayer.battery.status.bms_status) {
|
switch (datalayer.battery.status.bms_status) {
|
||||||
|
@ -1261,16 +1275,30 @@ String processor(const String& var) {
|
||||||
tempMinFloat = static_cast<float>(datalayer.battery2.status.temperature_min_dC) / 10.0; // Convert to float
|
tempMinFloat = static_cast<float>(datalayer.battery2.status.temperature_min_dC) / 10.0; // Convert to float
|
||||||
cell_delta_mv = datalayer.battery2.status.cell_max_voltage_mV - datalayer.battery2.status.cell_min_voltage_mV;
|
cell_delta_mv = datalayer.battery2.status.cell_max_voltage_mV - datalayer.battery2.status.cell_min_voltage_mV;
|
||||||
|
|
||||||
content += "<h4 style='color: white;'>Real SOC: " + String(socRealFloat, 2) + "%</h4>";
|
if (datalayer.battery.settings.soc_scaling_active)
|
||||||
content += "<h4 style='color: white;'>Scaled SOC: " + String(socScaledFloat, 2) + "%</h4>";
|
content += "<h4 style='color: white;'>Scaled SOC: " + String(socScaledFloat, 2) +
|
||||||
|
"% (real: " + String(socRealFloat, 2) + "%)</h4>";
|
||||||
|
else
|
||||||
|
content += "<h4 style='color: white;'>SOC: " + String(socRealFloat, 2) + "%</h4>";
|
||||||
|
|
||||||
content += "<h4 style='color: white;'>SOH: " + String(sohFloat, 2) + "%</h4>";
|
content += "<h4 style='color: white;'>SOH: " + String(sohFloat, 2) + "%</h4>";
|
||||||
content += "<h4 style='color: white;'>Voltage: " + String(voltageFloat, 1) + " V</h4>";
|
content += "<h4 style='color: white;'>Voltage: " + String(voltageFloat, 1) +
|
||||||
content += "<h4 style='color: white;'>Current: " + String(currentFloat, 1) + " A</h4>";
|
" V Current: " + String(currentFloat, 1) + " A</h4>";
|
||||||
content += formatPowerValue("Power", powerFloat, "", 1);
|
content += formatPowerValue("Power", powerFloat, "", 1);
|
||||||
|
|
||||||
|
if (datalayer.battery.settings.soc_scaling_active)
|
||||||
|
content += "<h4 style='color: white;'>Scaled total capacity: " +
|
||||||
|
formatPowerValue(datalayer.battery2.info.reported_total_capacity_Wh, "h", 1) +
|
||||||
|
" (real: " + formatPowerValue(datalayer.battery2.info.total_capacity_Wh, "h", 1) + ")</h4>";
|
||||||
|
else
|
||||||
content += formatPowerValue("Total capacity", datalayer.battery2.info.total_capacity_Wh, "h", 1);
|
content += formatPowerValue("Total capacity", datalayer.battery2.info.total_capacity_Wh, "h", 1);
|
||||||
content += formatPowerValue("Real Remaining capacity", datalayer.battery2.status.remaining_capacity_Wh, "h", 1);
|
|
||||||
content +=
|
if (datalayer.battery.settings.soc_scaling_active)
|
||||||
formatPowerValue("Scaled Remaining capacity", datalayer.battery2.status.reported_remaining_capacity_Wh, "h", 1);
|
content += "<h4 style='color: white;'>Scaled remaining capacity: " +
|
||||||
|
formatPowerValue(datalayer.battery2.status.reported_remaining_capacity_Wh, "h", 1) +
|
||||||
|
" (real: " + formatPowerValue(datalayer.battery2.status.remaining_capacity_Wh, "h", 1) + ")</h4>";
|
||||||
|
else
|
||||||
|
content += formatPowerValue("Remaining capacity", datalayer.battery2.status.remaining_capacity_Wh, "h", 1);
|
||||||
|
|
||||||
if (datalayer.system.settings.equipment_stop_active) {
|
if (datalayer.system.settings.equipment_stop_active) {
|
||||||
content += formatPowerValue("Max discharge power", datalayer.battery2.status.max_discharge_power_W, "", 1, "red");
|
content += formatPowerValue("Max discharge power", datalayer.battery2.status.max_discharge_power_W, "", 1, "red");
|
||||||
|
@ -1284,15 +1312,15 @@ String processor(const String& var) {
|
||||||
content += "<h4 style='color: white;'>Max charge current: " + String(maxCurrentChargeFloat, 1) + " A</h4>";
|
content += "<h4 style='color: white;'>Max charge current: " + String(maxCurrentChargeFloat, 1) + " A</h4>";
|
||||||
}
|
}
|
||||||
|
|
||||||
content += "<h4>Cell max: " + String(datalayer.battery2.status.cell_max_voltage_mV) + " mV</h4>";
|
content += "<h4>Cell min/max: " + String(datalayer.battery2.status.cell_min_voltage_mV) + " mV / " +
|
||||||
content += "<h4>Cell min: " + String(datalayer.battery2.status.cell_min_voltage_mV) + " mV</h4>";
|
String(datalayer.battery2.status.cell_max_voltage_mV) + " mV</h4>";
|
||||||
if (cell_delta_mv > datalayer.battery2.info.max_cell_voltage_deviation_mV) {
|
if (cell_delta_mv > datalayer.battery2.info.max_cell_voltage_deviation_mV) {
|
||||||
content += "<h4 style='color: red;'>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
content += "<h4 style='color: red;'>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
||||||
} else {
|
} else {
|
||||||
content += "<h4>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
content += "<h4>Cell delta: " + String(cell_delta_mv) + " mV</h4>";
|
||||||
}
|
}
|
||||||
content += "<h4>Temperature max: " + String(tempMaxFloat, 1) + " °C</h4>";
|
content +=
|
||||||
content += "<h4>Temperature min: " + String(tempMinFloat, 1) + " °C</h4>";
|
"<h4>Temperature min/max: " + String(tempMinFloat, 1) + " °C / " + String(tempMaxFloat, 1) + " °C</h4>";
|
||||||
if (datalayer.battery.status.bms_status == ACTIVE) {
|
if (datalayer.battery.status.bms_status == ACTIVE) {
|
||||||
content += "<h4>System status: OK </h4>";
|
content += "<h4>System status: OK </h4>";
|
||||||
} else if (datalayer.battery.status.bms_status == UPDATING) {
|
} else if (datalayer.battery.status.bms_status == UPDATING) {
|
||||||
|
@ -1564,6 +1592,13 @@ void onOTAEnd(bool success) {
|
||||||
template <typename T> // This function makes power values appear as W when under 1000, and kW when over
|
template <typename T> // This function makes power values appear as W when under 1000, and kW when over
|
||||||
String formatPowerValue(String label, T value, String unit, int precision, String color) {
|
String formatPowerValue(String label, T value, String unit, int precision, String color) {
|
||||||
String result = "<h4 style='color: " + color + ";'>" + label + ": ";
|
String result = "<h4 style='color: " + color + ";'>" + label + ": ";
|
||||||
|
result += formatPowerValue(value, unit, precision);
|
||||||
|
result += "</h4>";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
template <typename T> // This function makes power values appear as W when under 1000, and kW when over
|
||||||
|
String formatPowerValue(T value, String unit, int precision) {
|
||||||
|
String result = "";
|
||||||
|
|
||||||
if (std::is_same<T, float>::value || std::is_same<T, uint16_t>::value || std::is_same<T, uint32_t>::value) {
|
if (std::is_same<T, float>::value || std::is_same<T, uint16_t>::value || std::is_same<T, uint32_t>::value) {
|
||||||
float convertedValue = static_cast<float>(value);
|
float convertedValue = static_cast<float>(value);
|
||||||
|
@ -1575,6 +1610,6 @@ String formatPowerValue(String label, T value, String unit, int precision, Strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result += unit + "</h4>";
|
result += unit;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,9 @@ void onOTAEnd(bool success);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
String formatPowerValue(String label, T value, String unit, int precision, String color = "white");
|
String formatPowerValue(String label, T value, String unit, int precision, String color = "white");
|
||||||
|
|
||||||
|
template <typename T> // This function makes power values appear as W when under 1000, and kW when over
|
||||||
|
String formatPowerValue(T value, String unit, int precision);
|
||||||
|
|
||||||
extern void store_settings();
|
extern void store_settings();
|
||||||
|
|
||||||
void ota_monitor();
|
void ota_monitor();
|
||||||
|
|
|
@ -117,10 +117,10 @@ 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);
|
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
|
||||||
|
|
||||||
// Batteries might be larger than uint16_t value can take
|
// Batteries might be larger than uint16_t value can take
|
||||||
if (datalayer.battery.info.total_capacity_Wh > 65000) {
|
if (datalayer.battery.info.reported_total_capacity_Wh > 65000) {
|
||||||
capped_capacity_Wh = 65000;
|
capped_capacity_Wh = 65000;
|
||||||
} else {
|
} else {
|
||||||
capped_capacity_Wh = datalayer.battery.info.total_capacity_Wh;
|
capped_capacity_Wh = datalayer.battery.info.reported_total_capacity_Wh;
|
||||||
}
|
}
|
||||||
// Batteries might be larger than uint16_t value can take
|
// Batteries might be larger than uint16_t value can take
|
||||||
if (datalayer.battery.status.reported_remaining_capacity_Wh > 65000) {
|
if (datalayer.battery.status.reported_remaining_capacity_Wh > 65000) {
|
||||||
|
@ -187,10 +187,10 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
||||||
SOLAX_1878.data.u8[0] = (uint8_t)(datalayer.battery.status.voltage_dV);
|
SOLAX_1878.data.u8[0] = (uint8_t)(datalayer.battery.status.voltage_dV);
|
||||||
SOLAX_1878.data.u8[1] = ((datalayer.battery.status.voltage_dV) >> 8);
|
SOLAX_1878.data.u8[1] = ((datalayer.battery.status.voltage_dV) >> 8);
|
||||||
|
|
||||||
SOLAX_1878.data.u8[4] = (uint8_t)datalayer.battery.info.total_capacity_Wh;
|
SOLAX_1878.data.u8[4] = (uint8_t)datalayer.battery.info.reported_total_capacity_Wh;
|
||||||
SOLAX_1878.data.u8[5] = (datalayer.battery.info.total_capacity_Wh >> 8);
|
SOLAX_1878.data.u8[5] = (datalayer.battery.info.reported_total_capacity_Wh >> 8);
|
||||||
SOLAX_1878.data.u8[6] = (datalayer.battery.info.total_capacity_Wh >> 16);
|
SOLAX_1878.data.u8[6] = (datalayer.battery.info.reported_total_capacity_Wh >> 16);
|
||||||
SOLAX_1878.data.u8[7] = (datalayer.battery.info.total_capacity_Wh >> 24);
|
SOLAX_1878.data.u8[7] = (datalayer.battery.info.reported_total_capacity_Wh >> 24);
|
||||||
|
|
||||||
// BMS_Answer
|
// BMS_Answer
|
||||||
SOLAX_1801.data.u8[0] = 2;
|
SOLAX_1801.data.u8[0] = 2;
|
||||||
|
@ -198,10 +198,11 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
||||||
SOLAX_1801.data.u8[4] = 1;
|
SOLAX_1801.data.u8[4] = 1;
|
||||||
|
|
||||||
//Ultra messages
|
//Ultra messages
|
||||||
SOLAX_187E.data.u8[0] = (uint8_t)datalayer.battery.info.total_capacity_Wh;
|
SOLAX_187E.data.u8[0] = (uint8_t)datalayer.battery.info.reported_total_capacity_Wh;
|
||||||
SOLAX_187E.data.u8[1] = (datalayer.battery.info.total_capacity_Wh >> 8);
|
SOLAX_187E.data.u8[1] = (datalayer.battery.info.reported_total_capacity_Wh >> 8);
|
||||||
SOLAX_187E.data.u8[2] = (datalayer.battery.info.total_capacity_Wh >> 16);
|
SOLAX_187E.data.u8[2] = (datalayer.battery.info.reported_total_capacity_Wh >> 16);
|
||||||
SOLAX_187E.data.u8[3] = (datalayer.battery.info.total_capacity_Wh >> 24);
|
SOLAX_187E.data.u8[3] = (datalayer.battery.info.reported_total_capacity_Wh >> 24);
|
||||||
|
SOLAX_187E.data.u8[4] = (uint8_t)(datalayer.battery.status.soh_pptt / 100);
|
||||||
SOLAX_187E.data.u8[5] = (uint8_t)(datalayer.battery.status.reported_soc / 100);
|
SOLAX_187E.data.u8[5] = (uint8_t)(datalayer.battery.status.reported_soc / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue