Feature: Check for out of memory situations when sending json responses

Also shows a nice message in the frontend if an internal error occours
This commit is contained in:
Thomas Basler 2024-04-04 20:43:07 +02:00
parent 2e3125fe8d
commit 980e847ccb
26 changed files with 171 additions and 229 deletions

View File

@ -39,6 +39,7 @@ public:
static void writeConfig(JsonVariant& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!"); static void writeConfig(JsonVariant& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!");
static bool parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, JsonDocument& json_document); static bool parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, JsonDocument& json_document);
static bool sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line);
private: private:
AsyncWebServer _server; AsyncWebServer _server;

View File

@ -9,6 +9,7 @@ enum WebApiError {
GenericParseError, GenericParseError,
GenericValueMissing, GenericValueMissing,
GenericWriteFailed, GenericWriteFailed,
GenericInternalServerError,
DtuBase = 2000, DtuBase = 2000,
DtuSerialZero, DtuSerialZero,

View File

@ -4,6 +4,7 @@
*/ */
#include "WebApi.h" #include "WebApi.h"
#include "Configuration.h" #include "Configuration.h"
#include "MessageOutput.h"
#include "defaults.h" #include "defaults.h"
#include <AsyncJson.h> #include <AsyncJson.h>
@ -93,8 +94,7 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp
if (!request->hasParam("data", true)) { if (!request->hasParam("data", true)) {
retMsg["message"] = "No values found!"; retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound; retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return false; return false;
} }
@ -103,12 +103,31 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp
if (error) { if (error) {
retMsg["message"] = "Failed to parse data!"; retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError; retMsg["code"] = WebApiError::GenericParseError;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return false; return false;
} }
return true; return true;
} }
bool WebApiClass::sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line)
{
bool ret_val = true;
if (response->overflowed()) {
auto& root = response->getRoot();
root.clear();
root["message"] = String("500 Internal Server Error: ") + function + ", " + line;
root["code"] = WebApiError::GenericInternalServerError;
root["type"] = "danger";
response->setCode(500);
MessageOutput.printf("WebResponse failed: %s, %d\r\n", function, line);
ret_val = false;
}
response->setLength();
request->send(response);
return ret_val;
}
WebApiClass WebApi; WebApiClass WebApi;

View File

@ -63,16 +63,14 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
if (!(root.containsKey("delete"))) { if (!(root.containsKey("delete"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["delete"].as<bool>() == false) { if (root["delete"].as<bool>() == false) {
retMsg["message"] = "Not deleted anything!"; retMsg["message"] = "Not deleted anything!";
retMsg["code"] = WebApiError::ConfigNotDeleted; retMsg["code"] = WebApiError::ConfigNotDeleted;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -80,8 +78,7 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
retMsg["message"] = "Configuration resettet. Rebooting now..."; retMsg["message"] = "Configuration resettet. Rebooting now...";
retMsg["code"] = WebApiError::ConfigSuccess; retMsg["code"] = WebApiError::ConfigSuccess;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
Utils::removeAllFiles(); Utils::removeAllFiles();
Utils::restartDtu(); Utils::restartDtu();
@ -110,8 +107,7 @@ void WebApiConfigClass::onConfigListGet(AsyncWebServerRequest* request)
} }
file.close(); file.close();
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiConfigClass::onConfigUploadFinish(AsyncWebServerRequest* request) void WebApiConfigClass::onConfigUploadFinish(AsyncWebServerRequest* request)

View File

@ -86,8 +86,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
led["brightness"] = config.Led_Single[i].Brightness; led["brightness"] = config.Led_Single[i].Brightness;
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
@ -108,8 +107,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|| root.containsKey("display"))) { || root.containsKey("display"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -117,8 +115,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "Pin mapping must between 1 and " STR(DEV_MAX_MAPPING_NAME_STRLEN) " characters long!"; retMsg["message"] = "Pin mapping must between 1 and " STR(DEV_MAX_MAPPING_NAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::HardwarePinMappingLength; retMsg["code"] = WebApiError::HardwarePinMappingLength;
retMsg["param"]["max"] = DEV_MAX_MAPPING_NAME_STRLEN; retMsg["param"]["max"] = DEV_MAX_MAPPING_NAME_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -149,8 +146,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg); WebApi.writeConfig(retMsg);
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
if (performRestart) { if (performRestart) {
Utils::restartDtu(); Utils::restartDtu();

View File

@ -43,6 +43,5 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
root["fw_build_datetime"] = inv->DevInfo()->getFwBuildDateTimeStr(); root["fw_build_datetime"] = inv->DevInfo()->getFwBuildDateTimeStr();
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -73,8 +73,7 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request)
obj["freq_legal_max"] = definition.definition.Freq_Legal_Max; obj["freq_legal_max"] = definition.definition.Freq_Legal_Max;
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
@ -99,8 +98,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
&& root.containsKey("cmt_country"))) { && root.containsKey("cmt_country"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -110,40 +108,35 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
if (serial == 0) { if (serial == 0) {
retMsg["message"] = "Serial cannot be zero!"; retMsg["message"] = "Serial cannot be zero!";
retMsg["code"] = WebApiError::DtuSerialZero; retMsg["code"] = WebApiError::DtuSerialZero;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["pollinterval"].as<uint32_t>() == 0) { if (root["pollinterval"].as<uint32_t>() == 0) {
retMsg["message"] = "Poll interval must be greater zero!"; retMsg["message"] = "Poll interval must be greater zero!";
retMsg["code"] = WebApiError::DtuPollZero; retMsg["code"] = WebApiError::DtuPollZero;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["nrf_palevel"].as<uint8_t>() > 3) { if (root["nrf_palevel"].as<uint8_t>() > 3) {
retMsg["message"] = "Invalid power level setting!"; retMsg["message"] = "Invalid power level setting!";
retMsg["code"] = WebApiError::DtuInvalidPowerLevel; retMsg["code"] = WebApiError::DtuInvalidPowerLevel;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["cmt_palevel"].as<int8_t>() < -10 || root["cmt_palevel"].as<int8_t>() > 20) { if (root["cmt_palevel"].as<int8_t>() < -10 || root["cmt_palevel"].as<int8_t>() > 20) {
retMsg["message"] = "Invalid power level setting!"; retMsg["message"] = "Invalid power level setting!";
retMsg["code"] = WebApiError::DtuInvalidPowerLevel; retMsg["code"] = WebApiError::DtuInvalidPowerLevel;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["cmt_country"].as<uint8_t>() >= CountryModeId_t::CountryModeId_Max) { if (root["cmt_country"].as<uint8_t>() >= CountryModeId_t::CountryModeId_Max) {
retMsg["message"] = "Invalid country setting!"; retMsg["message"] = "Invalid country setting!";
retMsg["code"] = WebApiError::DtuInvalidCmtCountry; retMsg["code"] = WebApiError::DtuInvalidCmtCountry;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -156,8 +149,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::DtuInvalidCmtFrequency; retMsg["code"] = WebApiError::DtuInvalidCmtFrequency;
retMsg["param"]["min"] = FrequencyDefinition.Freq_Min; retMsg["param"]["min"] = FrequencyDefinition.Freq_Min;
retMsg["param"]["max"] = FrequencyDefinition.Freq_Max; retMsg["param"]["max"] = FrequencyDefinition.Freq_Max;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -172,8 +164,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg); WebApi.writeConfig(retMsg);
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
_applyDataTask.enable(); _applyDataTask.enable();
_applyDataTask.restart(); _applyDataTask.restart();

View File

@ -62,6 +62,5 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
} }
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -55,8 +55,7 @@ void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request)
} }
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request) void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request)
@ -83,6 +82,5 @@ void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request
copyArray(&data[0], data.size(), raw); copyArray(&data[0], data.size(), raw);
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -77,8 +77,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
} }
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
@ -99,8 +98,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
&& root.containsKey("name"))) { && root.containsKey("name"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -110,8 +108,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
if (serial == 0) { if (serial == 0) {
retMsg["message"] = "Serial must be a number > 0!"; retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::InverterSerialZero; retMsg["code"] = WebApiError::InverterSerialZero;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -119,8 +116,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
retMsg["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!"; retMsg["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::InverterNameLength; retMsg["code"] = WebApiError::InverterNameLength;
retMsg["param"]["max"] = INV_MAX_NAME_STRLEN; retMsg["param"]["max"] = INV_MAX_NAME_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -130,8 +126,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
retMsg["message"] = "Only " STR(INV_MAX_COUNT) " inverters are supported!"; retMsg["message"] = "Only " STR(INV_MAX_COUNT) " inverters are supported!";
retMsg["code"] = WebApiError::InverterCount; retMsg["code"] = WebApiError::InverterCount;
retMsg["param"]["max"] = INV_MAX_COUNT; retMsg["param"]["max"] = INV_MAX_COUNT;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -142,8 +137,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg, WebApiError::InverterAdded, "Inverter created!"); WebApi.writeConfig(retMsg, WebApiError::InverterAdded, "Inverter created!");
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
auto inv = Hoymiles.addInverter(inverter->Name, inverter->Serial); auto inv = Hoymiles.addInverter(inverter->Name, inverter->Serial);
@ -173,16 +167,14 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
if (!(root.containsKey("id") && root.containsKey("serial") && root.containsKey("name") && root.containsKey("channel"))) { if (!(root.containsKey("id") && root.containsKey("serial") && root.containsKey("name") && root.containsKey("channel"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) { if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) {
retMsg["message"] = "Invalid ID specified!"; retMsg["message"] = "Invalid ID specified!";
retMsg["code"] = WebApiError::InverterInvalidId; retMsg["code"] = WebApiError::InverterInvalidId;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -192,8 +184,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
if (serial == 0) { if (serial == 0) {
retMsg["message"] = "Serial must be a number > 0!"; retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::InverterSerialZero; retMsg["code"] = WebApiError::InverterSerialZero;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -201,8 +192,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
retMsg["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!"; retMsg["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::InverterNameLength; retMsg["code"] = WebApiError::InverterNameLength;
retMsg["param"]["max"] = INV_MAX_NAME_STRLEN; retMsg["param"]["max"] = INV_MAX_NAME_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -210,8 +200,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
if (channelArray.size() == 0 || channelArray.size() > INV_MAX_CHAN_COUNT) { if (channelArray.size() == 0 || channelArray.size() > INV_MAX_CHAN_COUNT) {
retMsg["message"] = "Invalid amount of max channel setting given!"; retMsg["message"] = "Invalid amount of max channel setting given!";
retMsg["code"] = WebApiError::InverterInvalidMaxChannel; retMsg["code"] = WebApiError::InverterInvalidMaxChannel;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -243,8 +232,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg, WebApiError::InverterChanged, "Inverter changed!"); WebApi.writeConfig(retMsg, WebApiError::InverterChanged, "Inverter changed!");
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(old_serial); std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(old_serial);
@ -293,16 +281,14 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
if (!(root.containsKey("id"))) { if (!(root.containsKey("id"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) { if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) {
retMsg["message"] = "Invalid ID specified!"; retMsg["message"] = "Invalid ID specified!";
retMsg["code"] = WebApiError::InverterInvalidId; retMsg["code"] = WebApiError::InverterInvalidId;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -315,8 +301,7 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg, WebApiError::InverterDeleted, "Inverter deleted!"); WebApi.writeConfig(retMsg, WebApiError::InverterDeleted, "Inverter deleted!");
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
MqttHandleHass.forceUpdate(); MqttHandleHass.forceUpdate();
} }
@ -338,8 +323,7 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request)
if (!(root.containsKey("order"))) { if (!(root.containsKey("order"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -357,6 +341,5 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg, WebApiError::InverterOrdered, "Inverter order saved!"); WebApi.writeConfig(retMsg, WebApiError::InverterOrdered, "Inverter order saved!");
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -47,8 +47,7 @@ void WebApiLimitClass::onLimitStatus(AsyncWebServerRequest* request)
root[serial]["limit_set_status"] = limitStatus; root[serial]["limit_set_status"] = limitStatus;
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
@ -70,8 +69,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
&& root.containsKey("limit_type"))) { && root.containsKey("limit_type"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -81,8 +79,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
if (serial == 0) { if (serial == 0) {
retMsg["message"] = "Serial must be a number > 0!"; retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::LimitSerialZero; retMsg["code"] = WebApiError::LimitSerialZero;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -90,8 +87,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
retMsg["message"] = "Limit must between 0 and " STR(MAX_INVERTER_LIMIT) "!"; retMsg["message"] = "Limit must between 0 and " STR(MAX_INVERTER_LIMIT) "!";
retMsg["code"] = WebApiError::LimitInvalidLimit; retMsg["code"] = WebApiError::LimitInvalidLimit;
retMsg["param"]["max"] = MAX_INVERTER_LIMIT; retMsg["param"]["max"] = MAX_INVERTER_LIMIT;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -102,8 +98,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
retMsg["message"] = "Invalid type specified!"; retMsg["message"] = "Invalid type specified!";
retMsg["code"] = WebApiError::LimitInvalidType; retMsg["code"] = WebApiError::LimitInvalidType;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -114,8 +109,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
if (inv == nullptr) { if (inv == nullptr) {
retMsg["message"] = "Invalid inverter specified!"; retMsg["message"] = "Invalid inverter specified!";
retMsg["code"] = WebApiError::LimitInvalidInverter; retMsg["code"] = WebApiError::LimitInvalidInverter;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -125,6 +119,5 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
retMsg["message"] = "Settings saved!"; retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess; retMsg["code"] = WebApiError::GenericSuccess;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -33,8 +33,7 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
if (!(root.containsKey("reboot"))) { if (!(root.containsKey("reboot"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -43,14 +42,12 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
retMsg["message"] = "Reboot triggered!"; retMsg["message"] = "Reboot triggered!";
retMsg["code"] = WebApiError::MaintenanceRebootTriggered; retMsg["code"] = WebApiError::MaintenanceRebootTriggered;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
Utils::restartDtu(); Utils::restartDtu();
} else { } else {
retMsg["message"] = "Reboot cancled!"; retMsg["message"] = "Reboot cancled!";
retMsg["code"] = WebApiError::MaintenanceRebootCancled; retMsg["code"] = WebApiError::MaintenanceRebootCancled;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
} }

View File

@ -50,8 +50,7 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
root["mqtt_hass_topic"] = config.Mqtt.Hass.Topic; root["mqtt_hass_topic"] = config.Mqtt.Hass.Topic;
root["mqtt_hass_individualpanels"] = config.Mqtt.Hass.IndividualPanels; root["mqtt_hass_individualpanels"] = config.Mqtt.Hass.IndividualPanels;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request) void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
@ -88,8 +87,7 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
root["mqtt_hass_topic"] = config.Mqtt.Hass.Topic; root["mqtt_hass_topic"] = config.Mqtt.Hass.Topic;
root["mqtt_hass_individualpanels"] = config.Mqtt.Hass.IndividualPanels; root["mqtt_hass_individualpanels"] = config.Mqtt.Hass.IndividualPanels;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
@ -130,8 +128,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
&& root.containsKey("mqtt_hass_individualpanels"))) { && root.containsKey("mqtt_hass_individualpanels"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -140,8 +137,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "MqTT Server must between 1 and " STR(MQTT_MAX_HOSTNAME_STRLEN) " characters long!"; retMsg["message"] = "MqTT Server must between 1 and " STR(MQTT_MAX_HOSTNAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::MqttHostnameLength; retMsg["code"] = WebApiError::MqttHostnameLength;
retMsg["param"]["max"] = MQTT_MAX_HOSTNAME_STRLEN; retMsg["param"]["max"] = MQTT_MAX_HOSTNAME_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -149,48 +145,42 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "Username must not be longer than " STR(MQTT_MAX_USERNAME_STRLEN) " characters!"; retMsg["message"] = "Username must not be longer than " STR(MQTT_MAX_USERNAME_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttUsernameLength; retMsg["code"] = WebApiError::MqttUsernameLength;
retMsg["param"]["max"] = MQTT_MAX_USERNAME_STRLEN; retMsg["param"]["max"] = MQTT_MAX_USERNAME_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["mqtt_password"].as<String>().length() > MQTT_MAX_PASSWORD_STRLEN) { if (root["mqtt_password"].as<String>().length() > MQTT_MAX_PASSWORD_STRLEN) {
retMsg["message"] = "Password must not be longer than " STR(MQTT_MAX_PASSWORD_STRLEN) " characters!"; retMsg["message"] = "Password must not be longer than " STR(MQTT_MAX_PASSWORD_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttPasswordLength; retMsg["code"] = WebApiError::MqttPasswordLength;
retMsg["param"]["max"] = MQTT_MAX_PASSWORD_STRLEN; retMsg["param"]["max"] = MQTT_MAX_PASSWORD_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["mqtt_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) { if (root["mqtt_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
retMsg["message"] = "Topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!"; retMsg["message"] = "Topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttTopicLength; retMsg["code"] = WebApiError::MqttTopicLength;
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN; retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["mqtt_topic"].as<String>().indexOf(' ') != -1) { if (root["mqtt_topic"].as<String>().indexOf(' ') != -1) {
retMsg["message"] = "Topic must not contain space characters!"; retMsg["message"] = "Topic must not contain space characters!";
retMsg["code"] = WebApiError::MqttTopicCharacter; retMsg["code"] = WebApiError::MqttTopicCharacter;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (!root["mqtt_topic"].as<String>().endsWith("/")) { if (!root["mqtt_topic"].as<String>().endsWith("/")) {
retMsg["message"] = "Topic must end with a slash (/)!"; retMsg["message"] = "Topic must end with a slash (/)!";
retMsg["code"] = WebApiError::MqttTopicTrailingSlash; retMsg["code"] = WebApiError::MqttTopicTrailingSlash;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["mqtt_port"].as<uint>() == 0 || root["mqtt_port"].as<uint>() > 65535) { if (root["mqtt_port"].as<uint>() == 0 || root["mqtt_port"].as<uint>() > 65535) {
retMsg["message"] = "Port must be a number between 1 and 65535!"; retMsg["message"] = "Port must be a number between 1 and 65535!";
retMsg["code"] = WebApiError::MqttPort; retMsg["code"] = WebApiError::MqttPort;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -200,8 +190,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "Certificates must not be longer than " STR(MQTT_MAX_CERT_STRLEN) " characters!"; retMsg["message"] = "Certificates must not be longer than " STR(MQTT_MAX_CERT_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttCertificateLength; retMsg["code"] = WebApiError::MqttCertificateLength;
retMsg["param"]["max"] = MQTT_MAX_CERT_STRLEN; retMsg["param"]["max"] = MQTT_MAX_CERT_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -209,16 +198,14 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "LWT topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!"; retMsg["message"] = "LWT topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttLwtTopicLength; retMsg["code"] = WebApiError::MqttLwtTopicLength;
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN; retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["mqtt_lwt_topic"].as<String>().indexOf(' ') != -1) { if (root["mqtt_lwt_topic"].as<String>().indexOf(' ') != -1) {
retMsg["message"] = "LWT topic must not contain space characters!"; retMsg["message"] = "LWT topic must not contain space characters!";
retMsg["code"] = WebApiError::MqttLwtTopicCharacter; retMsg["code"] = WebApiError::MqttLwtTopicCharacter;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -226,8 +213,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "LWT online value must not be longer than " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!"; retMsg["message"] = "LWT online value must not be longer than " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttLwtOnlineLength; retMsg["code"] = WebApiError::MqttLwtOnlineLength;
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN; retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -235,8 +221,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "LWT offline value must not be longer than " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!"; retMsg["message"] = "LWT offline value must not be longer than " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttLwtOfflineLength; retMsg["code"] = WebApiError::MqttLwtOfflineLength;
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN; retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -244,8 +229,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "LWT QoS must not be greater than " STR(2) "!"; retMsg["message"] = "LWT QoS must not be greater than " STR(2) "!";
retMsg["code"] = WebApiError::MqttLwtQos; retMsg["code"] = WebApiError::MqttLwtQos;
retMsg["param"]["max"] = 2; retMsg["param"]["max"] = 2;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -254,8 +238,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::MqttPublishInterval; retMsg["code"] = WebApiError::MqttPublishInterval;
retMsg["param"]["min"] = 5; retMsg["param"]["min"] = 5;
retMsg["param"]["max"] = 65535; retMsg["param"]["max"] = 65535;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -264,16 +247,14 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "Hass topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!"; retMsg["message"] = "Hass topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttHassTopicLength; retMsg["code"] = WebApiError::MqttHassTopicLength;
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN; retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["mqtt_hass_topic"].as<String>().indexOf(' ') != -1) { if (root["mqtt_hass_topic"].as<String>().indexOf(' ') != -1) {
retMsg["message"] = "Hass topic must not contain space characters!"; retMsg["message"] = "Hass topic must not contain space characters!";
retMsg["code"] = WebApiError::MqttHassTopicCharacter; retMsg["code"] = WebApiError::MqttHassTopicCharacter;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
} }
@ -306,8 +287,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg); WebApi.writeConfig(retMsg);
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
MqttSettings.performReconnect(); MqttSettings.performReconnect();
MqttHandleHass.forceUpdate(); MqttHandleHass.forceUpdate();

View File

@ -46,8 +46,7 @@ void WebApiNetworkClass::onNetworkStatus(AsyncWebServerRequest* request)
root["ap_mac"] = WiFi.softAPmacAddress(); root["ap_mac"] = WiFi.softAPmacAddress();
root["ap_stationnum"] = WiFi.softAPgetStationNum(); root["ap_stationnum"] = WiFi.softAPgetStationNum();
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request) void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request)
@ -72,8 +71,7 @@ void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request)
root["aptimeout"] = config.WiFi.ApTimeout; root["aptimeout"] = config.WiFi.ApTimeout;
root["mdnsenabled"] = config.Mdns.Enabled; root["mdnsenabled"] = config.Mdns.Enabled;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
@ -102,8 +100,7 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
&& root.containsKey("aptimeout"))) { && root.containsKey("aptimeout"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -111,68 +108,59 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
if (!ipaddress.fromString(root["ipaddress"].as<String>())) { if (!ipaddress.fromString(root["ipaddress"].as<String>())) {
retMsg["message"] = "IP address is invalid!"; retMsg["message"] = "IP address is invalid!";
retMsg["code"] = WebApiError::NetworkIpInvalid; retMsg["code"] = WebApiError::NetworkIpInvalid;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
IPAddress netmask; IPAddress netmask;
if (!netmask.fromString(root["netmask"].as<String>())) { if (!netmask.fromString(root["netmask"].as<String>())) {
retMsg["message"] = "Netmask is invalid!"; retMsg["message"] = "Netmask is invalid!";
retMsg["code"] = WebApiError::NetworkNetmaskInvalid; retMsg["code"] = WebApiError::NetworkNetmaskInvalid;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
IPAddress gateway; IPAddress gateway;
if (!gateway.fromString(root["gateway"].as<String>())) { if (!gateway.fromString(root["gateway"].as<String>())) {
retMsg["message"] = "Gateway is invalid!"; retMsg["message"] = "Gateway is invalid!";
retMsg["code"] = WebApiError::NetworkGatewayInvalid; retMsg["code"] = WebApiError::NetworkGatewayInvalid;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
IPAddress dns1; IPAddress dns1;
if (!dns1.fromString(root["dns1"].as<String>())) { if (!dns1.fromString(root["dns1"].as<String>())) {
retMsg["message"] = "DNS Server IP 1 is invalid!"; retMsg["message"] = "DNS Server IP 1 is invalid!";
retMsg["code"] = WebApiError::NetworkDns1Invalid; retMsg["code"] = WebApiError::NetworkDns1Invalid;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
IPAddress dns2; IPAddress dns2;
if (!dns2.fromString(root["dns2"].as<String>())) { if (!dns2.fromString(root["dns2"].as<String>())) {
retMsg["message"] = "DNS Server IP 2 is invalid!"; retMsg["message"] = "DNS Server IP 2 is invalid!";
retMsg["code"] = WebApiError::NetworkDns2Invalid; retMsg["code"] = WebApiError::NetworkDns2Invalid;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["hostname"].as<String>().length() == 0 || root["hostname"].as<String>().length() > WIFI_MAX_HOSTNAME_STRLEN) { if (root["hostname"].as<String>().length() == 0 || root["hostname"].as<String>().length() > WIFI_MAX_HOSTNAME_STRLEN) {
retMsg["message"] = "Hostname must between 1 and " STR(WIFI_MAX_HOSTNAME_STRLEN) " characters long!"; retMsg["message"] = "Hostname must between 1 and " STR(WIFI_MAX_HOSTNAME_STRLEN) " characters long!";
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (NetworkSettings.NetworkMode() == network_mode::WiFi) { if (NetworkSettings.NetworkMode() == network_mode::WiFi) {
if (root["ssid"].as<String>().length() == 0 || root["ssid"].as<String>().length() > WIFI_MAX_SSID_STRLEN) { if (root["ssid"].as<String>().length() == 0 || root["ssid"].as<String>().length() > WIFI_MAX_SSID_STRLEN) {
retMsg["message"] = "SSID must between 1 and " STR(WIFI_MAX_SSID_STRLEN) " characters long!"; retMsg["message"] = "SSID must between 1 and " STR(WIFI_MAX_SSID_STRLEN) " characters long!";
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
} }
if (root["password"].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN - 1) { if (root["password"].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN - 1) {
retMsg["message"] = "Password must not be longer than " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!"; retMsg["message"] = "Password must not be longer than " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!";
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
if (root["aptimeout"].as<uint>() > 99999) { if (root["aptimeout"].as<uint>() > 99999) {
retMsg["message"] = "ApTimeout must be a number between 0 and 99999!"; retMsg["message"] = "ApTimeout must be a number between 0 and 99999!";
retMsg["code"] = WebApiError::NetworkApTimeoutInvalid; retMsg["code"] = WebApiError::NetworkApTimeoutInvalid;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -210,8 +198,7 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg); WebApi.writeConfig(retMsg);
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
NetworkSettings.enableAdminMode(); NetworkSettings.enableAdminMode();
NetworkSettings.applyConfig(); NetworkSettings.applyConfig();

View File

@ -63,8 +63,7 @@ void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request)
root["sun_isSunsetAvailable"] = SunPosition.isSunsetAvailable(); root["sun_isSunsetAvailable"] = SunPosition.isSunsetAvailable();
root["sun_isDayPeriod"] = SunPosition.isDayPeriod(); root["sun_isDayPeriod"] = SunPosition.isDayPeriod();
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request) void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request)
@ -84,8 +83,7 @@ void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request)
root["latitude"] = config.Ntp.Latitude; root["latitude"] = config.Ntp.Latitude;
root["sunsettype"] = config.Ntp.SunsetType; root["sunsettype"] = config.Ntp.SunsetType;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
@ -109,8 +107,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
&& root.containsKey("sunsettype"))) { && root.containsKey("sunsettype"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -118,8 +115,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "NTP Server must between 1 and " STR(NTP_MAX_SERVER_STRLEN) " characters long!"; retMsg["message"] = "NTP Server must between 1 and " STR(NTP_MAX_SERVER_STRLEN) " characters long!";
retMsg["code"] = WebApiError::NtpServerLength; retMsg["code"] = WebApiError::NtpServerLength;
retMsg["param"]["max"] = NTP_MAX_SERVER_STRLEN; retMsg["param"]["max"] = NTP_MAX_SERVER_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -127,8 +123,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "Timezone must between 1 and " STR(NTP_MAX_TIMEZONE_STRLEN) " characters long!"; retMsg["message"] = "Timezone must between 1 and " STR(NTP_MAX_TIMEZONE_STRLEN) " characters long!";
retMsg["code"] = WebApiError::NtpTimezoneLength; retMsg["code"] = WebApiError::NtpTimezoneLength;
retMsg["param"]["max"] = NTP_MAX_TIMEZONE_STRLEN; retMsg["param"]["max"] = NTP_MAX_TIMEZONE_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -136,8 +131,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
retMsg["message"] = "Timezone description must between 1 and " STR(NTP_MAX_TIMEZONEDESCR_STRLEN) " characters long!"; retMsg["message"] = "Timezone description must between 1 and " STR(NTP_MAX_TIMEZONEDESCR_STRLEN) " characters long!";
retMsg["code"] = WebApiError::NtpTimezoneDescriptionLength; retMsg["code"] = WebApiError::NtpTimezoneDescriptionLength;
retMsg["param"]["max"] = NTP_MAX_TIMEZONEDESCR_STRLEN; retMsg["param"]["max"] = NTP_MAX_TIMEZONEDESCR_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -151,8 +145,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg); WebApi.writeConfig(retMsg);
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
NtpSettings.setServer(); NtpSettings.setServer();
NtpSettings.setTimezone(); NtpSettings.setTimezone();
@ -183,8 +176,7 @@ void WebApiNtpClass::onNtpTimeGet(AsyncWebServerRequest* request)
root["minute"] = timeinfo.tm_min; root["minute"] = timeinfo.tm_min;
root["second"] = timeinfo.tm_sec; root["second"] = timeinfo.tm_sec;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
@ -209,8 +201,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
&& root.containsKey("second"))) { && root.containsKey("second"))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -219,8 +210,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::NtpYearInvalid; retMsg["code"] = WebApiError::NtpYearInvalid;
retMsg["param"]["min"] = 2022; retMsg["param"]["min"] = 2022;
retMsg["param"]["max"] = 2100; retMsg["param"]["max"] = 2100;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -229,8 +219,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::NtpMonthInvalid; retMsg["code"] = WebApiError::NtpMonthInvalid;
retMsg["param"]["min"] = 1; retMsg["param"]["min"] = 1;
retMsg["param"]["max"] = 12; retMsg["param"]["max"] = 12;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -239,8 +228,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::NtpDayInvalid; retMsg["code"] = WebApiError::NtpDayInvalid;
retMsg["param"]["min"] = 1; retMsg["param"]["min"] = 1;
retMsg["param"]["max"] = 31; retMsg["param"]["max"] = 31;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -249,8 +237,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::NtpHourInvalid; retMsg["code"] = WebApiError::NtpHourInvalid;
retMsg["param"]["min"] = 0; retMsg["param"]["min"] = 0;
retMsg["param"]["max"] = 23; retMsg["param"]["max"] = 23;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -259,8 +246,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::NtpMinuteInvalid; retMsg["code"] = WebApiError::NtpMinuteInvalid;
retMsg["param"]["min"] = 0; retMsg["param"]["min"] = 0;
retMsg["param"]["max"] = 59; retMsg["param"]["max"] = 59;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -269,8 +255,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
retMsg["code"] = WebApiError::NtpSecondInvalid; retMsg["code"] = WebApiError::NtpSecondInvalid;
retMsg["param"]["min"] = 0; retMsg["param"]["min"] = 0;
retMsg["param"]["max"] = 59; retMsg["param"]["max"] = 59;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -291,6 +276,5 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
retMsg["message"] = "Time updated!"; retMsg["message"] = "Time updated!";
retMsg["code"] = WebApiError::NtpTimeUpdated; retMsg["code"] = WebApiError::NtpTimeUpdated;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -40,8 +40,7 @@ void WebApiPowerClass::onPowerStatus(AsyncWebServerRequest* request)
root[inv->serialString()]["power_set_status"] = limitStatus; root[inv->serialString()]["power_set_status"] = limitStatus;
} }
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
@ -63,8 +62,7 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
|| root.containsKey("restart")))) { || root.containsKey("restart")))) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -74,8 +72,7 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
if (serial == 0) { if (serial == 0) {
retMsg["message"] = "Serial must be a number > 0!"; retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::PowerSerialZero; retMsg["code"] = WebApiError::PowerSerialZero;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -83,8 +80,7 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
if (inv == nullptr) { if (inv == nullptr) {
retMsg["message"] = "Invalid inverter specified!"; retMsg["message"] = "Invalid inverter specified!";
retMsg["code"] = WebApiError::PowerInvalidInverter; retMsg["code"] = WebApiError::PowerInvalidInverter;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -101,6 +97,5 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
retMsg["message"] = "Settings saved!"; retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess; retMsg["code"] = WebApiError::GenericSuccess;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -31,8 +31,7 @@ void WebApiSecurityClass::onSecurityGet(AsyncWebServerRequest* request)
root["password"] = config.Security.Password; root["password"] = config.Security.Password;
root["allow_readonly"] = config.Security.AllowReadonly; root["allow_readonly"] = config.Security.AllowReadonly;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
@ -53,8 +52,7 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
&& root.containsKey("allow_readonly")) { && root.containsKey("allow_readonly")) {
retMsg["message"] = "Values are missing!"; retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing; retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -62,8 +60,7 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
retMsg["message"] = "Password must between 8 and " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!"; retMsg["message"] = "Password must between 8 and " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!";
retMsg["code"] = WebApiError::SecurityPasswordLength; retMsg["code"] = WebApiError::SecurityPasswordLength;
retMsg["param"]["max"] = WIFI_MAX_PASSWORD_STRLEN; retMsg["param"]["max"] = WIFI_MAX_PASSWORD_STRLEN;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
return; return;
} }
@ -73,8 +70,7 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg); WebApi.writeConfig(retMsg);
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }
void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request) void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request)
@ -89,6 +85,5 @@ void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request)
retMsg["message"] = "Authentication successful!"; retMsg["message"] = "Authentication successful!";
retMsg["code"] = WebApiError::SecurityAuthSuccess; retMsg["code"] = WebApiError::SecurityAuthSuccess;
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -76,6 +76,5 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
root["cmt_configured"] = PinMapping.isValidCmt2300Config(); root["cmt_configured"] = PinMapping.isValidCmt2300Config();
root["cmt_connected"] = Hoymiles.getRadioCmt()->isConnected(); root["cmt_connected"] = Hoymiles.getRadioCmt()->isConnected();
response->setLength(); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
request->send(response);
} }

View File

@ -255,12 +255,7 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request)
generateCommonJsonResponse(root); generateCommonJsonResponse(root);
if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
return;
}
response->setLength();
request->send(response);
} catch (const std::bad_alloc& bad_alloc) { } catch (const std::bad_alloc& bad_alloc) {
MessageOutput.printf("Call to /api/livedata/status temporarely out of resources. Reason: \"%s\".\r\n", bad_alloc.what()); MessageOutput.printf("Call to /api/livedata/status temporarely out of resources. Reason: \"%s\".\r\n", bad_alloc.what());

View File

@ -32,6 +32,9 @@
"Release": "Loslassen zum Aktualisieren", "Release": "Loslassen zum Aktualisieren",
"Close": "Schließen" "Close": "Schließen"
}, },
"Error": {
"Oops": "Oops!"
},
"localeswitcher": { "localeswitcher": {
"Dark": "Dunkel", "Dark": "Dunkel",
"Light": "Hell", "Light": "Hell",

View File

@ -32,6 +32,9 @@
"Release": "Release to refresh", "Release": "Release to refresh",
"Close": "Close" "Close": "Close"
}, },
"Error": {
"Oops": "Oops!"
},
"localeswitcher": { "localeswitcher": {
"Dark": "Dark", "Dark": "Dark",
"Light": "Light", "Light": "Light",

View File

@ -32,6 +32,9 @@
"Release": "Release to refresh", "Release": "Release to refresh",
"Close": "Fermer" "Close": "Fermer"
}, },
"Error": {
"Oops": "Oops!"
},
"localeswitcher": { "localeswitcher": {
"Dark": "Sombre", "Dark": "Sombre",
"Light": "Clair", "Light": "Clair",

View File

@ -3,6 +3,7 @@ import ConfigAdminView from '@/views/ConfigAdminView.vue';
import ConsoleInfoView from '@/views/ConsoleInfoView.vue'; import ConsoleInfoView from '@/views/ConsoleInfoView.vue';
import DeviceAdminView from '@/views/DeviceAdminView.vue' import DeviceAdminView from '@/views/DeviceAdminView.vue'
import DtuAdminView from '@/views/DtuAdminView.vue'; import DtuAdminView from '@/views/DtuAdminView.vue';
import ErrorView from '@/views/ErrorView.vue';
import FirmwareUpgradeView from '@/views/FirmwareUpgradeView.vue'; import FirmwareUpgradeView from '@/views/FirmwareUpgradeView.vue';
import HomeView from '@/views/HomeView.vue'; import HomeView from '@/views/HomeView.vue';
import InverterAdminView from '@/views/InverterAdminView.vue'; import InverterAdminView from '@/views/InverterAdminView.vue';
@ -32,6 +33,11 @@ const router = createRouter({
name: 'Login', name: 'Login',
component: LoginView component: LoginView
}, },
{
path: '/error?status=:status&message=:message',
name: 'Error',
component: ErrorView
},
{ {
path: '/about', path: '/about',
name: 'About', name: 'About',

View File

@ -77,6 +77,7 @@ export function handleResponse(response: Response, emitter: Emitter<Record<Event
} }
const error = { message: (data && data.message) || response.statusText, status: response.status || 0 }; const error = { message: (data && data.message) || response.statusText, status: response.status || 0 };
router.push({ name: "Error", params: error });
return Promise.reject(error); return Promise.reject(error);
} }

View File

@ -0,0 +1,18 @@
<template>
<BasePage :title="$t('Error.Oops')">
<div class="alert alert-danger" role="alert">
<h2>{{ $route.params.message }}</h2>
</div>
</BasePage>
</template>
<script lang="ts">
import BasePage from '@/components/BasePage.vue';
import { defineComponent } from 'vue';
export default defineComponent({
components: {
BasePage,
},
});
</script>

View File

@ -191,7 +191,7 @@ export default defineComponent({
const remoteHostUrl = "/api/system/status"; const remoteHostUrl = "/api/system/status";
// Use a simple fetch request to check if the remote host is reachable // Use a simple fetch request to check if the remote host is reachable
fetch(remoteHostUrl, { method: 'HEAD' }) fetch(remoteHostUrl, { method: 'GET' })
.then(response => { .then(response => {
// Check if the response status is OK (200-299 range) // Check if the response status is OK (200-299 range)
if (response.ok) { if (response.ok) {