diff --git a/Software/src/communication/nvm/comm_nvm.h b/Software/src/communication/nvm/comm_nvm.h index 20dcf622..7b4ecb14 100644 --- a/Software/src/communication/nvm/comm_nvm.h +++ b/Software/src/communication/nvm/comm_nvm.h @@ -6,6 +6,7 @@ #include #include "../../datalayer/datalayer.h" #include "../../devboard/utils/events.h" +#include "../../devboard/utils/logging.h" #include "../../devboard/wifi/wifi.h" /** diff --git a/Software/src/devboard/webserver/index_html.cpp b/Software/src/devboard/webserver/index_html.cpp index 5611824f..f67cc092 100644 --- a/Software/src/devboard/webserver/index_html.cpp +++ b/Software/src/devboard/webserver/index_html.cpp @@ -1,25 +1,5 @@ #include "index_html.h" -#define INDEX_HTML_HEADER \ - R"rawliteral(Battery Emulator)rawliteral" -#define INDEX_HTML_FOOTER R"rawliteral()rawliteral"; - -#define COMMON_JAVASCRIPT \ - R"rawliteral( - -)rawliteral" - const char index_html[] = INDEX_HTML_HEADER COMMON_JAVASCRIPT "%X%" INDEX_HTML_FOOTER; const char index_html_header[] = INDEX_HTML_HEADER; const char index_html_footer[] = INDEX_HTML_FOOTER; diff --git a/Software/src/devboard/webserver/index_html.h b/Software/src/devboard/webserver/index_html.h index 8a095650..cd867244 100644 --- a/Software/src/devboard/webserver/index_html.h +++ b/Software/src/devboard/webserver/index_html.h @@ -1,6 +1,26 @@ #ifndef INDEX_HTML_H #define INDEX_HTML_H +#define INDEX_HTML_HEADER \ + R"rawliteral(Battery Emulator)rawliteral" +#define INDEX_HTML_FOOTER R"rawliteral()rawliteral"; + +#define COMMON_JAVASCRIPT \ + R"rawliteral( + +)rawliteral" + extern const char index_html[]; extern const char index_html_header[]; extern const char index_html_footer[]; diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 46aaedb7..149677b0 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -6,6 +6,7 @@ #include "../../communication/nvm/comm_nvm.h" #include "../../datalayer/datalayer.h" #include "../../include.h" +#include "index_html.h" extern bool settingsUpdated; @@ -118,32 +119,207 @@ void render_textbox(String& content, const char* label, const char* name, Batter content += "\"/>"; } -String settings_processor(const String& var) { +String settings_processor(const String& var, BatteryEmulatorSettingsStore& settings) { + if (var == "BATTERYINTF") { + if (battery) { + return battery->interface_name(); + } + } + if (var == "SSID") { + return String(ssid.c_str()); + } + +#ifndef COMMON_IMAGE + if (var == "COMMONIMAGEDIVCLASS") { + return "hidden"; + } +#endif + + if (var == "SAVEDCLASS") { + if (!settingsUpdated) { + return "hidden"; + } + } + + if (var == "BATTERY2CLASS") { + if (!battery2) { + return "hidden"; + } + } + + if (var == "BATTERY2INTF") { + if (battery2) { + return battery2->interface_name(); + } + } + + if (var == "INVCLASS") { + if (!inverter) { + return "hidden"; + } + } + + if (var == "SHUNTCLASS") { + if (!shunt) { + return "hidden"; + } + } + + if (var == "CHARGERCLASS") { + if (!charger) { + return "hidden"; + } + } + + if (var == "SHUNTCOMM") { + return options_for_enum((comm_interface)settings.getUInt("SHUNTCOMM", (int)comm_interface::CanNative), + name_for_comm_interface); + } + + if (var == "BATTTYPE") { + return options_for_enum_with_none((BatteryType)settings.getUInt("BATTTYPE", (int)BatteryType::None), + name_for_battery_type, BatteryType::None); + } + if (var == "BATTCOMM") { + return options_for_enum((comm_interface)settings.getUInt("BATTCOMM", (int)comm_interface::CanNative), + name_for_comm_interface); + } + if (var == "BATTCHEM") { + return options_for_enum((battery_chemistry_enum)settings.getUInt("BATTCHEM", (int)battery_chemistry_enum::NCA), + name_for_chemistry); + } + if (var == "INVTYPE") { + return options_for_enum_with_none( + (InverterProtocolType)settings.getUInt("INVTYPE", (int)InverterProtocolType::None), name_for_inverter_type, + InverterProtocolType::None); + } + if (var == "INVCOMM") { + return options_for_enum((comm_interface)settings.getUInt("INVCOMM", (int)comm_interface::CanNative), + name_for_comm_interface); + } + if (var == "CHGTYPE") { + return options_for_enum_with_none((ChargerType)settings.getUInt("CHGTYPE", (int)ChargerType::None), + name_for_charger_type, ChargerType::None); + } + if (var == "CHGCOMM") { + return options_for_enum((comm_interface)settings.getUInt("CHGCOMM", (int)comm_interface::CanNative), + name_for_comm_interface); + } + if (var == "EQSTOP") { + return options_for_enum_with_none( + (STOP_BUTTON_BEHAVIOR)settings.getUInt("EQSTOP", (int)STOP_BUTTON_BEHAVIOR::NOT_CONNECTED), + name_for_button_type, STOP_BUTTON_BEHAVIOR::NOT_CONNECTED); + } + + if (var == "BATT2COMM") { + return options_for_enum((comm_interface)settings.getUInt("BATT2COMM", (int)comm_interface::CanNative), + name_for_comm_interface); + } + + if (var == "DBLBTR") { + return settings.getBool("DBLBTR") ? "checked" : ""; + } + + if (var == "CNTCTRL") { + return settings.getBool("CNTCTRL") ? "checked" : ""; + } + + if (var == "CNTCTRLDBL") { + return settings.getBool("CNTCTRLDBL") ? "checked" : ""; + } + + if (var == "PWMCNTCTRL") { + return settings.getBool("PWMCNTCTRL") ? "checked" : ""; + } + + if (var == "PERBMSRESET") { + return settings.getBool("PERBMSRESET") ? "checked" : ""; + } + + if (var == "REMBMSRESET") { + return settings.getBool("REMBMSRESET") ? "checked" : ""; + } + + if (var == "CANFDASCAN") { + return settings.getBool("CANFDASCAN") ? "checked" : ""; + } + + if (var == "WIFIAPENABLED") { + return settings.getBool("WIFIAPENABLED") ? "checked" : ""; + } + + if (var == "MQTTENABLED") { + return settings.getBool("MQTTENABLED") ? "checked" : ""; + } + + if (var == "BATTERY_WH_MAX") { + return String(datalayer.battery.info.total_capacity_Wh); + } + + if (var == "MAX_CHARGE_SPEED") { + return String(datalayer.battery.settings.max_user_set_charge_dA / 10.0, 1); + } + + if (var == "MAX_DISCHARGE_SPEED") { + return String(datalayer.battery.settings.max_user_set_discharge_dA / 10.0, 1); + } + + if (var == "SOC_MAX_PERCENTAGE") { + return String(datalayer.battery.settings.max_percentage / 100.0, 1); + } + + if (var == "SOC_MIN_PERCENTAGE") { + return String(datalayer.battery.settings.min_percentage / 100.0, 1); + } + + if (var == "CHARGE_VOLTAGE") { + return String(datalayer.battery.settings.max_user_set_charge_voltage_dV / 10.0, 1); + } + + if (var == "DISCHARGE_VOLTAGE") { + return String(datalayer.battery.settings.max_user_set_discharge_voltage_dV / 10.0, 1); + } + + if (var == "SOC_SCALING_ACTIVE_CLASS") { + return datalayer.battery.settings.soc_scaling_active ? "active" : "inactive"; + } + + if (var == "VOLTAGE_LIMITS_ACTIVE_CLASS") { + return datalayer.battery.settings.user_set_voltage_limits_active ? "active" : "inactive"; + } + + if (var == "SOC_SCALING_CLASS") { + return datalayer.battery.settings.soc_scaling_active ? "active" : "inactiveSoc"; + } + + if (var == "SOC_SCALING") { + return datalayer.battery.settings.soc_scaling_active ? "✓" : "✕"; + } + + if (var == "FAKE_VOLTAGE_CLASS") { + return battery && battery->supports_set_fake_voltage() ? "" : "hidden"; + } + + if (var == "BATTERY_VOLTAGE") { + if (battery) { + return String(battery->get_voltage(), 1); + } + } + + if (var == "VOLTAGE_LIMITS") { + if (datalayer.battery.settings.user_set_voltage_limits_active) { + return "✓"; + } else { + return "✕"; + } + } + if (var == "X") { String content = ""; //Page format - content += ""; - - content += ""; - - // Start a new block with a specific background color - content += "
"; - - content += "

SSID: " + String(ssid.c_str()) + - "

"; - content += - "

Password: ########

"; #ifdef COMMON_IMAGE - BatteryEmulatorSettingsStore settings(true); + //BatteryEmulatorSettingsStore settings(true); // It's important that we read/write settings directly to settings store instead of the run-time values // since the run-time values may have direct effect on operation. @@ -377,177 +553,6 @@ String settings_processor(const String& var) { content += "
"; } - content += ""; - - content += ""; return content; } return String(); @@ -575,3 +580,300 @@ const char* getCANInterfaceName(CAN_Interface interface) { return "UNKNOWN"; } } + +#define SETTINGS_HTML_SCRIPTS \ + R"rawliteral( + +)rawliteral" + +#define SETTINGS_STYLE \ + R"rawliteral( + +)rawliteral" + +#define SETTINGS_HTML_BODY \ + R"rawliteral( + + +
+

SSID: %SSID%

+

Password: ########

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+

Settings saved. Reboot to take the settings into use.

+

+ +
+
+
+ +

Battery interface: %BATTERYINTF%

+ +

Battery interface: %BATTERY2INTF%

+ +

Inverter interface: %INVINTF%

+ +

Shunt interface: %SHUNTINTF%

+ + + +
+ + + +

Battery capacity: %BATTERY_WH_MAX% Wh

+ +

Rescale SOC: %SOC_SCALING% +

+ +

SOC max percentage: %SOC_MAX_PERCENTAGE%

"; + +

SOC min percentage: %SOC_MAX_PERCENTAGE%

"; + +

Max charge speed: %MAX_CHARGE_SPEED% A

+ +

Max discharge speed: %MAX_DISCHARGE_SPEED% A

+ +

Manual charge voltage limits: + %VOLTAGE_LIMITS% +

+ +

Target charge voltage: %CHARGE_VOLTAGE% V

+ +

Target discharge voltage: %DISCHARGE_VOLTAGE% V

+ +
+ +
+

Fake battery voltage: %BATTERY_VOLTAGE% V

+
+ + + +
+ +

Manual LFP balancing: + String(datalayer.battery.settings.user_requests_balancing ? "" + : "") + +

+

Balancing max time: " + String(datalayer.battery.settings.balancing_time_ms / 60000.0, 1) + + Minutes

+ +

Balancing float power: " + String(datalayer.battery.settings.balancing_float_power_W / 1.0, 0) + + W

"; + +

Max battery voltage: " + String(datalayer.battery.settings.balancing_max_pack_voltage_dV / 10.0, 0) + + V

"; + +

Max cell voltage: " + String(datalayer.battery.settings.balancing_max_cell_voltage_mV / 1.0, 0) + + mV

"; + +

Max cell voltage deviation: + String(datalayer.battery.settings.balancing_max_deviation_cell_voltage_mV / 1.0, 0) + + mV

+ +
+ + + + +)rawliteral" + +const char settings_html[] = + INDEX_HTML_HEADER COMMON_JAVASCRIPT SETTINGS_STYLE SETTINGS_HTML_BODY SETTINGS_HTML_SCRIPTS INDEX_HTML_FOOTER; diff --git a/Software/src/devboard/webserver/settings_html.h b/Software/src/devboard/webserver/settings_html.h index b723130e..17043a37 100644 --- a/Software/src/devboard/webserver/settings_html.h +++ b/Software/src/devboard/webserver/settings_html.h @@ -8,6 +8,7 @@ extern std::string ssid; extern std::string password; #include "../../../USER_SETTINGS.h" // Needed for WiFi ssid and password +#include "../../communication/nvm/comm_nvm.h" /** * @brief Replaces placeholder with content section in web page @@ -16,7 +17,7 @@ extern std::string password; * * @return String */ -String settings_processor(const String& var); +String settings_processor(const String& var, BatteryEmulatorSettingsStore& settings); /** * @brief Maps the value to a string of characters * @@ -26,4 +27,6 @@ String settings_processor(const String& var); */ const char* getCANInterfaceName(CAN_Interface interface); +extern const char settings_html[]; + #endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 15cd4eae..f57a8cf2 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -187,9 +187,15 @@ void init_webserver() { // Route for going to settings web page server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) { - if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) + if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { return request->requestAuthentication(); - request->send(200, "text/html", index_html, settings_processor); + } + + // Using make_shared to ensure lifetime for the settings object during send() lambda execution + auto settings = std::make_shared(true); + + request->send(200, "text/html", settings_html, + [settings](const String& content) { return settings_processor(content, *settings); }); }); // Route for going to advanced battery info web page