diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index ea1418d3..68273896 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -1,9 +1,25 @@ #include "USER_SETTINGS.h" +/* This file contains all the battery settings and limits */ +/* They can be defined here, or later on in the WebUI */ + +/* Battery settings */ +volatile uint16_t BATTERY_WH_MAX = + 30000; //Battery size in Wh (Maximum value for most inverters is 65000 [65kWh], you can use larger batteries but do not set value over 65000! +volatile uint16_t MAXPERCENTAGE = + 800; //80.0% , Max percentage the battery will charge to (App will show 100% once this value is reached) +volatile uint16_t MINPERCENTAGE = + 200; //20.0% , Min percentage the battery will discharge to (App will show 0% once this value is reached) +volatile uint16_t MAXCHARGEAMP = + 300; //30.0A , BYD CAN specific setting, Max charge speed in Amp (Some inverters needs to be artificially limited) +volatile uint16_t MAXDISCHARGEAMP = + 300; //30.0A , BYD CAN specific setting, Max discharge speed in Amp (Some inverters needs to be artificially limited) + #ifdef WEBSERVER -#define ENABLE_AP //Comment out this line to turn off the broadcasted AP -const char* ssid = "REPLACE_WITH_YOUR_SSID"; // maximum of 63 characters; -const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // minimum of 8 characters; -const char* ssidAP = "Battery Emulator"; // maximum of 63 characters; -const char* passwordAP = "123456789"; // minimum of 8 characters; set to NULL if you want the access point to be open +#define ENABLE_AP // Comment out this line to turn off the broadcasted AP +const char* ssid = "REPLACE_WITH_YOUR_SSID"; // Maximum of 63 characters; +const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Minimum of 8 characters; +const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters; +const char* passwordAP = "123456789"; // Minimum of 8 characters; set to NULL if you want the access point to be open +const char* versionNumber = "4.3.0"; // The current software version, shown on webserver #endif diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 7cf64c3d..1b9f963e 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -1,9 +1,11 @@ #ifndef __USER_SETTINGS_H__ #define __USER_SETTINGS_H__ +#include -/* This file contains all the user configurable settings for the Battery-Emulator software */ +/* This file contains all the battery/inverter protocol settings Battery-Emulator software */ /* To switch between batteries/inverters, uncomment a line to enable, comment out to disable. */ /* There are also some options for battery limits and extra functionality */ +/* To edit battery specific limits, see also the USER_SETTINGS.cpp file*/ /* Select battery used */ //#define BMW_I3_BATTERY @@ -26,21 +28,9 @@ //#define SOFAR_CAN //Enable this line to emulate a "Sofar Energy Storage Inverter High Voltage BMS General Protocol (Extended Frame)" over CAN bus //#define SOLAX_CAN //Enable this line to emulate a "SolaX Triple Power LFP" over CAN bus -/* Battery settings */ -#define BATTERY_WH_MAX \ - 30000 //Battery size in Wh (Maximum value for most inverters is 65000 [65kWh], you can use larger batteries but do not set value over 65000! -#define MAXPERCENTAGE \ - 800 //80.0% , Max percentage the battery will charge to (App will show 100% once this value is reached) -#define MINPERCENTAGE \ - 200 //20.0% , Min percentage the battery will discharge to (App will show 0% once this value is reached) -#define MAXCHARGEAMP \ - 300 //30.0A , BYD CAN specific setting, Max charge speed in Amp (Some inverters needs to be artificially limited) -#define MAXDISCHARGEAMP \ - 300 //30.0A , BYD CAN specific setting, Max discharge speed in Amp (Some inverters needs to be artificially limited) -//define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting - /* Other options */ #define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs +//define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence //#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM logic for contactors, which lower power consumption and heat generation //#define DUAL_CAN //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 controller (Needed for FoxESS inverters) @@ -48,4 +38,10 @@ //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) //#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. +/* Battery limits: These are set in the USER_SETTINGS.cpp file, or later on via the Webserver */ +extern volatile uint16_t BATTERY_WH_MAX; +extern volatile uint16_t MAXPERCENTAGE; +extern volatile uint16_t MINPERCENTAGE; +extern volatile uint16_t MAXCHARGEAMP; +extern volatile uint16_t MAXDISCHARGEAMP; #endif diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index ad48c6db..547b8ab1 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -56,6 +56,70 @@ void init_webserver() { server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { request->send_P(200, "text/html", index_html, processor); }); + // Route for going to settings web page + server.on("/settings", HTTP_GET, + [](AsyncWebServerRequest* request) { request->send_P(200, "text/html", index_html, settings_processor); }); + + // Route for editing Wh + server.on("/updateBatterySize", HTTP_GET, [](AsyncWebServerRequest* request) { + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + // Convert the string to an integer and update the variable + BATTERY_WH_MAX = value.toInt(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + + // Route for editing SOCMax + server.on("/updateSocMax", HTTP_GET, [](AsyncWebServerRequest* request) { + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + // Convert the string to an integer and update the variable + MAXPERCENTAGE = value.toInt(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + + // Route for editing SOCMin + server.on("/updateSocMin", HTTP_GET, [](AsyncWebServerRequest* request) { + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + // Convert the string to an integer and update the variable + MINPERCENTAGE = value.toInt(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + + // Route for editing MaxChargeA + server.on("/updateMaxChargeA", HTTP_GET, [](AsyncWebServerRequest* request) { + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + // Convert the string to an integer and update the variable + MAXCHARGEAMP = value.toInt(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + + // Route for editing MaxDischargeA + server.on("/updateMaxDischargeA", HTTP_GET, [](AsyncWebServerRequest* request) { + if (request->hasParam("value")) { + String value = request->getParam("value")->value(); + // Convert the string to an integer and update the variable + MAXDISCHARGEAMP = value.toInt(); + request->send(200, "text/plain", "Updated successfully"); + } else { + request->send(400, "text/plain", "Bad Request"); + } + }); + // Send a GET request to /update server.on("/debug", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(200, "text/plain", "Debug: all OK."); }); @@ -63,6 +127,7 @@ void init_webserver() { // Route to handle reboot command server.on("/reboot", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(200, "text/plain", "Rebooting server..."); + //TODO: Should we handle contactors gracefully? Ifdef CONTACTOR_CONTROL then what? delay(1000); ESP.restart(); }); @@ -140,6 +205,9 @@ String processor(const String& var) { // Start a new block with a specific background color content += "
"; + // Show version number + content += "

Software version: " + String(versionNumber) + "

"; + // Display LED color content += "

LED color: "; switch (LEDcolor) { @@ -167,46 +235,7 @@ String processor(const String& var) { if (wifi_connected == true) { content += "

IP: " + WiFi.localIP().toString() + "

"; // Get and display the signal strength (RSSI) - //content += "

Signal Strength: " + String(WiFi.RSSI()) + " dBm

"; - - // Get and display the signal strength (RSSI) as a 0-5 bar visualization - //int rssiValue = WiFi.RSSI(); - //int signalStrengthBars = map(rssiValue, -100, -50, 0, 5); - //signalStrengthBars = constrain(signalStrengthBars, 0, 5); - //content += "

Signal Strength: " + String(signalStrengthBars) + " out of 5 bars

"; - - // Get and display the signal strength (RSSI) as Unicode blocks - int rssiValue = WiFi.RSSI(); - int signalStrengthBars = map(rssiValue, -100, -50, 0, 5); - signalStrengthBars = constrain(signalStrengthBars, 0, 5); - String filledBlock = "█"; // Unicode for a filled block - String emptyBlock = "░"; // Unicode for an empty block - - String signalStrengthText = ""; - switch (signalStrengthBars) { - case 0: - signalStrengthText = emptyBlock + emptyBlock + emptyBlock + emptyBlock + emptyBlock; - break; - case 1: - signalStrengthText = filledBlock + emptyBlock + emptyBlock + emptyBlock + emptyBlock; - break; - case 2: - signalStrengthText = filledBlock + filledBlock + emptyBlock + emptyBlock + emptyBlock; - break; - case 3: - signalStrengthText = filledBlock + filledBlock + filledBlock + emptyBlock + emptyBlock; - break; - case 4: - signalStrengthText = filledBlock + filledBlock + filledBlock + filledBlock + emptyBlock; - break; - case 5: - signalStrengthText = filledBlock + filledBlock + filledBlock + filledBlock + filledBlock; - break; - default: - signalStrengthText = "Invalid signal strength"; - } - - content += "

Signal Strength: [" + signalStrengthText + "]

"; + content += "

Signal Strength: " + String(WiFi.RSSI()) + " dBm

"; } // Close the block content += "
"; @@ -356,11 +385,16 @@ String processor(const String& var) { content += ""; content += ""; + content += " "; + content += ""; + content += " "; content += ""; content += ""; + + // Close the block + content += ""; + + content += ""; + content += ""; + return content; + } + return String(); +} + void onOTAStart() { // Log when OTA has started Serial.println("OTA update started!"); ESP32Can.CANStop(); - bms_status = 5; //Inform inverter that we are updating + bms_status = UPDATING; //Inform inverter that we are updating LEDcolor = BLUE; } void onOTAProgress(size_t current, size_t final) { - bms_status = 5; //Inform inverter that we are updating + bms_status = UPDATING; //Inform inverter that we are updating LEDcolor = BLUE; // Log every 1 second if (millis() - ota_progress_millis > 1000) { @@ -404,6 +536,6 @@ void onOTAEnd(bool success) { } else { Serial.println("There was an error during OTA update!"); } - bms_status = 5; //Inform inverter that we are updating + bms_status = UPDATING; //Inform inverter that we are updating LEDcolor = BLUE; } diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index eb99c06b..b948d351 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -33,6 +33,7 @@ extern const char* ssid; extern const char* password; extern const char* ssidAP; extern const char* passwordAP; +extern const char* versionNumber; /** * @brief Initialization function for the webserver. @@ -80,6 +81,15 @@ void init_ElegantOTA(); */ String processor(const String& var); +/** + * @brief Replaces placeholder with content section in web page + * + * @param[in] var + * + * @return String + */ +String settings_processor(const String& var); + /** * @brief Executes on OTA start *