mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 10:49:42 +02:00
Make cellmonitor handle 2 batteries
This commit is contained in:
parent
e141a5e910
commit
ae163e4814
3 changed files with 157 additions and 5 deletions
|
@ -586,7 +586,7 @@ void receive_can2() { // This function is similar to receive_can, but just take
|
||||||
#endif
|
#endif
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
receive_can_battery2(rx_frame_can2);
|
receive_can_battery2(rx_frame_can2);
|
||||||
#endif
|
#endif //DOUBLE_BATTERY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ void handle_CAN_contactors() {
|
||||||
(uint8_t)(abs(datalayer.battery.status.voltage_dV - datalayer.battery2.status.voltage_dV) / 10));
|
(uint8_t)(abs(datalayer.battery.status.voltage_dV - datalayer.battery2.status.voltage_dV) / 10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif //DOUBLE_BATTERY
|
||||||
|
|
||||||
#ifdef CONTACTOR_CONTROL
|
#ifdef CONTACTOR_CONTROL
|
||||||
void handle_contactors() {
|
void handle_contactors() {
|
||||||
|
@ -739,7 +739,7 @@ void update_SOC() {
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
datalayer.battery.status.reported_soc =
|
datalayer.battery.status.reported_soc =
|
||||||
(datalayer.battery.status.real_soc + datalayer.battery2.status.real_soc) / 2;
|
(datalayer.battery.status.real_soc + datalayer.battery2.status.real_soc) / 2;
|
||||||
#endif
|
#endif //DOUBLE_BATTERY
|
||||||
}
|
}
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
datalayer.battery.status.reported_soc = (datalayer.battery.status.real_soc + datalayer.battery2.status.real_soc) / 2;
|
datalayer.battery.status.reported_soc = (datalayer.battery.status.real_soc + datalayer.battery2.status.real_soc) / 2;
|
||||||
|
@ -758,7 +758,7 @@ void update_SOC() {
|
||||||
datalayer.battery.status.reported_soc = datalayer.battery2.status.real_soc;
|
datalayer.battery.status.reported_soc = datalayer.battery2.status.real_soc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //TODO: Constrain according to the user settings. Help wanted on algoritm to use.
|
#endif //DOUBLE_BATTERY
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_values_inverter() {
|
void update_values_inverter() {
|
||||||
|
|
|
@ -1249,6 +1249,12 @@ void setup_battery(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_design_voltage_dV =
|
datalayer.battery.info.max_design_voltage_dV =
|
||||||
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
4040; // 404.4V, over this, charging is not possible (goes into forced discharge)
|
||||||
datalayer.battery.info.min_design_voltage_dV = 2600; // 260.0V under this, discharging further is disabled
|
datalayer.battery.info.min_design_voltage_dV = 2600; // 260.0V under this, discharging further is disabled
|
||||||
|
|
||||||
|
#ifdef DOUBLE_BATTERY
|
||||||
|
datalayer.battery2.info.number_of_cells = datalayer.battery.info.number_of_cells;
|
||||||
|
datalayer.battery2.info.max_design_voltage_dV = datalayer.battery.info.max_design_voltage_dV;
|
||||||
|
datalayer.battery2.info.min_design_voltage_dV = datalayer.battery.info.min_design_voltage_dV;
|
||||||
|
#endif //DOUBLE_BATTERY
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,13 +12,25 @@ String cellmonitor_processor(const String& var) {
|
||||||
content += ".cell { width: 48%; margin: 1%; padding: 10px; border: 1px solid white; text-align: center; }";
|
content += ".cell { width: 48%; margin: 1%; padding: 10px; border: 1px solid white; text-align: center; }";
|
||||||
content += ".low-voltage { color: red; }"; // Style for low voltage text
|
content += ".low-voltage { color: red; }"; // Style for low voltage text
|
||||||
content += ".voltage-values { margin-bottom: 10px; }"; // Style for voltage values section
|
content += ".voltage-values { margin-bottom: 10px; }"; // Style for voltage values section
|
||||||
|
#ifdef DOUBLE_BATTERY
|
||||||
|
content +=
|
||||||
|
"#graph, #graph2 {display: flex;align-items: flex-end;height: 200px;border: 1px solid #ccc;position: "
|
||||||
|
"relative;}";
|
||||||
|
#else
|
||||||
content += "#graph {display: flex;align-items: flex-end;height: 200px;border: 1px solid #ccc;position: relative;}";
|
content += "#graph {display: flex;align-items: flex-end;height: 200px;border: 1px solid #ccc;position: relative;}";
|
||||||
|
#endif
|
||||||
content +=
|
content +=
|
||||||
".bar {margin: 0 0px;background-color: blue;display: inline-block;position: relative;cursor: pointer;border: "
|
".bar {margin: 0 0px;background-color: blue;display: inline-block;position: relative;cursor: pointer;border: "
|
||||||
"1px solid white; /* Add this line */}";
|
"1px solid white; /* Add this line */}";
|
||||||
|
#ifdef DOUBLE_BATTERY
|
||||||
|
content += "#valueDisplay, #valueDisplay2 {text-align: left;font-weight: bold;margin-top: 10px;}";
|
||||||
|
#else
|
||||||
content += "#valueDisplay {text-align: left;font-weight: bold;margin-top: 10px;}";
|
content += "#valueDisplay {text-align: left;font-weight: bold;margin-top: 10px;}";
|
||||||
|
#endif
|
||||||
content += "</style>";
|
content += "</style>";
|
||||||
|
|
||||||
|
content += "<button onclick='home()'>Back to main page</button>";
|
||||||
|
|
||||||
// Start a new block with a specific background color
|
// Start a new block with a specific background color
|
||||||
content += "<div style='background-color: #303E47; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
|
content += "<div style='background-color: #303E47; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
|
||||||
|
|
||||||
|
@ -33,7 +45,26 @@ String cellmonitor_processor(const String& var) {
|
||||||
|
|
||||||
// Close the block
|
// Close the block
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
|
|
||||||
|
#ifdef DOUBLE_BATTERY
|
||||||
|
// Start a new block with a specific background color
|
||||||
|
content += "<div style='background-color: #303E41; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
|
||||||
|
|
||||||
|
// Display max, min, and deviation voltage values
|
||||||
|
content += "<div id='voltageValues2' class='voltage-values'></div>";
|
||||||
|
// Display cells
|
||||||
|
content += "<div id='cellContainer2' class='container'></div>";
|
||||||
|
// Display bars
|
||||||
|
content += "<div id='graph2'></div>";
|
||||||
|
// Display single hovered value
|
||||||
|
content += "<div id='valueDisplay2'>Value: ...</div>";
|
||||||
|
|
||||||
|
// Close the block
|
||||||
|
content += "</div>";
|
||||||
|
|
||||||
content += "<button onclick='home()'>Back to main page</button>";
|
content += "<button onclick='home()'>Back to main page</button>";
|
||||||
|
#endif // DOUBLE_BATTERY
|
||||||
|
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
// Populate cell data
|
// Populate cell data
|
||||||
content += "const data = [";
|
content += "const data = [";
|
||||||
|
@ -149,8 +180,123 @@ String cellmonitor_processor(const String& var) {
|
||||||
"available';";
|
"available';";
|
||||||
content += "}";
|
content += "}";
|
||||||
|
|
||||||
|
#ifdef DOUBLE_BATTERY
|
||||||
|
// Populate cell data
|
||||||
|
content += "const data2 = [";
|
||||||
|
for (uint8_t i = 0u; i < datalayer.battery2.info.number_of_cells; i++) {
|
||||||
|
if (datalayer.battery2.status.cell_voltages_mV[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
content += String(datalayer.battery2.status.cell_voltages_mV[i]) + ",";
|
||||||
|
}
|
||||||
|
content += "];";
|
||||||
|
|
||||||
|
content += "const min_mv2 = Math.min(...data2) - 20;";
|
||||||
|
content += "const max_mv2 = Math.max(...data2) + 20;";
|
||||||
|
content += "const min_index2 = data2.indexOf(Math.min(...data2));";
|
||||||
|
content += "const max_index2 = data2.indexOf(Math.max(...data2));";
|
||||||
|
content += "const graphContainer2 = document.getElementById('graph2');";
|
||||||
|
content += "const valueDisplay2 = document.getElementById('valueDisplay2');";
|
||||||
|
content += "const cellContainer2 = document.getElementById('cellContainer2');";
|
||||||
|
|
||||||
|
// Arduino-style map() function
|
||||||
|
content +=
|
||||||
|
"function map2(value, fromLow, fromHigh, toLow, toHigh) {return (value - fromLow) * (toHigh - toLow) / "
|
||||||
|
"(fromHigh - fromLow) + toLow;}";
|
||||||
|
|
||||||
|
// Mark cell and bar with highest/lowest values
|
||||||
|
content +=
|
||||||
|
"function checkMinMax2(cell2, bar2, index2) {if ((index2 == min_index2) || (index2 == max_index2)) "
|
||||||
|
"{cell2.style.borderColor = 'red';bar2.style.borderColor = 'red';}}";
|
||||||
|
|
||||||
|
// Bar function. Basically get the mV, scale the height and add a bar div to its container
|
||||||
|
content +=
|
||||||
|
"function createBars2(data2) {"
|
||||||
|
"data2.forEach((mV, index2) => {"
|
||||||
|
"const bar2 = document.createElement('div');"
|
||||||
|
"const mV_limited2 = map2(mV, min_mv2, max_mv2, 20, 200);"
|
||||||
|
"bar2.className = 'bar';"
|
||||||
|
"bar2.id = `barIndex2${index2}`;"
|
||||||
|
"bar2.style.height = `${mV_limited2}px`;"
|
||||||
|
"bar2.style.width = `${750/data2.length}px`;"
|
||||||
|
|
||||||
|
"const cell2 = document.getElementById(`cellIndex2${index2}`);"
|
||||||
|
|
||||||
|
"checkMinMax2(cell2, bar2, index2);"
|
||||||
|
|
||||||
|
"bar2.addEventListener('mouseenter', () => {"
|
||||||
|
"valueDisplay2.textContent = `Value: ${mV}`;"
|
||||||
|
"bar2.style.backgroundColor = `lightblue`;"
|
||||||
|
"cell2.style.backgroundColor = `blue`;"
|
||||||
|
"});"
|
||||||
|
|
||||||
|
"bar2.addEventListener('mouseleave', () => {"
|
||||||
|
"valueDisplay2.textContent = 'Value: ...';"
|
||||||
|
"bar2.style.backgroundColor = `blue`;"
|
||||||
|
"cell2.style.removeProperty('background-color');"
|
||||||
|
"});"
|
||||||
|
|
||||||
|
"graphContainer2.appendChild(bar2);"
|
||||||
|
"});"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
// Cell population function. For each value, add a cell block with its value
|
||||||
|
content +=
|
||||||
|
"function createCells2(data2) {"
|
||||||
|
"data2.forEach((mV, index2) => {"
|
||||||
|
"const cell2 = document.createElement('div');"
|
||||||
|
"cell2.className = 'cell';"
|
||||||
|
"cell2.id = `cellIndex2${index2}`;"
|
||||||
|
"let cellContent2 = `Cell ${index2 + 1}<br>${mV} mV`;"
|
||||||
|
"if (mV < 3000) {"
|
||||||
|
"cellContent2 = `<span class='low-voltage'>${cellContent2}</span>`;"
|
||||||
|
"}"
|
||||||
|
"cell2.innerHTML = cellContent2;"
|
||||||
|
|
||||||
|
"cell2.addEventListener('mouseenter', () => {"
|
||||||
|
"let bar2 = document.getElementById(`barIndex2${index2}`);"
|
||||||
|
"valueDisplay2.textContent = `Value: ${mV}`;"
|
||||||
|
"bar2.style.backgroundColor = `lightblue`;"
|
||||||
|
"cell2.style.backgroundColor = `blue`;"
|
||||||
|
"});"
|
||||||
|
|
||||||
|
"cell2.addEventListener('mouseleave', () => {"
|
||||||
|
"let bar2 = document.getElementById(`barIndex2${index2}`);"
|
||||||
|
"bar2.style.backgroundColor = `blue`;"
|
||||||
|
"cell2.style.removeProperty('background-color');"
|
||||||
|
"});"
|
||||||
|
|
||||||
|
"cellContainer2.appendChild(cell2);"
|
||||||
|
"});"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
// On fetch, update the header of max/min/deviation client-side for consistency
|
||||||
|
content +=
|
||||||
|
"function updateVoltageValues2(data2) {"
|
||||||
|
"const min_mv2 = Math.min(...data2);"
|
||||||
|
"const max_mv2 = Math.max(...data2);"
|
||||||
|
"const cell_dev2 = max_mv2 - min_mv2;"
|
||||||
|
"const voltVal2 = document.getElementById('voltageValues2');"
|
||||||
|
"voltVal2.innerHTML = `Max Voltage : ${max_mv2} mV<br>Min Voltage: ${min_mv2} mV<br>Voltage Deviation: "
|
||||||
|
"${cell_dev2} mV`"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
// If we have values, do the thing. Otherwise, display friendly message and wait
|
||||||
|
content += "if (data2.length != 0) {";
|
||||||
|
content += "createCells2(data2);";
|
||||||
|
content += "createBars2(data2);";
|
||||||
|
content += "updateVoltageValues2(data2);";
|
||||||
|
content += "}";
|
||||||
|
content += "else {";
|
||||||
|
content +=
|
||||||
|
"document.getElementById('voltageValues2').textContent = 'Cell information not yet fetched, or information not "
|
||||||
|
"available';";
|
||||||
|
content += "}";
|
||||||
|
|
||||||
|
#endif //DOUBLE_BATTERY
|
||||||
|
|
||||||
// Automatic refresh is nice
|
// Automatic refresh is nice
|
||||||
content += "setTimeout(function(){ location.reload(true); }, 10000);";
|
content += "setTimeout(function(){ location.reload(true); }, 20000);";
|
||||||
|
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
return content;
|
return content;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue