diff --git a/Software/Software.ino b/Software/Software.ino
index 6b457798..b458b49c 100644
--- a/Software/Software.ino
+++ b/Software/Software.ino
@@ -462,6 +462,10 @@ void update_calculated_values() {
} else {
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 {
datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery.status.remaining_capacity_Wh;
diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h
index 6122c8f9..e9fc9867 100644
--- a/Software/src/datalayer/datalayer.h
+++ b/Software/src/datalayer/datalayer.h
@@ -7,6 +7,7 @@ typedef struct {
/** uint32_t */
/** Total energy capacity in Watt-hours */
uint32_t total_capacity_Wh = BATTERY_WH_MAX;
+ uint32_t reported_total_capacity_Wh = BATTERY_WH_MAX;
/** uint16_t */
/** The maximum intended packvoltage, in deciVolt. 4900 = 490.0 V */
diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp
index 78224a60..51b65288 100644
--- a/Software/src/devboard/webserver/webserver.cpp
+++ b/Software/src/devboard/webserver/webserver.cpp
@@ -1054,16 +1054,30 @@ String processor(const String& var) {
uint16_t cell_delta_mv =
datalayer.battery.status.cell_max_voltage_mV - datalayer.battery.status.cell_min_voltage_mV;
- content += "
Real SOC: " + String(socRealFloat, 2) + "%
";
- content += "Scaled SOC: " + String(socScaledFloat, 2) + "%
";
+ if (datalayer.battery.settings.soc_scaling_active)
+ content += "Scaled SOC: " + String(socScaledFloat, 2) +
+ "% (real: " + String(socRealFloat, 2) + "%)
";
+ else
+ content += "SOC: " + String(socRealFloat, 2) + "%
";
+
content += "SOH: " + String(sohFloat, 2) + "%
";
- content += "Voltage: " + String(voltageFloat, 1) + " V
";
- content += "Current: " + String(currentFloat, 1) + " A
";
+ content += "Voltage: " + String(voltageFloat, 1) +
+ " V Current: " + String(currentFloat, 1) + " A
";
content += formatPowerValue("Power", powerFloat, "", 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 +=
- formatPowerValue("Scaled Remaining capacity", datalayer.battery.status.reported_remaining_capacity_Wh, "h", 1);
+
+ if (datalayer.battery.settings.soc_scaling_active)
+ content += "Scaled total capacity: " +
+ formatPowerValue(datalayer.battery.info.reported_total_capacity_Wh, "h", 1) +
+ " (real: " + formatPowerValue(datalayer.battery.info.total_capacity_Wh, "h", 1) + ")
";
+ else
+ content += formatPowerValue("Total capacity", datalayer.battery.info.total_capacity_Wh, "h", 1);
+
+ if (datalayer.battery.settings.soc_scaling_active)
+ content += "Scaled remaining capacity: " +
+ formatPowerValue(datalayer.battery.status.reported_remaining_capacity_Wh, "h", 1) +
+ " (real: " + formatPowerValue(datalayer.battery.status.remaining_capacity_Wh, "h", 1) + ")
";
+ else
+ content += formatPowerValue("Remaining capacity", datalayer.battery.status.remaining_capacity_Wh, "h", 1);
if (datalayer.system.settings.equipment_stop_active) {
content += formatPowerValue("Max discharge power", datalayer.battery.status.max_discharge_power_W, "", 1, "red");
@@ -1087,15 +1101,15 @@ String processor(const String& var) {
}
}
- content += "Cell max: " + String(datalayer.battery.status.cell_max_voltage_mV) + " mV
";
- content += "Cell min: " + String(datalayer.battery.status.cell_min_voltage_mV) + " mV
";
+ content += "Cell min/max: " + String(datalayer.battery.status.cell_min_voltage_mV) + " mV / " +
+ String(datalayer.battery.status.cell_max_voltage_mV) + " mV
";
if (cell_delta_mv > datalayer.battery.info.max_cell_voltage_deviation_mV) {
content += "Cell delta: " + String(cell_delta_mv) + " mV
";
} else {
content += "Cell delta: " + String(cell_delta_mv) + " mV
";
}
- content += "Temperature max: " + String(tempMaxFloat, 1) + " °C
";
- content += "Temperature min: " + String(tempMinFloat, 1) + " °C
";
+ content +=
+ "Temperature min/max: " + String(tempMinFloat, 1) + " °C / " + String(tempMaxFloat, 1) + " °C
";
content += "System status: ";
switch (datalayer.battery.status.bms_status) {
@@ -1261,16 +1275,30 @@ String processor(const String& var) {
tempMinFloat = static_cast(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;
- content += "Real SOC: " + String(socRealFloat, 2) + "%
";
- content += "Scaled SOC: " + String(socScaledFloat, 2) + "%
";
+ if (datalayer.battery.settings.soc_scaling_active)
+ content += "Scaled SOC: " + String(socScaledFloat, 2) +
+ "% (real: " + String(socRealFloat, 2) + "%)
";
+ else
+ content += "SOC: " + String(socRealFloat, 2) + "%
";
+
content += "SOH: " + String(sohFloat, 2) + "%
";
- content += "Voltage: " + String(voltageFloat, 1) + " V
";
- content += "Current: " + String(currentFloat, 1) + " A
";
+ content += "Voltage: " + String(voltageFloat, 1) +
+ " V Current: " + String(currentFloat, 1) + " A
";
content += formatPowerValue("Power", powerFloat, "", 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 +=
- formatPowerValue("Scaled Remaining capacity", datalayer.battery2.status.reported_remaining_capacity_Wh, "h", 1);
+
+ if (datalayer.battery.settings.soc_scaling_active)
+ content += "Scaled total capacity: " +
+ formatPowerValue(datalayer.battery2.info.reported_total_capacity_Wh, "h", 1) +
+ " (real: " + formatPowerValue(datalayer.battery2.info.total_capacity_Wh, "h", 1) + ")
";
+ else
+ content += formatPowerValue("Total capacity", datalayer.battery2.info.total_capacity_Wh, "h", 1);
+
+ if (datalayer.battery.settings.soc_scaling_active)
+ content += "Scaled remaining capacity: " +
+ formatPowerValue(datalayer.battery2.status.reported_remaining_capacity_Wh, "h", 1) +
+ " (real: " + formatPowerValue(datalayer.battery2.status.remaining_capacity_Wh, "h", 1) + ")
";
+ else
+ content += formatPowerValue("Remaining capacity", datalayer.battery2.status.remaining_capacity_Wh, "h", 1);
if (datalayer.system.settings.equipment_stop_active) {
content += formatPowerValue("Max discharge power", datalayer.battery2.status.max_discharge_power_W, "", 1, "red");
@@ -1284,15 +1312,15 @@ String processor(const String& var) {
content += "Max charge current: " + String(maxCurrentChargeFloat, 1) + " A
";
}
- content += "Cell max: " + String(datalayer.battery2.status.cell_max_voltage_mV) + " mV
";
- content += "Cell min: " + String(datalayer.battery2.status.cell_min_voltage_mV) + " mV
";
+ content += "Cell min/max: " + String(datalayer.battery2.status.cell_min_voltage_mV) + " mV / " +
+ String(datalayer.battery2.status.cell_max_voltage_mV) + " mV
";
if (cell_delta_mv > datalayer.battery2.info.max_cell_voltage_deviation_mV) {
content += "Cell delta: " + String(cell_delta_mv) + " mV
";
} else {
content += "Cell delta: " + String(cell_delta_mv) + " mV
";
}
- content += "Temperature max: " + String(tempMaxFloat, 1) + " °C
";
- content += "Temperature min: " + String(tempMinFloat, 1) + " °C
";
+ content +=
+ "Temperature min/max: " + String(tempMinFloat, 1) + " °C / " + String(tempMaxFloat, 1) + " °C
";
if (datalayer.battery.status.bms_status == ACTIVE) {
content += "System status: OK
";
} else if (datalayer.battery.status.bms_status == UPDATING) {
@@ -1564,6 +1592,13 @@ void onOTAEnd(bool success) {
template // 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 result = "" + label + ": ";
+ result += formatPowerValue(value, unit, precision);
+ result += "
";
+ return result;
+}
+template // 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::value || std::is_same::value || std::is_same::value) {
float convertedValue = static_cast(value);
@@ -1575,6 +1610,6 @@ String formatPowerValue(String label, T value, String unit, int precision, Strin
}
}
- result += unit + "
";
+ result += unit;
return result;
}
diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h
index 3e2a71a1..62d8d90c 100644
--- a/Software/src/devboard/webserver/webserver.h
+++ b/Software/src/devboard/webserver/webserver.h
@@ -103,6 +103,9 @@ void onOTAEnd(bool success);
template
String formatPowerValue(String label, T value, String unit, int precision, String color = "white");
+template // 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();
void ota_monitor();
diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp
index 05675b1c..dec2b961 100644
--- a/Software/src/inverter/SOLAX-CAN.cpp
+++ b/Software/src/inverter/SOLAX-CAN.cpp
@@ -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);
// 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;
} 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
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[1] = ((datalayer.battery.status.voltage_dV) >> 8);
- SOLAX_1878.data.u8[4] = (uint8_t)datalayer.battery.info.total_capacity_Wh;
- SOLAX_1878.data.u8[5] = (datalayer.battery.info.total_capacity_Wh >> 8);
- SOLAX_1878.data.u8[6] = (datalayer.battery.info.total_capacity_Wh >> 16);
- SOLAX_1878.data.u8[7] = (datalayer.battery.info.total_capacity_Wh >> 24);
+ SOLAX_1878.data.u8[4] = (uint8_t)datalayer.battery.info.reported_total_capacity_Wh;
+ SOLAX_1878.data.u8[5] = (datalayer.battery.info.reported_total_capacity_Wh >> 8);
+ SOLAX_1878.data.u8[6] = (datalayer.battery.info.reported_total_capacity_Wh >> 16);
+ SOLAX_1878.data.u8[7] = (datalayer.battery.info.reported_total_capacity_Wh >> 24);
// BMS_Answer
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;
//Ultra messages
- SOLAX_187E.data.u8[0] = (uint8_t)datalayer.battery.info.total_capacity_Wh;
- SOLAX_187E.data.u8[1] = (datalayer.battery.info.total_capacity_Wh >> 8);
- SOLAX_187E.data.u8[2] = (datalayer.battery.info.total_capacity_Wh >> 16);
- SOLAX_187E.data.u8[3] = (datalayer.battery.info.total_capacity_Wh >> 24);
+ SOLAX_187E.data.u8[0] = (uint8_t)datalayer.battery.info.reported_total_capacity_Wh;
+ SOLAX_187E.data.u8[1] = (datalayer.battery.info.reported_total_capacity_Wh >> 8);
+ SOLAX_187E.data.u8[2] = (datalayer.battery.info.reported_total_capacity_Wh >> 16);
+ 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);
}