From 694041895591da86647903abf67b4680095f7075 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Mon, 1 Apr 2024 00:00:36 +0200 Subject: [PATCH 01/17] Move source files for TimeoutHelper to correct directories --- lib/TimeoutHelper/README.md | 0 lib/TimeoutHelper/library.json | 13 +++++++++++++ lib/TimeoutHelper/{ => src}/TimeoutHelper.cpp | 0 lib/TimeoutHelper/{ => src}/TimeoutHelper.h | 0 4 files changed, 13 insertions(+) create mode 100644 lib/TimeoutHelper/README.md create mode 100644 lib/TimeoutHelper/library.json rename lib/TimeoutHelper/{ => src}/TimeoutHelper.cpp (100%) rename lib/TimeoutHelper/{ => src}/TimeoutHelper.h (100%) diff --git a/lib/TimeoutHelper/README.md b/lib/TimeoutHelper/README.md new file mode 100644 index 00000000..e69de29b diff --git a/lib/TimeoutHelper/library.json b/lib/TimeoutHelper/library.json new file mode 100644 index 00000000..0e0472ba --- /dev/null +++ b/lib/TimeoutHelper/library.json @@ -0,0 +1,13 @@ +{ + "name": "TimeoutHelper", + "keywords": "timeout", + "description": "An Arduino for ESP32 timeout helper", + "authors": { + "name": "Thomas Basler" + }, + "version": "0.0.1", + "frameworks": "arduino", + "platforms": [ + "espressif32" + ] +} diff --git a/lib/TimeoutHelper/TimeoutHelper.cpp b/lib/TimeoutHelper/src/TimeoutHelper.cpp similarity index 100% rename from lib/TimeoutHelper/TimeoutHelper.cpp rename to lib/TimeoutHelper/src/TimeoutHelper.cpp diff --git a/lib/TimeoutHelper/TimeoutHelper.h b/lib/TimeoutHelper/src/TimeoutHelper.h similarity index 100% rename from lib/TimeoutHelper/TimeoutHelper.h rename to lib/TimeoutHelper/src/TimeoutHelper.h From 58efd9e9543e475863a3cebdc85fcd9a95fefb07 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Mon, 1 Apr 2024 00:03:04 +0200 Subject: [PATCH 02/17] Move source files for ThreadSafeQueue to correct directories --- lib/ThreadSafeQueue/README.md | 0 lib/ThreadSafeQueue/library.json | 13 +++++++++++++ lib/ThreadSafeQueue/{ => src}/ThreadSafeQueue.h | 0 3 files changed, 13 insertions(+) create mode 100644 lib/ThreadSafeQueue/README.md create mode 100644 lib/ThreadSafeQueue/library.json rename lib/ThreadSafeQueue/{ => src}/ThreadSafeQueue.h (100%) diff --git a/lib/ThreadSafeQueue/README.md b/lib/ThreadSafeQueue/README.md new file mode 100644 index 00000000..e69de29b diff --git a/lib/ThreadSafeQueue/library.json b/lib/ThreadSafeQueue/library.json new file mode 100644 index 00000000..768cb8b2 --- /dev/null +++ b/lib/ThreadSafeQueue/library.json @@ -0,0 +1,13 @@ +{ + "name": "ThreadSafeQueue", + "keywords": "queue, threadsafe", + "description": "An Arduino for ESP32 thread safe queue implementation", + "authors": { + "name": "Thomas Basler" + }, + "version": "0.0.1", + "frameworks": "arduino", + "platforms": [ + "espressif32" + ] +} diff --git a/lib/ThreadSafeQueue/ThreadSafeQueue.h b/lib/ThreadSafeQueue/src/ThreadSafeQueue.h similarity index 100% rename from lib/ThreadSafeQueue/ThreadSafeQueue.h rename to lib/ThreadSafeQueue/src/ThreadSafeQueue.h From 8add226a7c79760c2ef8df0bdca617e676be1866 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Mon, 1 Apr 2024 13:52:09 +0200 Subject: [PATCH 03/17] Save flash: Move WebApi json parsing to separate method to prevent a lot of redundant code --- include/WebApi.h | 3 + src/WebApi.cpp | 34 ++++++++++ src/WebApi_config.cpp | 31 +--------- src/WebApi_device.cpp | 31 +--------- src/WebApi_dtu.cpp | 31 +--------- src/WebApi_inverter.cpp | 124 ++++--------------------------------- src/WebApi_limit.cpp | 31 +--------- src/WebApi_maintenance.cpp | 31 +--------- src/WebApi_mqtt.cpp | 31 +--------- src/WebApi_network.cpp | 31 +--------- src/WebApi_ntp.cpp | 62 ++----------------- src/WebApi_power.cpp | 31 +--------- src/WebApi_security.cpp | 31 +--------- 13 files changed, 82 insertions(+), 420 deletions(-) diff --git a/include/WebApi.h b/include/WebApi.h index 28ae7d33..5e5af527 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -22,6 +22,7 @@ #include "WebApi_webapp.h" #include "WebApi_ws_console.h" #include "WebApi_ws_live.h" +#include #include #include @@ -37,6 +38,8 @@ public: static void writeConfig(JsonVariant& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!"); + static bool parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, DynamicJsonDocument& json_document, size_t max_document_size = 1024); + private: AsyncWebServer _server; diff --git a/src/WebApi.cpp b/src/WebApi.cpp index 40809927..10f3e28d 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -85,4 +85,38 @@ void WebApiClass::writeConfig(JsonVariant& retMsg, const WebApiError code, const } } +bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, DynamicJsonDocument& json_document, size_t max_document_size) +{ + auto& retMsg = response->getRoot(); + retMsg["type"] = "warning"; + + if (!request->hasParam("data", true)) { + retMsg["message"] = "No values found!"; + retMsg["code"] = WebApiError::GenericNoValueFound; + response->setLength(); + request->send(response); + return false; + } + + const String json = request->getParam("data", true)->value(); + if (json.length() > max_document_size) { + retMsg["message"] = "Data too large!"; + retMsg["code"] = WebApiError::GenericDataTooLarge; + response->setLength(); + request->send(response); + return false; + } + + const DeserializationError error = deserializeJson(json_document, json); + if (error) { + retMsg["message"] = "Failed to parse data!"; + retMsg["code"] = WebApiError::GenericParseError; + response->setLength(); + request->send(response); + return false; + } + + return true; +} + WebApiClass WebApi; diff --git a/src/WebApi_config.cpp b/src/WebApi_config.cpp index 29f35319..f76a2e0a 100644 --- a/src/WebApi_config.cpp +++ b/src/WebApi_config.cpp @@ -53,38 +53,13 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("delete"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; diff --git a/src/WebApi_device.cpp b/src/WebApi_device.cpp index 2042f7da..1cc14220 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -97,38 +97,13 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > MQTT_JSON_DOC_SIZE) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(MQTT_JSON_DOC_SIZE); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root, MQTT_JSON_DOC_SIZE)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("curPin") || root.containsKey("display"))) { retMsg["message"] = "Values are missing!"; diff --git a/src/WebApi_dtu.cpp b/src/WebApi_dtu.cpp index 817e71b2..c6678b0a 100644 --- a/src/WebApi_dtu.cpp +++ b/src/WebApi_dtu.cpp @@ -84,38 +84,13 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("serial") && root.containsKey("pollinterval") && root.containsKey("nrf_palevel") diff --git a/src/WebApi_inverter.cpp b/src/WebApi_inverter.cpp index 5f5e4101..eb48c8ef 100644 --- a/src/WebApi_inverter.cpp +++ b/src/WebApi_inverter.cpp @@ -88,38 +88,13 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("serial") && root.containsKey("name"))) { retMsg["message"] = "Values are missing!"; @@ -188,38 +163,13 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("id") && root.containsKey("serial") && root.containsKey("name") && root.containsKey("channel"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; @@ -333,38 +283,13 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("id"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; @@ -403,38 +328,13 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("order"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; diff --git a/src/WebApi_limit.cpp b/src/WebApi_limit.cpp index b5b9e172..89058926 100644 --- a/src/WebApi_limit.cpp +++ b/src/WebApi_limit.cpp @@ -58,38 +58,13 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("serial") && root.containsKey("limit_value") && root.containsKey("limit_type"))) { diff --git a/src/WebApi_maintenance.cpp b/src/WebApi_maintenance.cpp index ba257efa..538f087a 100644 --- a/src/WebApi_maintenance.cpp +++ b/src/WebApi_maintenance.cpp @@ -23,38 +23,13 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > MQTT_JSON_DOC_SIZE) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(MQTT_JSON_DOC_SIZE); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root, MQTT_JSON_DOC_SIZE)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("reboot"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; diff --git a/src/WebApi_mqtt.cpp b/src/WebApi_mqtt.cpp index 29459a5b..78fed204 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -99,38 +99,13 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > MQTT_JSON_DOC_SIZE) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(MQTT_JSON_DOC_SIZE); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root, MQTT_JSON_DOC_SIZE)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("mqtt_enabled") && root.containsKey("mqtt_hostname") && root.containsKey("mqtt_port") diff --git a/src/WebApi_network.cpp b/src/WebApi_network.cpp index 12f637ad..b7fbbe51 100644 --- a/src/WebApi_network.cpp +++ b/src/WebApi_network.cpp @@ -83,38 +83,13 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("ssid") && root.containsKey("password") && root.containsKey("hostname") diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 02bbfb10..343d94b5 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -95,38 +95,13 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone") && root.containsKey("longitude") @@ -219,38 +194,13 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("year") && root.containsKey("month") && root.containsKey("day") diff --git a/src/WebApi_power.cpp b/src/WebApi_power.cpp index 08fe9c05..2f921d74 100644 --- a/src/WebApi_power.cpp +++ b/src/WebApi_power.cpp @@ -51,38 +51,13 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!(root.containsKey("serial") && (root.containsKey("power") || root.containsKey("restart")))) { diff --git a/src/WebApi_security.cpp b/src/WebApi_security.cpp index b95ebb29..05f829c5 100644 --- a/src/WebApi_security.cpp +++ b/src/WebApi_security.cpp @@ -42,38 +42,13 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - auto& retMsg = response->getRoot(); - retMsg["type"] = "warning"; - - if (!request->hasParam("data", true)) { - retMsg["message"] = "No values found!"; - retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); - return; - } - - const String json = request->getParam("data", true)->value(); - - if (json.length() > 1024) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return; - } - DynamicJsonDocument root(1024); - const DeserializationError error = deserializeJson(root, json); - - if (error) { - retMsg["message"] = "Failed to parse data!"; - retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + if (!WebApi.parseRequestData(request, response, root)) { return; } + auto& retMsg = response->getRoot(); + if (!root.containsKey("password") && root.containsKey("allow_readonly")) { retMsg["message"] = "Values are missing!"; From 718690030e543f99628efdd64b424822ae2c169a Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Mon, 1 Apr 2024 13:52:59 +0200 Subject: [PATCH 04/17] Fix include for TimeoutHelper --- lib/Hoymiles/src/HoymilesRadio.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Hoymiles/src/HoymilesRadio.h b/lib/Hoymiles/src/HoymilesRadio.h index 33b8c613..cb2a947c 100644 --- a/lib/Hoymiles/src/HoymilesRadio.h +++ b/lib/Hoymiles/src/HoymilesRadio.h @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include "TimeoutHelper.h" #include "commands/CommandAbstract.h" #include "types.h" -#include #include +#include +#include class HoymilesRadio { public: @@ -43,4 +43,4 @@ protected: bool _busyFlag = false; TimeoutHelper _rxTimeout; -}; \ No newline at end of file +}; From d2d775d687b1b5cd4898931b48de9b80c6ef57aa Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Tue, 2 Apr 2024 19:58:42 +0200 Subject: [PATCH 05/17] Update espressif32 from 6.5.0 to 6.6.0 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 108c12be..12938d3e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,7 +19,7 @@ extra_configs = custom_ci_action = generic,generic_esp32,generic_esp32s3,generic_esp32s3_usb framework = arduino -platform = espressif32@6.5.0 +platform = espressif32@6.6.0 build_flags = -DPIOENV=\"$PIOENV\" From b55ca53d1d01ab381b7207e766bcdde1e3df22fa Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Wed, 3 Apr 2024 18:35:27 +0200 Subject: [PATCH 06/17] Fix: Setting DTU options was only possible once without reboot Fix #1884 --- src/WebApi_dtu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WebApi_dtu.cpp b/src/WebApi_dtu.cpp index c6678b0a..bbcd909f 100644 --- a/src/WebApi_dtu.cpp +++ b/src/WebApi_dtu.cpp @@ -176,4 +176,5 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) request->send(response); _applyDataTask.enable(); + _applyDataTask.restart(); } From aa10c2c5e1a686fc5c487d776d230cea1b88d22b Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Wed, 3 Apr 2024 19:12:08 +0200 Subject: [PATCH 07/17] Fix: Too small event_queue_size in AsyncTCP lead to wdt reset Fix #1705 --- patches/async_tcp/event_queue_size.patch | 26 ++++++++++++++++++++++++ platformio.ini | 3 ++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 patches/async_tcp/event_queue_size.patch diff --git a/patches/async_tcp/event_queue_size.patch b/patches/async_tcp/event_queue_size.patch new file mode 100644 index 00000000..1280d46a --- /dev/null +++ b/patches/async_tcp/event_queue_size.patch @@ -0,0 +1,26 @@ +diff --color -ruN a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp +--- a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp ++++ b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp +@@ -97,7 +97,7 @@ + + static inline bool _init_async_event_queue(){ + if(!_async_queue){ +- _async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *)); ++ _async_queue = xQueueCreate(CONFIG_ASYNC_TCP_EVENT_QUEUE_SIZE, sizeof(lwip_event_packet_t *)); + if(!_async_queue){ + return false; + } +diff --color -ruN a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h +--- a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h ++++ b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h +@@ -53,6 +53,10 @@ + #define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2 + #endif + ++#ifndef CONFIG_ASYNC_TCP_EVENT_QUEUE_SIZE ++#define CONFIG_ASYNC_TCP_EVENT_QUEUE_SIZE 32 ++#endif ++ + class AsyncClient; + + #define ASYNC_MAX_ACK_TIME 5000 diff --git a/platformio.ini b/platformio.ini index 12938d3e..1f072bfa 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,6 +25,7 @@ build_flags = -DPIOENV=\"$PIOENV\" -D_TASK_STD_FUNCTION=1 -D_TASK_THREAD_SAFE=1 + -DCONFIG_ASYNC_TCP_EVENT_QUEUE_SIZE=128 -Wall -Wextra -Wunused -Wmisleading-indentation -Wduplicated-cond -Wlogical-op -Wnull-dereference ; Have to remove -Werror because of ; https://github.com/espressif/arduino-esp32/issues/9044 and @@ -59,7 +60,7 @@ board_build.embed_files = webapp_dist/js/app.js.gz webapp_dist/site.webmanifest -custom_patches = +custom_patches = async_tcp monitor_filters = esp32_exception_decoder, time, log2file, colorize monitor_speed = 115200 From e7a9c96b724f29f4dad91beb8bb8027620e8c44d Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Wed, 3 Apr 2024 23:11:30 +0200 Subject: [PATCH 08/17] Upgrade ESP Async WebServer from 2.8.1 to 2.9.0 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 1f072bfa..06e663c2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -37,7 +37,7 @@ build_unflags = -std=gnu++11 lib_deps = - mathieucarbou/ESP Async WebServer @ 2.8.1 + mathieucarbou/ESP Async WebServer @ 2.9.0 bblanchon/ArduinoJson @ ^6.21.5 https://github.com/bertmelis/espMqttClient.git#v1.6.0 nrf24/RF24 @ ^1.4.8 From 2e3125fe8d6a3f3ff224aa3aaa1d15040b7135b3 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Tue, 2 Apr 2024 23:23:12 +0200 Subject: [PATCH 09/17] Feature: Migrated ArduinoJson 6 to 7 --- include/Configuration.h | 2 -- include/MqttHandleHass.h | 6 ++-- include/Utils.h | 2 +- include/WebApi.h | 2 +- include/WebApi_errors.h | 2 +- include/WebApi_mqtt.h | 2 -- platformio.ini | 2 +- src/Configuration.cpp | 66 +++++++++++++++++++------------------- src/MqttHandleHass.cpp | 62 +++++++++++++++++++---------------- src/PinMapping.cpp | 6 ++-- src/Utils.cpp | 4 +-- src/WebApi.cpp | 10 +----- src/WebApi_config.cpp | 6 ++-- src/WebApi_device.cpp | 26 +++++++-------- src/WebApi_dtu.cpp | 6 ++-- src/WebApi_eventlog.cpp | 6 ++-- src/WebApi_gridprofile.cpp | 14 ++++---- src/WebApi_inverter.cpp | 18 +++++------ src/WebApi_limit.cpp | 2 +- src/WebApi_maintenance.cpp | 6 ++-- src/WebApi_mqtt.cpp | 10 +++--- src/WebApi_network.cpp | 2 +- src/WebApi_ntp.cpp | 4 +-- src/WebApi_power.cpp | 2 +- src/WebApi_security.cpp | 2 +- src/WebApi_ws_live.cpp | 31 ++++++++++-------- 26 files changed, 149 insertions(+), 152 deletions(-) diff --git a/include/Configuration.h b/include/Configuration.h index bb0e478f..e13b558a 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -30,8 +30,6 @@ #define DEV_MAX_MAPPING_NAME_STRLEN 63 -#define JSON_BUFFER_SIZE 12288 - struct CHANNEL_CONFIG_T { uint16_t MaxChannelPower; char Name[CHAN_MAX_NAME_STRLEN]; diff --git a/include/MqttHandleHass.h b/include/MqttHandleHass.h index feb86743..a76cb0c7 100644 --- a/include/MqttHandleHass.h +++ b/include/MqttHandleHass.h @@ -66,10 +66,10 @@ private: void publishInverterNumber(std::shared_ptr inv, const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, const int16_t min = 1, const int16_t max = 100); void publishInverterBinarySensor(std::shared_ptr inv, const char* caption, const char* subTopic, const char* payload_on, const char* payload_off); - static void createInverterInfo(DynamicJsonDocument& doc, std::shared_ptr inv); - static void createDtuInfo(DynamicJsonDocument& doc); + static void createInverterInfo(JsonDocument& doc, std::shared_ptr inv); + static void createDtuInfo(JsonDocument& doc); - static void createDeviceInfo(DynamicJsonDocument& doc, const String& name, const String& identifiers, const String& configuration_url, const String& manufacturer, const String& model, const String& sw_version, const String& via_device = ""); + static void createDeviceInfo(JsonDocument& doc, const String& name, const String& identifiers, const String& configuration_url, const String& manufacturer, const String& model, const String& sw_version, const String& via_device = ""); static String getDtuUniqueId(); static String getDtuUrl(); diff --git a/include/Utils.h b/include/Utils.h index fddc2ab9..f81e7318 100644 --- a/include/Utils.h +++ b/include/Utils.h @@ -10,6 +10,6 @@ public: static uint64_t generateDtuSerial(); static int getTimezoneOffset(); static void restartDtu(); - static bool checkJsonAlloc(const DynamicJsonDocument& doc, const char* function, const uint16_t line); + static bool checkJsonAlloc(const JsonDocument& doc, const char* function, const uint16_t line); static void removeAllFiles(); }; diff --git a/include/WebApi.h b/include/WebApi.h index 5e5af527..b4c49983 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -38,7 +38,7 @@ public: static void writeConfig(JsonVariant& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!"); - static bool parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, DynamicJsonDocument& json_document, size_t max_document_size = 1024); + static bool parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, JsonDocument& json_document); private: AsyncWebServer _server; diff --git a/include/WebApi_errors.h b/include/WebApi_errors.h index efb890c5..675419d7 100644 --- a/include/WebApi_errors.h +++ b/include/WebApi_errors.h @@ -5,7 +5,7 @@ enum WebApiError { GenericBase = 1000, GenericSuccess, GenericNoValueFound, - GenericDataTooLarge, + GenericDataTooLarge, // not used anymore GenericParseError, GenericValueMissing, GenericWriteFailed, diff --git a/include/WebApi_mqtt.h b/include/WebApi_mqtt.h index b259752b..6e428249 100644 --- a/include/WebApi_mqtt.h +++ b/include/WebApi_mqtt.h @@ -4,8 +4,6 @@ #include #include -#define MQTT_JSON_DOC_SIZE 10240 - class WebApiMqttClass { public: void init(AsyncWebServer& server, Scheduler& scheduler); diff --git a/platformio.ini b/platformio.ini index 06e663c2..2eef6f07 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,7 +38,7 @@ build_unflags = lib_deps = mathieucarbou/ESP Async WebServer @ 2.9.0 - bblanchon/ArduinoJson @ ^6.21.5 + bblanchon/ArduinoJson @ ^7.0.4 https://github.com/bertmelis/espMqttClient.git#v1.6.0 nrf24/RF24 @ ^1.4.8 olikraus/U8g2 @ ^2.35.15 diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 3b189187..8e803074 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -25,17 +25,13 @@ bool ConfigurationClass::write() } config.Cfg.SaveCount++; - DynamicJsonDocument doc(JSON_BUFFER_SIZE); + JsonDocument doc; - if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) { - return false; - } - - JsonObject cfg = doc.createNestedObject("cfg"); + JsonObject cfg = doc["cfg"].to(); cfg["version"] = config.Cfg.Version; cfg["save_count"] = config.Cfg.SaveCount; - JsonObject wifi = doc.createNestedObject("wifi"); + JsonObject wifi = doc["wifi"].to(); wifi["ssid"] = config.WiFi.Ssid; wifi["password"] = config.WiFi.Password; wifi["ip"] = IPAddress(config.WiFi.Ip).toString(); @@ -47,10 +43,10 @@ bool ConfigurationClass::write() wifi["hostname"] = config.WiFi.Hostname; wifi["aptimeout"] = config.WiFi.ApTimeout; - JsonObject mdns = doc.createNestedObject("mdns"); + JsonObject mdns = doc["mdns"].to(); mdns["enabled"] = config.Mdns.Enabled; - JsonObject ntp = doc.createNestedObject("ntp"); + JsonObject ntp = doc["ntp"].to(); ntp["server"] = config.Ntp.Server; ntp["timezone"] = config.Ntp.Timezone; ntp["timezone_descr"] = config.Ntp.TimezoneDescr; @@ -58,7 +54,7 @@ bool ConfigurationClass::write() ntp["longitude"] = config.Ntp.Longitude; ntp["sunsettype"] = config.Ntp.SunsetType; - JsonObject mqtt = doc.createNestedObject("mqtt"); + JsonObject mqtt = doc["mqtt"].to(); mqtt["enabled"] = config.Mqtt.Enabled; mqtt["hostname"] = config.Mqtt.Hostname; mqtt["port"] = config.Mqtt.Port; @@ -69,27 +65,27 @@ bool ConfigurationClass::write() mqtt["publish_interval"] = config.Mqtt.PublishInterval; mqtt["clean_session"] = config.Mqtt.CleanSession; - JsonObject mqtt_lwt = mqtt.createNestedObject("lwt"); + JsonObject mqtt_lwt = mqtt["lwt"].to(); mqtt_lwt["topic"] = config.Mqtt.Lwt.Topic; mqtt_lwt["value_online"] = config.Mqtt.Lwt.Value_Online; mqtt_lwt["value_offline"] = config.Mqtt.Lwt.Value_Offline; mqtt_lwt["qos"] = config.Mqtt.Lwt.Qos; - JsonObject mqtt_tls = mqtt.createNestedObject("tls"); + JsonObject mqtt_tls = mqtt["tls"].to(); mqtt_tls["enabled"] = config.Mqtt.Tls.Enabled; mqtt_tls["root_ca_cert"] = config.Mqtt.Tls.RootCaCert; mqtt_tls["certlogin"] = config.Mqtt.Tls.CertLogin; mqtt_tls["client_cert"] = config.Mqtt.Tls.ClientCert; mqtt_tls["client_key"] = config.Mqtt.Tls.ClientKey; - JsonObject mqtt_hass = mqtt.createNestedObject("hass"); + JsonObject mqtt_hass = mqtt["hass"].to(); mqtt_hass["enabled"] = config.Mqtt.Hass.Enabled; mqtt_hass["retain"] = config.Mqtt.Hass.Retain; mqtt_hass["topic"] = config.Mqtt.Hass.Topic; mqtt_hass["individual_panels"] = config.Mqtt.Hass.IndividualPanels; mqtt_hass["expire"] = config.Mqtt.Hass.Expire; - JsonObject dtu = doc.createNestedObject("dtu"); + JsonObject dtu = doc["dtu"].to(); dtu["serial"] = config.Dtu.Serial; dtu["poll_interval"] = config.Dtu.PollInterval; dtu["nrf_pa_level"] = config.Dtu.Nrf.PaLevel; @@ -97,14 +93,14 @@ bool ConfigurationClass::write() dtu["cmt_frequency"] = config.Dtu.Cmt.Frequency; dtu["cmt_country_mode"] = config.Dtu.Cmt.CountryMode; - JsonObject security = doc.createNestedObject("security"); + JsonObject security = doc["security"].to(); security["password"] = config.Security.Password; security["allow_readonly"] = config.Security.AllowReadonly; - JsonObject device = doc.createNestedObject("device"); + JsonObject device = doc["device"].to(); device["pinmapping"] = config.Dev_PinMapping; - JsonObject display = device.createNestedObject("display"); + JsonObject display = device["display"].to(); display["powersafe"] = config.Display.PowerSafe; display["screensaver"] = config.Display.ScreenSaver; display["rotation"] = config.Display.Rotation; @@ -113,15 +109,15 @@ bool ConfigurationClass::write() display["diagram_duration"] = config.Display.Diagram.Duration; display["diagram_mode"] = config.Display.Diagram.Mode; - JsonArray leds = device.createNestedArray("led"); + JsonArray leds = device["led"].to(); for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) { - JsonObject led = leds.createNestedObject(); + JsonObject led = leds.add(); led["brightness"] = config.Led_Single[i].Brightness; } - JsonArray inverters = doc.createNestedArray("inverters"); + JsonArray inverters = doc["inverters"].to(); for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { - JsonObject inv = inverters.createNestedObject(); + JsonObject inv = inverters.add(); inv["serial"] = config.Inverter[i].Serial; inv["name"] = config.Inverter[i].Name; inv["order"] = config.Inverter[i].Order; @@ -134,15 +130,19 @@ bool ConfigurationClass::write() inv["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight; inv["yieldday_correction"] = config.Inverter[i].YieldDayCorrection; - JsonArray channel = inv.createNestedArray("channel"); + JsonArray channel = inv["channel"].to(); for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { - JsonObject chanData = channel.createNestedObject(); + JsonObject chanData = channel.add(); chanData["name"] = config.Inverter[i].channel[c].Name; chanData["max_power"] = config.Inverter[i].channel[c].MaxChannelPower; chanData["yield_total_offset"] = config.Inverter[i].channel[c].YieldTotalOffset; } } + if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) { + return false; + } + // Serialize JSON to file if (serializeJson(doc, f) == 0) { MessageOutput.println("Failed to write file"); @@ -157,11 +157,7 @@ bool ConfigurationClass::read() { File f = LittleFS.open(CONFIG_FILENAME, "r", false); - DynamicJsonDocument doc(JSON_BUFFER_SIZE); - - if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) { - return false; - } + JsonDocument doc; // Deserialize the JSON document const DeserializationError error = deserializeJson(doc, f); @@ -169,6 +165,10 @@ bool ConfigurationClass::read() MessageOutput.println("Failed to read file, using default configuration"); } + if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) { + return false; + } + JsonObject cfg = doc["cfg"]; config.Cfg.Version = cfg["version"] | CONFIG_VERSION; config.Cfg.SaveCount = cfg["save_count"] | 0; @@ -324,11 +324,7 @@ void ConfigurationClass::migrate() return; } - DynamicJsonDocument doc(JSON_BUFFER_SIZE); - - if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) { - return; - } + JsonDocument doc; // Deserialize the JSON document const DeserializationError error = deserializeJson(doc, f); @@ -337,6 +333,10 @@ void ConfigurationClass::migrate() return; } + if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) { + return; + } + if (config.Cfg.Version < 0x00011700) { JsonArray inverters = doc["inverters"]; for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { diff --git a/src/MqttHandleHass.cpp b/src/MqttHandleHass.cpp index 21ff0fa2..a2d998d1 100644 --- a/src/MqttHandleHass.cpp +++ b/src/MqttHandleHass.cpp @@ -137,10 +137,7 @@ void MqttHandleHassClass::publishInverterField(std::shared_ptr name = "CH" + chanNum + " " + fieldName; } - DynamicJsonDocument root(1024); - if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { - return; - } + JsonDocument root; root["name"] = name; root["stat_t"] = stateTopic; @@ -163,6 +160,10 @@ void MqttHandleHassClass::publishInverterField(std::shared_ptr root["stat_cla"] = stateCls; } + if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { + return; + } + String buffer; serializeJson(root, buffer); publish(configTopic, buffer); @@ -185,10 +186,7 @@ void MqttHandleHassClass::publishInverterButton(std::shared_ptr inv) +void MqttHandleHassClass::createInverterInfo(JsonDocument& root, std::shared_ptr inv) { createDeviceInfo( root, @@ -378,7 +384,7 @@ void MqttHandleHassClass::createInverterInfo(DynamicJsonDocument& root, std::sha getDtuUniqueId()); } -void MqttHandleHassClass::createDtuInfo(DynamicJsonDocument& root) +void MqttHandleHassClass::createDtuInfo(JsonDocument& root) { createDeviceInfo( root, @@ -391,12 +397,12 @@ void MqttHandleHassClass::createDtuInfo(DynamicJsonDocument& root) } void MqttHandleHassClass::createDeviceInfo( - DynamicJsonDocument& root, + JsonDocument& root, const String& name, const String& identifiers, const String& configuration_url, const String& manufacturer, const String& model, const String& sw_version, const String& via_device) { - auto object = root.createNestedObject("dev"); + auto object = root["dev"].to(); object["name"] = name; object["ids"] = identifiers; diff --git a/src/PinMapping.cpp b/src/PinMapping.cpp index 8d7062b0..74f28285 100644 --- a/src/PinMapping.cpp +++ b/src/PinMapping.cpp @@ -8,8 +8,6 @@ #include #include -#define JSON_BUFFER_SIZE 6144 - #ifndef DISPLAY_TYPE #define DISPLAY_TYPE 0U #endif @@ -141,7 +139,7 @@ bool PinMappingClass::init(const String& deviceMapping) return false; } - DynamicJsonDocument doc(JSON_BUFFER_SIZE); + JsonDocument doc; // Deserialize the JSON document DeserializationError error = deserializeJson(doc, f); if (error) { @@ -216,4 +214,4 @@ bool PinMappingClass::isValidCmt2300Config() const bool PinMappingClass::isValidEthConfig() const { return _pinMapping.eth_enabled; -} \ No newline at end of file +} diff --git a/src/Utils.cpp b/src/Utils.cpp index 7ad07293..6bedd2cb 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -69,9 +69,9 @@ void Utils::restartDtu() ESP.restart(); } -bool Utils::checkJsonAlloc(const DynamicJsonDocument& doc, const char* function, const uint16_t line) +bool Utils::checkJsonAlloc(const JsonDocument& doc, const char* function, const uint16_t line) { - if (doc.capacity() == 0) { + if (doc.overflowed()) { MessageOutput.printf("Alloc failed: %s, %d\r\n", function, line); return false; } diff --git a/src/WebApi.cpp b/src/WebApi.cpp index 10f3e28d..04821d7e 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -85,7 +85,7 @@ void WebApiClass::writeConfig(JsonVariant& retMsg, const WebApiError code, const } } -bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, DynamicJsonDocument& json_document, size_t max_document_size) +bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResponse* response, JsonDocument& json_document) { auto& retMsg = response->getRoot(); retMsg["type"] = "warning"; @@ -99,14 +99,6 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp } const String json = request->getParam("data", true)->value(); - if (json.length() > max_document_size) { - retMsg["message"] = "Data too large!"; - retMsg["code"] = WebApiError::GenericDataTooLarge; - response->setLength(); - request->send(response); - return false; - } - const DeserializationError error = deserializeJson(json_document, json); if (error) { retMsg["message"] = "Failed to parse data!"; diff --git a/src/WebApi_config.cpp b/src/WebApi_config.cpp index f76a2e0a..99a539ed 100644 --- a/src/WebApi_config.cpp +++ b/src/WebApi_config.cpp @@ -53,7 +53,7 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } @@ -95,7 +95,7 @@ void WebApiConfigClass::onConfigListGet(AsyncWebServerRequest* request) AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - auto data = root.createNestedArray("configs"); + auto data = root["configs"].to(); File rootfs = LittleFS.open("/"); File file = rootfs.openNextFile(); @@ -103,7 +103,7 @@ void WebApiConfigClass::onConfigListGet(AsyncWebServerRequest* request) if (file.isDirectory()) { continue; } - JsonObject obj = data.createNestedObject(); + JsonObject obj = data.add(); obj["name"] = String(file.name()); file = rootfs.openNextFile(); diff --git a/src/WebApi_device.cpp b/src/WebApi_device.cpp index 1cc14220..421f9456 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -26,15 +26,15 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); const CONFIG_T& config = Configuration.get(); const PinMapping_t& pin = PinMapping.get(); - auto curPin = root.createNestedObject("curPin"); + auto curPin = root["curPin"].to(); curPin["name"] = config.Dev_PinMapping; - auto nrfPinObj = curPin.createNestedObject("nrf24"); + auto nrfPinObj = curPin["nrf24"].to(); nrfPinObj["clk"] = pin.nrf24_clk; nrfPinObj["cs"] = pin.nrf24_cs; nrfPinObj["en"] = pin.nrf24_en; @@ -42,7 +42,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request) nrfPinObj["miso"] = pin.nrf24_miso; nrfPinObj["mosi"] = pin.nrf24_mosi; - auto cmtPinObj = curPin.createNestedObject("cmt"); + auto cmtPinObj = curPin["cmt"].to(); cmtPinObj["clk"] = pin.cmt_clk; cmtPinObj["cs"] = pin.cmt_cs; cmtPinObj["fcs"] = pin.cmt_fcs; @@ -50,7 +50,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request) cmtPinObj["gpio2"] = pin.cmt_gpio2; cmtPinObj["gpio3"] = pin.cmt_gpio3; - auto ethPinObj = curPin.createNestedObject("eth"); + auto ethPinObj = curPin["eth"].to(); ethPinObj["enabled"] = pin.eth_enabled; ethPinObj["phy_addr"] = pin.eth_phy_addr; ethPinObj["power"] = pin.eth_power; @@ -59,19 +59,19 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request) ethPinObj["type"] = pin.eth_type; ethPinObj["clk_mode"] = pin.eth_clk_mode; - auto displayPinObj = curPin.createNestedObject("display"); + auto displayPinObj = curPin["display"].to(); displayPinObj["type"] = pin.display_type; displayPinObj["data"] = pin.display_data; displayPinObj["clk"] = pin.display_clk; displayPinObj["cs"] = pin.display_cs; displayPinObj["reset"] = pin.display_reset; - auto ledPinObj = curPin.createNestedObject("led"); + auto ledPinObj = curPin["led"].to(); for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) { ledPinObj["led" + String(i)] = pin.led[i]; } - auto display = root.createNestedObject("display"); + auto display = root["display"].to(); display["rotation"] = config.Display.Rotation; display["power_safe"] = config.Display.PowerSafe; display["screensaver"] = config.Display.ScreenSaver; @@ -80,9 +80,9 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request) display["diagramduration"] = config.Display.Diagram.Duration; display["diagrammode"] = config.Display.Diagram.Mode; - auto leds = root.createNestedArray("led"); + auto leds = root["led"].to(); for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) { - auto led = leds.createNestedObject(); + auto led = leds.add(); led["brightness"] = config.Led_Single[i].Brightness; } @@ -96,9 +96,9 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); - DynamicJsonDocument root(MQTT_JSON_DOC_SIZE); - if (!WebApi.parseRequestData(request, response, root, MQTT_JSON_DOC_SIZE)) { + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonDocument root; + if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_dtu.cpp b/src/WebApi_dtu.cpp index bbcd909f..a2192c7c 100644 --- a/src/WebApi_dtu.cpp +++ b/src/WebApi_dtu.cpp @@ -62,10 +62,10 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request) root["cmt_country"] = config.Dtu.Cmt.CountryMode; root["cmt_chan_width"] = Hoymiles.getRadioCmt()->getChannelWidth(); - auto data = root.createNestedArray("country_def"); + auto data = root["country_def"].to(); auto countryDefs = Hoymiles.getRadioCmt()->getCountryFrequencyList(); for (const auto& definition : countryDefs) { - auto obj = data.createNestedObject(); + auto obj = data.add(); obj["freq_default"] = definition.definition.Freq_Default; obj["freq_min"] = definition.definition.Freq_Min; obj["freq_max"] = definition.definition.Freq_Max; @@ -84,7 +84,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_eventlog.cpp b/src/WebApi_eventlog.cpp index 51e85aff..3637a3d9 100644 --- a/src/WebApi_eventlog.cpp +++ b/src/WebApi_eventlog.cpp @@ -20,7 +20,7 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, 2048); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); uint64_t serial = 0; @@ -47,10 +47,10 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request) uint8_t logEntryCount = inv->EventLog()->getEntryCount(); root["count"] = logEntryCount; - JsonArray eventsArray = root.createNestedArray("events"); + JsonArray eventsArray = root["events"].to(); for (uint8_t logEntry = 0; logEntry < logEntryCount; logEntry++) { - JsonObject eventsObject = eventsArray.createNestedObject(); + JsonObject eventsObject = eventsArray.add(); AlarmLogEntry_t entry; inv->EventLog()->getLogEntry(logEntry, entry, locale); diff --git a/src/WebApi_gridprofile.cpp b/src/WebApi_gridprofile.cpp index 60c340fa..2527396d 100644 --- a/src/WebApi_gridprofile.cpp +++ b/src/WebApi_gridprofile.cpp @@ -21,7 +21,7 @@ void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, 8192); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); uint64_t serial = 0; @@ -36,17 +36,17 @@ void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request) root["name"] = inv->GridProfile()->getProfileName(); root["version"] = inv->GridProfile()->getProfileVersion(); - auto jsonSections = root.createNestedArray("sections"); + auto jsonSections = root["sections"].to(); auto profSections = inv->GridProfile()->getProfile(); for (auto &profSection : profSections) { - auto jsonSection = jsonSections.createNestedObject(); + auto jsonSection = jsonSections.add(); jsonSection["name"] = profSection.SectionName; - auto jsonItems = jsonSection.createNestedArray("items"); + auto jsonItems = jsonSection["items"].to(); for (auto &profItem : profSection.items) { - auto jsonItem = jsonItems.createNestedObject(); + auto jsonItem = jsonItems.add(); jsonItem["n"] = profItem.Name; jsonItem["u"] = profItem.Unit; @@ -65,7 +65,7 @@ void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, 4096); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); uint64_t serial = 0; @@ -77,7 +77,7 @@ void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request auto inv = Hoymiles.getInverterBySerial(serial); if (inv != nullptr) { - auto raw = root.createNestedArray("raw"); + auto raw = root["raw"].to(); auto data = inv->GridProfile()->getRawData(); copyArray(&data[0], data.size(), raw); diff --git a/src/WebApi_inverter.cpp b/src/WebApi_inverter.cpp index eb48c8ef..0d82a326 100644 --- a/src/WebApi_inverter.cpp +++ b/src/WebApi_inverter.cpp @@ -29,15 +29,15 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, 768 * INV_MAX_COUNT); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - JsonArray data = root.createNestedArray("inverter"); + JsonArray data = root["inverter"].to(); const CONFIG_T& config = Configuration.get(); for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { if (config.Inverter[i].Serial > 0) { - JsonObject obj = data.createNestedObject(); + JsonObject obj = data.add(); obj["id"] = i; obj["name"] = String(config.Inverter[i].Name); obj["order"] = config.Inverter[i].Order; @@ -67,9 +67,9 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request) max_channels = inv->Statistics()->getChannelsByType(TYPE_DC).size(); } - JsonArray channel = obj.createNestedArray("channel"); + JsonArray channel = obj["channel"].to(); for (uint8_t c = 0; c < max_channels; c++) { - JsonObject chanData = channel.createNestedObject(); + JsonObject chanData = channel.add(); chanData["name"] = config.Inverter[i].channel[c].Name; chanData["max_power"] = config.Inverter[i].channel[c].MaxChannelPower; chanData["yield_total_offset"] = config.Inverter[i].channel[c].YieldTotalOffset; @@ -88,7 +88,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } @@ -163,7 +163,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } @@ -283,7 +283,7 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } @@ -328,7 +328,7 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_limit.cpp b/src/WebApi_limit.cpp index 89058926..79d6039f 100644 --- a/src/WebApi_limit.cpp +++ b/src/WebApi_limit.cpp @@ -58,7 +58,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_maintenance.cpp b/src/WebApi_maintenance.cpp index 538f087a..a7eeb424 100644 --- a/src/WebApi_maintenance.cpp +++ b/src/WebApi_maintenance.cpp @@ -22,9 +22,9 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); - DynamicJsonDocument root(MQTT_JSON_DOC_SIZE); - if (!WebApi.parseRequestData(request, response, root, MQTT_JSON_DOC_SIZE)) { + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonDocument root; + if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_mqtt.cpp b/src/WebApi_mqtt.cpp index 78fed204..88c2a4ab 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -26,7 +26,7 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); const CONFIG_T& config = Configuration.get(); @@ -60,7 +60,7 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); const CONFIG_T& config = Configuration.get(); @@ -98,9 +98,9 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE); - DynamicJsonDocument root(MQTT_JSON_DOC_SIZE); - if (!WebApi.parseRequestData(request, response, root, MQTT_JSON_DOC_SIZE)) { + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonDocument root; + if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_network.cpp b/src/WebApi_network.cpp index b7fbbe51..158c8bde 100644 --- a/src/WebApi_network.cpp +++ b/src/WebApi_network.cpp @@ -83,7 +83,7 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 343d94b5..07553921 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -95,7 +95,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } @@ -194,7 +194,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_power.cpp b/src/WebApi_power.cpp index 2f921d74..f019ce33 100644 --- a/src/WebApi_power.cpp +++ b/src/WebApi_power.cpp @@ -51,7 +51,7 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_security.cpp b/src/WebApi_security.cpp index 05f829c5..78eaffe0 100644 --- a/src/WebApi_security.cpp +++ b/src/WebApi_security.cpp @@ -42,7 +42,7 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) } AsyncJsonResponse* response = new AsyncJsonResponse(); - DynamicJsonDocument root(1024); + JsonDocument root; if (!WebApi.parseRequestData(request, response, root)) { return; } diff --git a/src/WebApi_ws_live.cpp b/src/WebApi_ws_live.cpp index 354ed372..f378e3ab 100644 --- a/src/WebApi_ws_live.cpp +++ b/src/WebApi_ws_live.cpp @@ -73,19 +73,20 @@ void WebApiWsLiveClass::sendDataTaskCb() try { std::lock_guard lock(_mutex); - DynamicJsonDocument root(4096); - if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { - continue; - } + JsonDocument root; JsonVariant var = root; - auto invArray = var.createNestedArray("inverters"); - auto invObject = invArray.createNestedObject(); + auto invArray = var["inverters"].to(); + auto invObject = invArray.add(); generateCommonJsonResponse(var); generateInverterCommonJsonResponse(invObject, inv); generateInverterChannelJsonResponse(invObject, inv); + if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { + continue; + } + String buffer; serializeJson(root, buffer); @@ -101,12 +102,12 @@ void WebApiWsLiveClass::sendDataTaskCb() void WebApiWsLiveClass::generateCommonJsonResponse(JsonVariant& root) { - JsonObject totalObj = root.createNestedObject("total"); + auto totalObj = root["total"].to(); addTotalField(totalObj, "Power", Datastore.getTotalAcPowerEnabled(), "W", Datastore.getTotalAcPowerDigits()); addTotalField(totalObj, "YieldDay", Datastore.getTotalAcYieldDayEnabled(), "Wh", Datastore.getTotalAcYieldDayDigits()); addTotalField(totalObj, "YieldTotal", Datastore.getTotalAcYieldTotalEnabled(), "kWh", Datastore.getTotalAcYieldTotalDigits()); - JsonObject hintObj = root.createNestedObject("hints"); + JsonObject hintObj = root["hints"].to(); struct tm timeinfo; hintObj["time_sync"] = !getLocalTime(&timeinfo, 5); hintObj["radio_problem"] = (Hoymiles.getRadioNrf()->isInitialized() && (!Hoymiles.getRadioNrf()->isConnected() || !Hoymiles.getRadioNrf()->isPVariant())) || (Hoymiles.getRadioCmt()->isInitialized() && (!Hoymiles.getRadioCmt()->isConnected())); @@ -144,7 +145,7 @@ void WebApiWsLiveClass::generateInverterChannelJsonResponse(JsonObject& root, st // Loop all channels for (auto& t : inv->Statistics()->getChannelTypes()) { - JsonObject chanTypeObj = root.createNestedObject(inv->Statistics()->getChannelTypeName(t)); + auto chanTypeObj = root[inv->Statistics()->getChannelTypeName(t)].to(); for (auto& c : inv->Statistics()->getChannelsByType(t)) { if (t == TYPE_DC) { chanTypeObj[String(static_cast(c))]["name"]["u"] = inv_cfg->channel[c].Name; @@ -221,10 +222,10 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request) try { std::lock_guard lock(_mutex); - AsyncJsonResponse* response = new AsyncJsonResponse(false, 4096); + AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - JsonArray invArray = root.createNestedArray("inverters"); + auto invArray = root["inverters"].to(); uint64_t serial = 0; if (request->hasParam("inv")) { @@ -235,7 +236,7 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request) if (serial > 0) { auto inv = Hoymiles.getInverterBySerial(serial); if (inv != nullptr) { - JsonObject invObject = invArray.createNestedObject(); + JsonObject invObject = invArray.add(); generateInverterCommonJsonResponse(invObject, inv); generateInverterChannelJsonResponse(invObject, inv); } @@ -247,13 +248,17 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request) continue; } - JsonObject invObject = invArray.createNestedObject(); + JsonObject invObject = invArray.add(); generateInverterCommonJsonResponse(invObject, inv); } } generateCommonJsonResponse(root); + if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { + return; + } + response->setLength(); request->send(response); From 980e847ccb9b062816887f81da25c79c41457eca Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Thu, 4 Apr 2024 20:43:07 +0200 Subject: [PATCH 10/17] Feature: Check for out of memory situations when sending json responses Also shows a nice message in the frontend if an internal error occours --- include/WebApi.h | 1 + include/WebApi_errors.h | 1 + src/WebApi.cpp | 27 +++++++++-- src/WebApi_config.cpp | 12 ++--- src/WebApi_device.cpp | 12 ++--- src/WebApi_devinfo.cpp | 3 +- src/WebApi_dtu.cpp | 27 ++++------- src/WebApi_eventlog.cpp | 3 +- src/WebApi_gridprofile.cpp | 6 +-- src/WebApi_inverter.cpp | 51 +++++++------------- src/WebApi_limit.cpp | 21 +++------ src/WebApi_maintenance.cpp | 9 ++-- src/WebApi_mqtt.cpp | 60 ++++++++---------------- src/WebApi_network.cpp | 39 +++++---------- src/WebApi_ntp.cpp | 48 +++++++------------ src/WebApi_power.cpp | 15 ++---- src/WebApi_security.cpp | 15 ++---- src/WebApi_sysstatus.cpp | 3 +- src/WebApi_ws_live.cpp | 7 +-- webapp/src/locales/de.json | 3 ++ webapp/src/locales/en.json | 3 ++ webapp/src/locales/fr.json | 3 ++ webapp/src/router/index.ts | 8 +++- webapp/src/utils/authentication.ts | 3 +- webapp/src/views/ErrorView.vue | 18 +++++++ webapp/src/views/FirmwareUpgradeView.vue | 2 +- 26 files changed, 171 insertions(+), 229 deletions(-) create mode 100644 webapp/src/views/ErrorView.vue diff --git a/include/WebApi.h b/include/WebApi.h index b4c49983..14eddc31 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -39,6 +39,7 @@ public: 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 sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line); private: AsyncWebServer _server; diff --git a/include/WebApi_errors.h b/include/WebApi_errors.h index 675419d7..97d61b22 100644 --- a/include/WebApi_errors.h +++ b/include/WebApi_errors.h @@ -9,6 +9,7 @@ enum WebApiError { GenericParseError, GenericValueMissing, GenericWriteFailed, + GenericInternalServerError, DtuBase = 2000, DtuSerialZero, diff --git a/src/WebApi.cpp b/src/WebApi.cpp index 04821d7e..bd59bd3e 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -4,6 +4,7 @@ */ #include "WebApi.h" #include "Configuration.h" +#include "MessageOutput.h" #include "defaults.h" #include @@ -93,8 +94,7 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp if (!request->hasParam("data", true)) { retMsg["message"] = "No values found!"; retMsg["code"] = WebApiError::GenericNoValueFound; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return false; } @@ -103,12 +103,31 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp if (error) { retMsg["message"] = "Failed to parse data!"; retMsg["code"] = WebApiError::GenericParseError; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return false; } 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; diff --git a/src/WebApi_config.cpp b/src/WebApi_config.cpp index 99a539ed..a67be42f 100644 --- a/src/WebApi_config.cpp +++ b/src/WebApi_config.cpp @@ -63,16 +63,14 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request) if (!(root.containsKey("delete"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["delete"].as() == false) { retMsg["message"] = "Not deleted anything!"; retMsg["code"] = WebApiError::ConfigNotDeleted; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -80,8 +78,7 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request) retMsg["message"] = "Configuration resettet. Rebooting now..."; retMsg["code"] = WebApiError::ConfigSuccess; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); Utils::removeAllFiles(); Utils::restartDtu(); @@ -110,8 +107,7 @@ void WebApiConfigClass::onConfigListGet(AsyncWebServerRequest* request) } file.close(); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiConfigClass::onConfigUploadFinish(AsyncWebServerRequest* request) diff --git a/src/WebApi_device.cpp b/src/WebApi_device.cpp index 421f9456..078d5b4a 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -86,8 +86,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request) led["brightness"] = config.Led_Single[i].Brightness; } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) @@ -108,8 +107,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) || root.containsKey("display"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::HardwarePinMappingLength; retMsg["param"]["max"] = DEV_MAX_MAPPING_NAME_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -149,8 +146,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); if (performRestart) { Utils::restartDtu(); diff --git a/src/WebApi_devinfo.cpp b/src/WebApi_devinfo.cpp index 212a7f7d..68f3396b 100644 --- a/src/WebApi_devinfo.cpp +++ b/src/WebApi_devinfo.cpp @@ -43,6 +43,5 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request) root["fw_build_datetime"] = inv->DevInfo()->getFwBuildDateTimeStr(); } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_dtu.cpp b/src/WebApi_dtu.cpp index a2192c7c..9b67ec39 100644 --- a/src/WebApi_dtu.cpp +++ b/src/WebApi_dtu.cpp @@ -73,8 +73,7 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request) obj["freq_legal_max"] = definition.definition.Freq_Legal_Max; } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) @@ -99,8 +98,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) && root.containsKey("cmt_country"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -110,40 +108,35 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) if (serial == 0) { retMsg["message"] = "Serial cannot be zero!"; retMsg["code"] = WebApiError::DtuSerialZero; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["pollinterval"].as() == 0) { retMsg["message"] = "Poll interval must be greater zero!"; retMsg["code"] = WebApiError::DtuPollZero; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["nrf_palevel"].as() > 3) { retMsg["message"] = "Invalid power level setting!"; retMsg["code"] = WebApiError::DtuInvalidPowerLevel; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["cmt_palevel"].as() < -10 || root["cmt_palevel"].as() > 20) { retMsg["message"] = "Invalid power level setting!"; retMsg["code"] = WebApiError::DtuInvalidPowerLevel; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["cmt_country"].as() >= CountryModeId_t::CountryModeId_Max) { retMsg["message"] = "Invalid country setting!"; retMsg["code"] = WebApiError::DtuInvalidCmtCountry; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -156,8 +149,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::DtuInvalidCmtFrequency; retMsg["param"]["min"] = FrequencyDefinition.Freq_Min; retMsg["param"]["max"] = FrequencyDefinition.Freq_Max; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -172,8 +164,7 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); _applyDataTask.enable(); _applyDataTask.restart(); diff --git a/src/WebApi_eventlog.cpp b/src/WebApi_eventlog.cpp index 3637a3d9..e2d34442 100644 --- a/src/WebApi_eventlog.cpp +++ b/src/WebApi_eventlog.cpp @@ -62,6 +62,5 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request) } } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_gridprofile.cpp b/src/WebApi_gridprofile.cpp index 2527396d..5ed579d0 100644 --- a/src/WebApi_gridprofile.cpp +++ b/src/WebApi_gridprofile.cpp @@ -55,8 +55,7 @@ void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request) } } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request) @@ -83,6 +82,5 @@ void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request copyArray(&data[0], data.size(), raw); } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_inverter.cpp b/src/WebApi_inverter.cpp index 0d82a326..2d9a5634 100644 --- a/src/WebApi_inverter.cpp +++ b/src/WebApi_inverter.cpp @@ -77,8 +77,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request) } } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) @@ -99,8 +98,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) && root.containsKey("name"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -110,8 +108,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) if (serial == 0) { retMsg["message"] = "Serial must be a number > 0!"; retMsg["code"] = WebApiError::InverterSerialZero; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::InverterNameLength; retMsg["param"]["max"] = INV_MAX_NAME_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -130,8 +126,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) retMsg["message"] = "Only " STR(INV_MAX_COUNT) " inverters are supported!"; retMsg["code"] = WebApiError::InverterCount; retMsg["param"]["max"] = INV_MAX_COUNT; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -142,8 +137,7 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg, WebApiError::InverterAdded, "Inverter created!"); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["id"].as() > INV_MAX_COUNT - 1) { retMsg["message"] = "Invalid ID specified!"; retMsg["code"] = WebApiError::InverterInvalidId; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -192,8 +184,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) if (serial == 0) { retMsg["message"] = "Serial must be a number > 0!"; retMsg["code"] = WebApiError::InverterSerialZero; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::InverterNameLength; retMsg["param"]["max"] = INV_MAX_NAME_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -210,8 +200,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) if (channelArray.size() == 0 || channelArray.size() > INV_MAX_CHAN_COUNT) { retMsg["message"] = "Invalid amount of max channel setting given!"; retMsg["code"] = WebApiError::InverterInvalidMaxChannel; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -243,8 +232,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg, WebApiError::InverterChanged, "Inverter changed!"); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); std::shared_ptr inv = Hoymiles.getInverterBySerial(old_serial); @@ -293,16 +281,14 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request) if (!(root.containsKey("id"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["id"].as() > INV_MAX_COUNT - 1) { retMsg["message"] = "Invalid ID specified!"; retMsg["code"] = WebApiError::InverterInvalidId; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -315,8 +301,7 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg, WebApiError::InverterDeleted, "Inverter deleted!"); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); MqttHandleHass.forceUpdate(); } @@ -338,8 +323,7 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request) if (!(root.containsKey("order"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -357,6 +341,5 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg, WebApiError::InverterOrdered, "Inverter order saved!"); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_limit.cpp b/src/WebApi_limit.cpp index 79d6039f..9a622dea 100644 --- a/src/WebApi_limit.cpp +++ b/src/WebApi_limit.cpp @@ -47,8 +47,7 @@ void WebApiLimitClass::onLimitStatus(AsyncWebServerRequest* request) root[serial]["limit_set_status"] = limitStatus; } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) @@ -70,8 +69,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) && root.containsKey("limit_type"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -81,8 +79,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) if (serial == 0) { retMsg["message"] = "Serial must be a number > 0!"; retMsg["code"] = WebApiError::LimitSerialZero; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -90,8 +87,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) retMsg["message"] = "Limit must between 0 and " STR(MAX_INVERTER_LIMIT) "!"; retMsg["code"] = WebApiError::LimitInvalidLimit; retMsg["param"]["max"] = MAX_INVERTER_LIMIT; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -102,8 +98,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) retMsg["message"] = "Invalid type specified!"; retMsg["code"] = WebApiError::LimitInvalidType; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -114,8 +109,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) if (inv == nullptr) { retMsg["message"] = "Invalid inverter specified!"; retMsg["code"] = WebApiError::LimitInvalidInverter; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -125,6 +119,5 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request) retMsg["message"] = "Settings saved!"; retMsg["code"] = WebApiError::GenericSuccess; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_maintenance.cpp b/src/WebApi_maintenance.cpp index a7eeb424..1504f9d7 100644 --- a/src/WebApi_maintenance.cpp +++ b/src/WebApi_maintenance.cpp @@ -33,8 +33,7 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request) if (!(root.containsKey("reboot"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -43,14 +42,12 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request) retMsg["message"] = "Reboot triggered!"; retMsg["code"] = WebApiError::MaintenanceRebootTriggered; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); Utils::restartDtu(); } else { retMsg["message"] = "Reboot cancled!"; retMsg["code"] = WebApiError::MaintenanceRebootCancled; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } } diff --git a/src/WebApi_mqtt.cpp b/src/WebApi_mqtt.cpp index 88c2a4ab..1795b7aa 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -50,8 +50,7 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request) root["mqtt_hass_topic"] = config.Mqtt.Hass.Topic; root["mqtt_hass_individualpanels"] = config.Mqtt.Hass.IndividualPanels; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } 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_individualpanels"] = config.Mqtt.Hass.IndividualPanels; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) @@ -130,8 +128,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) && root.containsKey("mqtt_hass_individualpanels"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::MqttHostnameLength; retMsg["param"]["max"] = MQTT_MAX_HOSTNAME_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::MqttUsernameLength; retMsg["param"]["max"] = MQTT_MAX_USERNAME_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["mqtt_password"].as().length() > MQTT_MAX_PASSWORD_STRLEN) { retMsg["message"] = "Password must not be longer than " STR(MQTT_MAX_PASSWORD_STRLEN) " characters!"; retMsg["code"] = WebApiError::MqttPasswordLength; retMsg["param"]["max"] = MQTT_MAX_PASSWORD_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["mqtt_topic"].as().length() > MQTT_MAX_TOPIC_STRLEN) { retMsg["message"] = "Topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!"; retMsg["code"] = WebApiError::MqttTopicLength; retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["mqtt_topic"].as().indexOf(' ') != -1) { retMsg["message"] = "Topic must not contain space characters!"; retMsg["code"] = WebApiError::MqttTopicCharacter; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (!root["mqtt_topic"].as().endsWith("/")) { retMsg["message"] = "Topic must end with a slash (/)!"; retMsg["code"] = WebApiError::MqttTopicTrailingSlash; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["mqtt_port"].as() == 0 || root["mqtt_port"].as() > 65535) { retMsg["message"] = "Port must be a number between 1 and 65535!"; retMsg["code"] = WebApiError::MqttPort; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::MqttCertificateLength; retMsg["param"]["max"] = MQTT_MAX_CERT_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::MqttLwtTopicLength; retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["mqtt_lwt_topic"].as().indexOf(' ') != -1) { retMsg["message"] = "LWT topic must not contain space characters!"; retMsg["code"] = WebApiError::MqttLwtTopicCharacter; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::MqttLwtOnlineLength; retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::MqttLwtOfflineLength; retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -244,8 +229,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) retMsg["message"] = "LWT QoS must not be greater than " STR(2) "!"; retMsg["code"] = WebApiError::MqttLwtQos; retMsg["param"]["max"] = 2; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -254,8 +238,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::MqttPublishInterval; retMsg["param"]["min"] = 5; retMsg["param"]["max"] = 65535; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::MqttHassTopicLength; retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["mqtt_hass_topic"].as().indexOf(' ') != -1) { retMsg["message"] = "Hass topic must not contain space characters!"; retMsg["code"] = WebApiError::MqttHassTopicCharacter; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } } @@ -306,8 +287,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); MqttSettings.performReconnect(); MqttHandleHass.forceUpdate(); diff --git a/src/WebApi_network.cpp b/src/WebApi_network.cpp index 158c8bde..7fec44b2 100644 --- a/src/WebApi_network.cpp +++ b/src/WebApi_network.cpp @@ -46,8 +46,7 @@ void WebApiNetworkClass::onNetworkStatus(AsyncWebServerRequest* request) root["ap_mac"] = WiFi.softAPmacAddress(); root["ap_stationnum"] = WiFi.softAPgetStationNum(); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request) @@ -72,8 +71,7 @@ void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request) root["aptimeout"] = config.WiFi.ApTimeout; root["mdnsenabled"] = config.Mdns.Enabled; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) @@ -102,8 +100,7 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) && root.containsKey("aptimeout"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -111,68 +108,59 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) if (!ipaddress.fromString(root["ipaddress"].as())) { retMsg["message"] = "IP address is invalid!"; retMsg["code"] = WebApiError::NetworkIpInvalid; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } IPAddress netmask; if (!netmask.fromString(root["netmask"].as())) { retMsg["message"] = "Netmask is invalid!"; retMsg["code"] = WebApiError::NetworkNetmaskInvalid; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } IPAddress gateway; if (!gateway.fromString(root["gateway"].as())) { retMsg["message"] = "Gateway is invalid!"; retMsg["code"] = WebApiError::NetworkGatewayInvalid; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } IPAddress dns1; if (!dns1.fromString(root["dns1"].as())) { retMsg["message"] = "DNS Server IP 1 is invalid!"; retMsg["code"] = WebApiError::NetworkDns1Invalid; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } IPAddress dns2; if (!dns2.fromString(root["dns2"].as())) { retMsg["message"] = "DNS Server IP 2 is invalid!"; retMsg["code"] = WebApiError::NetworkDns2Invalid; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["hostname"].as().length() == 0 || root["hostname"].as().length() > WIFI_MAX_HOSTNAME_STRLEN) { retMsg["message"] = "Hostname must between 1 and " STR(WIFI_MAX_HOSTNAME_STRLEN) " characters long!"; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (NetworkSettings.NetworkMode() == network_mode::WiFi) { if (root["ssid"].as().length() == 0 || root["ssid"].as().length() > WIFI_MAX_SSID_STRLEN) { retMsg["message"] = "SSID must between 1 and " STR(WIFI_MAX_SSID_STRLEN) " characters long!"; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } } if (root["password"].as().length() > WIFI_MAX_PASSWORD_STRLEN - 1) { retMsg["message"] = "Password must not be longer than " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!"; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } if (root["aptimeout"].as() > 99999) { retMsg["message"] = "ApTimeout must be a number between 0 and 99999!"; retMsg["code"] = WebApiError::NetworkApTimeoutInvalid; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -210,8 +198,7 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); NetworkSettings.enableAdminMode(); NetworkSettings.applyConfig(); diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 07553921..d50e0f02 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -63,8 +63,7 @@ void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request) root["sun_isSunsetAvailable"] = SunPosition.isSunsetAvailable(); root["sun_isDayPeriod"] = SunPosition.isDayPeriod(); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request) @@ -84,8 +83,7 @@ void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request) root["latitude"] = config.Ntp.Latitude; root["sunsettype"] = config.Ntp.SunsetType; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) @@ -109,8 +107,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) && root.containsKey("sunsettype"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::NtpServerLength; retMsg["param"]["max"] = NTP_MAX_SERVER_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::NtpTimezoneLength; retMsg["param"]["max"] = NTP_MAX_TIMEZONE_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::NtpTimezoneDescriptionLength; retMsg["param"]["max"] = NTP_MAX_TIMEZONEDESCR_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -151,8 +145,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); NtpSettings.setServer(); NtpSettings.setTimezone(); @@ -183,8 +176,7 @@ void WebApiNtpClass::onNtpTimeGet(AsyncWebServerRequest* request) root["minute"] = timeinfo.tm_min; root["second"] = timeinfo.tm_sec; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) @@ -209,8 +201,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) && root.containsKey("second"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -219,8 +210,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::NtpYearInvalid; retMsg["param"]["min"] = 2022; retMsg["param"]["max"] = 2100; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -229,8 +219,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::NtpMonthInvalid; retMsg["param"]["min"] = 1; retMsg["param"]["max"] = 12; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -239,8 +228,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::NtpDayInvalid; retMsg["param"]["min"] = 1; retMsg["param"]["max"] = 31; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -249,8 +237,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::NtpHourInvalid; retMsg["param"]["min"] = 0; retMsg["param"]["max"] = 23; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -259,8 +246,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::NtpMinuteInvalid; retMsg["param"]["min"] = 0; retMsg["param"]["max"] = 59; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -269,8 +255,7 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) retMsg["code"] = WebApiError::NtpSecondInvalid; retMsg["param"]["min"] = 0; retMsg["param"]["max"] = 59; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -291,6 +276,5 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request) retMsg["message"] = "Time updated!"; retMsg["code"] = WebApiError::NtpTimeUpdated; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_power.cpp b/src/WebApi_power.cpp index f019ce33..b2b2ce42 100644 --- a/src/WebApi_power.cpp +++ b/src/WebApi_power.cpp @@ -40,8 +40,7 @@ void WebApiPowerClass::onPowerStatus(AsyncWebServerRequest* request) root[inv->serialString()]["power_set_status"] = limitStatus; } - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) @@ -63,8 +62,7 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) || root.containsKey("restart")))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -74,8 +72,7 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) if (serial == 0) { retMsg["message"] = "Serial must be a number > 0!"; retMsg["code"] = WebApiError::PowerSerialZero; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -83,8 +80,7 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) if (inv == nullptr) { retMsg["message"] = "Invalid inverter specified!"; retMsg["code"] = WebApiError::PowerInvalidInverter; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -101,6 +97,5 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request) retMsg["message"] = "Settings saved!"; retMsg["code"] = WebApiError::GenericSuccess; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_security.cpp b/src/WebApi_security.cpp index 78eaffe0..eb0f27d2 100644 --- a/src/WebApi_security.cpp +++ b/src/WebApi_security.cpp @@ -31,8 +31,7 @@ void WebApiSecurityClass::onSecurityGet(AsyncWebServerRequest* request) root["password"] = config.Security.Password; root["allow_readonly"] = config.Security.AllowReadonly; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) @@ -53,8 +52,7 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) && root.containsKey("allow_readonly")) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); 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["code"] = WebApiError::SecurityPasswordLength; retMsg["param"]["max"] = WIFI_MAX_PASSWORD_STRLEN; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); return; } @@ -73,8 +70,7 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) WebApi.writeConfig(retMsg); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request) @@ -89,6 +85,5 @@ void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request) retMsg["message"] = "Authentication successful!"; retMsg["code"] = WebApiError::SecurityAuthSuccess; - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_sysstatus.cpp b/src/WebApi_sysstatus.cpp index 11bd29c2..a2893c82 100644 --- a/src/WebApi_sysstatus.cpp +++ b/src/WebApi_sysstatus.cpp @@ -76,6 +76,5 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request) root["cmt_configured"] = PinMapping.isValidCmt2300Config(); root["cmt_connected"] = Hoymiles.getRadioCmt()->isConnected(); - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } diff --git a/src/WebApi_ws_live.cpp b/src/WebApi_ws_live.cpp index f378e3ab..e79c664a 100644 --- a/src/WebApi_ws_live.cpp +++ b/src/WebApi_ws_live.cpp @@ -255,12 +255,7 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request) generateCommonJsonResponse(root); - if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) { - return; - } - - response->setLength(); - request->send(response); + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); } 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()); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index c9dfa975..ad184d1c 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -32,6 +32,9 @@ "Release": "Loslassen zum Aktualisieren", "Close": "Schließen" }, + "Error": { + "Oops": "Oops!" + }, "localeswitcher": { "Dark": "Dunkel", "Light": "Hell", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 4375137b..4179227a 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -32,6 +32,9 @@ "Release": "Release to refresh", "Close": "Close" }, + "Error": { + "Oops": "Oops!" + }, "localeswitcher": { "Dark": "Dark", "Light": "Light", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 24f0a951..c60a552a 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -32,6 +32,9 @@ "Release": "Release to refresh", "Close": "Fermer" }, + "Error": { + "Oops": "Oops!" + }, "localeswitcher": { "Dark": "Sombre", "Light": "Clair", diff --git a/webapp/src/router/index.ts b/webapp/src/router/index.ts index 6cfc00ef..8fd3cfe8 100644 --- a/webapp/src/router/index.ts +++ b/webapp/src/router/index.ts @@ -3,6 +3,7 @@ import ConfigAdminView from '@/views/ConfigAdminView.vue'; import ConsoleInfoView from '@/views/ConsoleInfoView.vue'; import DeviceAdminView from '@/views/DeviceAdminView.vue' import DtuAdminView from '@/views/DtuAdminView.vue'; +import ErrorView from '@/views/ErrorView.vue'; import FirmwareUpgradeView from '@/views/FirmwareUpgradeView.vue'; import HomeView from '@/views/HomeView.vue'; import InverterAdminView from '@/views/InverterAdminView.vue'; @@ -32,6 +33,11 @@ const router = createRouter({ name: 'Login', component: LoginView }, + { + path: '/error?status=:status&message=:message', + name: 'Error', + component: ErrorView + }, { path: '/about', name: 'About', @@ -115,4 +121,4 @@ const router = createRouter({ ] }); -export default router; \ No newline at end of file +export default router; diff --git a/webapp/src/utils/authentication.ts b/webapp/src/utils/authentication.ts index d1f87e3d..52d92fd9 100644 --- a/webapp/src/utils/authentication.ts +++ b/webapp/src/utils/authentication.ts @@ -77,6 +77,7 @@ export function handleResponse(response: Response, emitter: Emitter + + + + + + diff --git a/webapp/src/views/FirmwareUpgradeView.vue b/webapp/src/views/FirmwareUpgradeView.vue index 73846079..f7bf0d75 100644 --- a/webapp/src/views/FirmwareUpgradeView.vue +++ b/webapp/src/views/FirmwareUpgradeView.vue @@ -191,7 +191,7 @@ export default defineComponent({ const remoteHostUrl = "/api/system/status"; // Use a simple fetch request to check if the remote host is reachable - fetch(remoteHostUrl, { method: 'HEAD' }) + fetch(remoteHostUrl, { method: 'GET' }) .then(response => { // Check if the response status is OK (200-299 range) if (response.ok) { From ea289037617f4e2bc144a5bc97b94ece6f5334f6 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Thu, 4 Apr 2024 20:50:38 +0200 Subject: [PATCH 11/17] Move parsing of serial from web request to separate method --- include/WebApi.h | 1 + src/WebApi.cpp | 10 ++++++++++ src/WebApi_devinfo.cpp | 8 +------- src/WebApi_eventlog.cpp | 7 +------ src/WebApi_gridprofile.cpp | 16 ++-------------- src/WebApi_ws_live.cpp | 8 +------- 6 files changed, 16 insertions(+), 34 deletions(-) diff --git a/include/WebApi.h b/include/WebApi.h index 14eddc31..b6fdbd08 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -39,6 +39,7 @@ public: 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 uint64_t parseSerialFromRequest(AsyncWebServerRequest* request, String param_name = "inv"); static bool sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line); private: diff --git a/src/WebApi.cpp b/src/WebApi.cpp index bd59bd3e..1a5b2870 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -110,6 +110,16 @@ bool WebApiClass::parseRequestData(AsyncWebServerRequest* request, AsyncJsonResp return true; } +uint64_t WebApiClass::parseSerialFromRequest(AsyncWebServerRequest* request, String param_name) +{ + if (request->hasParam(param_name)) { + String s = request->getParam(param_name)->value(); + return strtoll(s.c_str(), NULL, 16); + } + + return 0; +} + bool WebApiClass::sendJsonResponse(AsyncWebServerRequest* request, AsyncJsonResponse* response, const char* function, const uint16_t line) { bool ret_val = true; diff --git a/src/WebApi_devinfo.cpp b/src/WebApi_devinfo.cpp index 68f3396b..449cd177 100644 --- a/src/WebApi_devinfo.cpp +++ b/src/WebApi_devinfo.cpp @@ -23,13 +23,7 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request) AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - - uint64_t serial = 0; - if (request->hasParam("inv")) { - String s = request->getParam("inv")->value(); - serial = strtoll(s.c_str(), NULL, 16); - } - + auto serial = WebApi.parseSerialFromRequest(request); auto inv = Hoymiles.getInverterBySerial(serial); if (inv != nullptr) { diff --git a/src/WebApi_eventlog.cpp b/src/WebApi_eventlog.cpp index e2d34442..ec8b78c3 100644 --- a/src/WebApi_eventlog.cpp +++ b/src/WebApi_eventlog.cpp @@ -22,12 +22,7 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request) AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - - uint64_t serial = 0; - if (request->hasParam("inv")) { - String s = request->getParam("inv")->value(); - serial = strtoll(s.c_str(), NULL, 16); - } + auto serial = WebApi.parseSerialFromRequest(request); AlarmMessageLocale_t locale = AlarmMessageLocale_t::EN; if (request->hasParam("locale")) { diff --git a/src/WebApi_gridprofile.cpp b/src/WebApi_gridprofile.cpp index 5ed579d0..9fc05b03 100644 --- a/src/WebApi_gridprofile.cpp +++ b/src/WebApi_gridprofile.cpp @@ -23,13 +23,7 @@ void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request) AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - - uint64_t serial = 0; - if (request->hasParam("inv")) { - String s = request->getParam("inv")->value(); - serial = strtoll(s.c_str(), NULL, 16); - } - + auto serial = WebApi.parseSerialFromRequest(request); auto inv = Hoymiles.getInverterBySerial(serial); if (inv != nullptr) { @@ -66,13 +60,7 @@ void WebApiGridProfileClass::onGridProfileRawdata(AsyncWebServerRequest* request AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - - uint64_t serial = 0; - if (request->hasParam("inv")) { - String s = request->getParam("inv")->value(); - serial = strtoll(s.c_str(), NULL, 16); - } - + auto serial = WebApi.parseSerialFromRequest(request); auto inv = Hoymiles.getInverterBySerial(serial); if (inv != nullptr) { diff --git a/src/WebApi_ws_live.cpp b/src/WebApi_ws_live.cpp index e79c664a..eb1a83bf 100644 --- a/src/WebApi_ws_live.cpp +++ b/src/WebApi_ws_live.cpp @@ -224,14 +224,8 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request) std::lock_guard lock(_mutex); AsyncJsonResponse* response = new AsyncJsonResponse(); auto& root = response->getRoot(); - auto invArray = root["inverters"].to(); - - uint64_t serial = 0; - if (request->hasParam("inv")) { - String s = request->getParam("inv")->value(); - serial = strtoll(s.c_str(), NULL, 16); - } + auto serial = WebApi.parseSerialFromRequest(request); if (serial > 0) { auto inv = Hoymiles.getInverterBySerial(serial); From 153293e1c7dd5daca4bd4f161b0034dda3181892 Mon Sep 17 00:00:00 2001 From: Bernhard Kirchen Date: Fri, 12 Apr 2024 15:27:24 +0200 Subject: [PATCH 12/17] remove remaining usage of F() macro --- lib/Hoymiles/src/inverters/HMT_4CH.cpp | 2 +- lib/Hoymiles/src/inverters/HMT_6CH.cpp | 2 +- src/InverterSettings.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Hoymiles/src/inverters/HMT_4CH.cpp b/lib/Hoymiles/src/inverters/HMT_4CH.cpp index 609e3350..c84eff47 100644 --- a/lib/Hoymiles/src/inverters/HMT_4CH.cpp +++ b/lib/Hoymiles/src/inverters/HMT_4CH.cpp @@ -70,7 +70,7 @@ bool HMT_4CH::isValidSerial(const uint64_t serial) String HMT_4CH::typeName() const { - return F("HMT-1600/1800/2000-4T"); + return "HMT-1600/1800/2000-4T"; } const byteAssign_t* HMT_4CH::getByteAssignment() const diff --git a/lib/Hoymiles/src/inverters/HMT_6CH.cpp b/lib/Hoymiles/src/inverters/HMT_6CH.cpp index f8b9f407..2c3dd5f3 100644 --- a/lib/Hoymiles/src/inverters/HMT_6CH.cpp +++ b/lib/Hoymiles/src/inverters/HMT_6CH.cpp @@ -84,7 +84,7 @@ bool HMT_6CH::isValidSerial(const uint64_t serial) String HMT_6CH::typeName() const { - return F("HMT-1800/2250-6T"); + return "HMT-1800/2250-6T"; } const byteAssign_t* HMT_6CH::getByteAssignment() const diff --git a/src/InverterSettings.cpp b/src/InverterSettings.cpp index 7daad4df..c08585e2 100644 --- a/src/InverterSettings.cpp +++ b/src/InverterSettings.cpp @@ -51,9 +51,9 @@ void InverterSettingsClass::init(Scheduler& scheduler) if (PinMapping.isValidCmt2300Config()) { Hoymiles.initCMT(pin.cmt_sdio, pin.cmt_clk, pin.cmt_cs, pin.cmt_fcs, pin.cmt_gpio2, pin.cmt_gpio3); - MessageOutput.println(F(" Setting country mode... ")); + MessageOutput.println(" Setting country mode... "); Hoymiles.getRadioCmt()->setCountryMode(static_cast(config.Dtu.Cmt.CountryMode)); - MessageOutput.println(F(" Setting CMT target frequency... ")); + MessageOutput.println(" Setting CMT target frequency... "); Hoymiles.getRadioCmt()->setInverterTargetFrequency(config.Dtu.Cmt.Frequency); } From b58d08683e3b4e9d7ed6a9963d943887375db061 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Fri, 12 Apr 2024 20:02:18 +0200 Subject: [PATCH 13/17] webapp: update dependencies --- webapp/.eslintrc.cjs | 14 -- webapp/eslint.config.js | 36 ++++ webapp/package.json | 21 ++- webapp/yarn.lock | 371 +++++++++++++++++----------------------- 4 files changed, 204 insertions(+), 238 deletions(-) delete mode 100644 webapp/.eslintrc.cjs create mode 100644 webapp/eslint.config.js diff --git a/webapp/.eslintrc.cjs b/webapp/.eslintrc.cjs deleted file mode 100644 index ade85716..00000000 --- a/webapp/.eslintrc.cjs +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-env node */ -require('@rushstack/eslint-patch/modern-module-resolution') - -module.exports = { - root: true, - 'extends': [ - 'plugin:vue/vue3-essential', - 'eslint:recommended', - '@vue/eslint-config-typescript' - ], - parserOptions: { - ecmaVersion: 'latest' - } -} diff --git a/webapp/eslint.config.js b/webapp/eslint.config.js new file mode 100644 index 00000000..91657b98 --- /dev/null +++ b/webapp/eslint.config.js @@ -0,0 +1,36 @@ +/* eslint-env node */ +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { FlatCompat } from "@eslint/eslintrc"; +import js from "@eslint/js"; +import pluginVue from 'eslint-plugin-vue' + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); + +export default [ + js.configs.recommended, + ...pluginVue.configs['flat/essential'], + ...compat.extends("@vue/eslint-config-typescript/recommended"), + { + files: [ + "**/*.vue", + "**/*.js", + "**/*.jsx", + "**/*.cjs", + "**/*.mjs", + "**/*.ts", + "**/*.tsx", + "**/*.cts", + "**/*.mts", + ], + languageOptions: { + ecmaVersion: 'latest' + }, + } + ] diff --git a/webapp/package.json b/webapp/package.json index 5e92ee74..86b30904 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -9,7 +9,7 @@ "preview": "vite preview --port 4173", "build-only": "vite build", "type-check": "vue-tsc --noEmit", - "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" + "lint": "eslint ." }, "dependencies": { "@popperjs/core": "^2.11.8", @@ -19,31 +19,30 @@ "sortablejs": "^1.15.2", "spark-md5": "^3.0.2", "vue": "^3.4.21", - "vue-i18n": "^9.10.2", + "vue-i18n": "^9.12.0", "vue-router": "^4.3.0" }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^4.0.0", - "@rushstack/eslint-patch": "^1.10.1", "@tsconfig/node18": "^18.2.4", "@types/bootstrap": "^5.2.10", - "@types/node": "^20.12.2", + "@types/node": "^20.12.7", "@types/pulltorefreshjs": "^0.1.7", "@types/sortablejs": "^1.15.8", "@types/spark-md5": "^3.0.4", "@vitejs/plugin-vue": "^5.0.4", "@vue/eslint-config-typescript": "^13.0.0", "@vue/tsconfig": "^0.5.1", - "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.24.0", + "eslint": "^9.0.0", + "eslint-plugin-vue": "^9.24.1", "npm-run-all": "^4.1.5", "pulltorefreshjs": "^0.1.22", - "sass": "^1.72.0", - "terser": "^5.30.0", - "typescript": "^5.4.3", - "vite": "^5.2.7", + "sass": "^1.75.0", + "terser": "^5.30.3", + "typescript": "^5.4.5", + "vite": "^5.2.8", "vite-plugin-compression": "^0.5.1", "vite-plugin-css-injected-by-js": "^3.5.0", - "vue-tsc": "^2.0.7" + "vue-tsc": "^2.0.13" } } diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 1d7bc202..e27e2459 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -156,32 +156,32 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== +"@eslint/eslintrc@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.0.2.tgz#36180f8e85bf34d2fe3ccc2261e8e204a411ab4e" + integrity sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.0.0.tgz#1a9e4b4c96d8c7886e0110ed310a0135144a1691" + integrity sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ== -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== +"@humanwhocodes/config-array@^0.12.3": + version "0.12.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.12.3.tgz#a6216d90f81a30bedd1d4b5d799b47241f318072" + integrity sha512-jsNnTBlMWuTpDkeE3on7+dWJi0D6fdDfeANj/w7MpS8ztROCoLvIO2nG0CcFj+E4k8j4QrSTh4Oryi3i2G669g== dependencies: - "@humanwhocodes/object-schema" "^2.0.2" + "@humanwhocodes/object-schema" "^2.0.3" debug "^4.3.1" minimatch "^3.0.5" @@ -190,10 +190,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@intlify/bundle-utils@^8.0.0": version "8.0.0" @@ -210,20 +210,20 @@ source-map-js "^1.0.1" yaml-eslint-parser "^1.2.2" -"@intlify/core-base@9.10.2": - version "9.10.2" - resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.10.2.tgz#e7f8857f8011184e4afbdcfae7dbd85c50ba5271" - integrity sha512-HGStVnKobsJL0DoYIyRCGXBH63DMQqEZxDUGrkNI05FuTcruYUtOAxyL3zoAZu/uDGO6mcUvm3VXBaHG2GdZCg== +"@intlify/core-base@9.12.0": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.12.0.tgz#79f43faa8eb1f3b2bfe569a9fbae9bc50908d311" + integrity sha512-6EnWQXHnCh2bMiXT5N/IWwkcYQXjmF8nnEZ3YhTm23h1ZfOylz83D7pJYhcU8CsTiEdgbGiNdqyZPKwrHw03Ng== dependencies: - "@intlify/message-compiler" "9.10.2" - "@intlify/shared" "9.10.2" + "@intlify/message-compiler" "9.12.0" + "@intlify/shared" "9.12.0" -"@intlify/message-compiler@9.10.2": - version "9.10.2" - resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.10.2.tgz#c44cbb915bdd0d62780a38595a84006c781f717a" - integrity sha512-ntY/kfBwQRtX5Zh6wL8cSATujPzWW2ZQd1QwKyWwAy5fMqJyyixHMeovN4fmEyCqSu+hFfYOE63nU94evsy4YA== +"@intlify/message-compiler@9.12.0": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.12.0.tgz#5e152344853c29369911bd5e541e061b09218333" + integrity sha512-2c6VwhvVJ1nur+2cN2NjdrmrV6vXjvyxYVvtUYMXKsWSUwoNURHGds0xJVJmWxbF8qV9oGepcVV6xl9bvadEIg== dependencies: - "@intlify/shared" "9.10.2" + "@intlify/shared" "9.12.0" source-map-js "^1.0.2" "@intlify/message-compiler@^9.4.0": @@ -234,10 +234,10 @@ "@intlify/shared" "9.4.0" source-map-js "^1.0.2" -"@intlify/shared@9.10.2": - version "9.10.2" - resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.10.2.tgz#693300ea033868cbe4086b832170612f002e24a9" - integrity sha512-ttHCAJkRy7R5W2S9RVnN9KYQYPIpV2+GiS79T4EE37nrPyH6/1SrOh3bmdCRC1T3ocL8qCDx7x2lBJ0xaITU7Q== +"@intlify/shared@9.12.0": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.12.0.tgz#993383b6a98c8e37a1fa184a677eb39635a14a1c" + integrity sha512-uBcH55x5CfZynnerWHQxrXbT6yD6j6T7Nt+R2+dHAOAneoMd6BoGvfEzfYscE94rgmjoDqdr+PdGDBLk5I5EjA== "@intlify/shared@9.4.0", "@intlify/shared@^9.4.0": version "9.4.0" @@ -412,11 +412,6 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz#6abd79db7ff8d01a58865ba20a63cfd23d9e2a10" integrity sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw== -"@rushstack/eslint-patch@^1.10.1": - version "1.10.1" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.1.tgz#7ca168b6937818e9a74b47ac4e2112b2e1a024cf" - integrity sha512-S3Kq8e7LqxkA9s7HKLqXGTGck1uwis5vAXan3FnU5yw1Ec5hsSGnq4s/UCaSqABPOnOTg7zASLyst7+ohgWexg== - "@tsconfig/node18@^18.2.4": version "18.2.4" resolved "https://registry.yarnpkg.com/@tsconfig/node18/-/node18-18.2.4.tgz#094efbdd70f697d37c09f34067bf41bc4a828ae3" @@ -444,10 +439,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== -"@types/node@^20.12.2": - version "20.12.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.2.tgz#9facdd11102f38b21b4ebedd9d7999663343d72e" - integrity sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ== +"@types/node@^20.12.7": + version "20.12.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384" + integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg== dependencies: undici-types "~5.26.4" @@ -557,36 +552,31 @@ "@typescript-eslint/types" "7.2.0" eslint-visitor-keys "^3.4.1" -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - "@vitejs/plugin-vue@^5.0.4": version "5.0.4" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz#508d6a0f2440f86945835d903fcc0d95d1bb8a37" integrity sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ== -"@volar/language-core@2.1.3", "@volar/language-core@~2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.1.3.tgz#ac6057ec73c5fcda1fc07677bf0d7be41e6c59b1" - integrity sha512-F93KYZYqcYltG7NihfnLt/omMZOtrQtsh2+wj+cgx3xolopU+TZvmwlZWOjw3ObZGFj3SKBb4jJn6VSfSch6RA== +"@volar/language-core@2.2.0-alpha.8": + version "2.2.0-alpha.8" + resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.2.0-alpha.8.tgz#74120a27ff2498ad297e86d17be95a9c7e1b46f5" + integrity sha512-Ew1Iw7/RIRNuDLn60fWJdOLApAlfTVPxbPiSLzc434PReC9kleYtaa//Wo2WlN1oiRqneW0pWQQV0CwYqaimLQ== dependencies: - "@volar/source-map" "2.1.3" + "@volar/source-map" "2.2.0-alpha.8" -"@volar/source-map@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.1.3.tgz#8f3cb110019c45fa4cd47ad2f5fe5469bd54b9e3" - integrity sha512-j+R+NG/OlDgdNMttADxNuSM9Z26StT/Bjw0NgSydI05Vihngn9zvaP/xXwfWs5qQrRzbKVFxJebS2ks5m/URuA== +"@volar/source-map@2.2.0-alpha.8": + version "2.2.0-alpha.8" + resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.2.0-alpha.8.tgz#ca090f828fbef7e09ea06a636c41a06aa2afe153" + integrity sha512-E1ZVmXFJ5DU4fWDcWHzi8OLqqReqIDwhXvIMhVdk6+VipfMVv4SkryXu7/rs4GA/GsebcRyJdaSkKBB3OAkIcA== dependencies: muggle-string "^0.4.0" -"@volar/typescript@~2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.1.3.tgz#bfdc901afd44c2d05697967211aa55d53fb8bf69" - integrity sha512-ZZqLMih4mvu2eJAW3UCFm84OM/ojYMoA/BU/W1TctT5F2nVzNJmW4jxMWmP3wQzxCbATfTa5gLb1+BSI9NBMBg== +"@volar/typescript@2.2.0-alpha.8": + version "2.2.0-alpha.8" + resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.2.0-alpha.8.tgz#83a056c52995b4142364be3dda41d955a96f7356" + integrity sha512-RLbRDI+17CiayHZs9HhSzlH0FhLl/+XK6o2qoiw2o2GGKcyD1aDoY6AcMd44acYncTOrqoTNoY6LuCiRyiJiGg== dependencies: - "@volar/language-core" "2.1.3" + "@volar/language-core" "2.2.0-alpha.8" path-browserify "^1.0.1" "@vue/compiler-core@3.2.47": @@ -692,12 +682,12 @@ "@typescript-eslint/parser" "^7.1.1" vue-eslint-parser "^9.3.1" -"@vue/language-core@2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-2.0.7.tgz#af12f752a93c4d2498626fca33f5d1ddc8c5ceb9" - integrity sha512-Vh1yZX3XmYjn9yYLkjU8DN6L0ceBtEcapqiyclHne8guG84IaTzqtvizZB1Yfxm3h6m7EIvjerLO5fvOZO6IIQ== +"@vue/language-core@2.0.13": + version "2.0.13" + resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-2.0.13.tgz#2d1638b882011187b4b57115425d52b0901acab5" + integrity sha512-oQgM+BM66SU5GKtUMLQSQN0bxHFkFpLSSAiY87wVziPaiNQZuKVDt/3yA7GB9PiQw0y/bTNL0bOc0jM/siYjKg== dependencies: - "@volar/language-core" "~2.1.3" + "@volar/language-core" "2.2.0-alpha.8" "@vue/compiler-dom" "^3.4.0" "@vue/shared" "^3.4.0" computeds "^0.0.1" @@ -768,6 +758,11 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn@^8.11.3: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + acorn@^8.5.0, acorn@^8.9.0: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" @@ -1028,13 +1023,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" @@ -1136,10 +1124,10 @@ escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" -eslint-plugin-vue@^9.24.0: - version "9.24.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.24.0.tgz#71209f4652ee767f18c0bf56f25991b7cdc5aa46" - integrity sha512-9SkJMvF8NGMT9aQCwFc5rj8Wo1XWSMSHk36i7ZwdI614BU7sIOR28ZjuFPKp8YGymZN12BSEbiSwa7qikp+PBw== +eslint-plugin-vue@^9.24.1: + version "9.24.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz#0d90330c939f9dd2f4c759da5a2ad91dc1c8bac4" + integrity sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg== dependencies: "@eslint-community/eslint-utils" "^4.4.0" globals "^13.24.0" @@ -1158,15 +1146,15 @@ eslint-scope@^7.1.1: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.1.tgz#a9601e4b81a0b9171657c343fb13111688963cfc" + integrity sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.0.0: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== @@ -1181,41 +1169,42 @@ eslint-visitor-keys@^3.4.1: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== -eslint@^8.57.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== +eslint-visitor-keys@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" + integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== + +eslint@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.0.0.tgz#6270548758e390343f78c8afd030566d86927d40" + integrity sha512-IMryZ5SudxzQvuod6rUdIUz29qFItWx281VhtFVc2Psy/ZhlCeD/5DT6lBIJ4H3G+iamGJoTln1v+QSuPw0p7Q== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" + "@eslint/eslintrc" "^3.0.2" + "@eslint/js" "9.0.0" + "@humanwhocodes/config-array" "^0.12.3" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" + eslint-scope "^8.0.1" + eslint-visitor-keys "^4.0.0" + espree "^10.0.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" @@ -1225,7 +1214,16 @@ eslint@^8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -espree@^9.0.0, espree@^9.6.1: +espree@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.0.1.tgz#600e60404157412751ba4a6f3a2ee1a42433139f" + integrity sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww== + dependencies: + acorn "^8.11.3" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.0.0" + +espree@^9.0.0: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== @@ -1243,15 +1241,6 @@ espree@^9.3.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" -espree@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.0.tgz#80869754b1c6560f32e3b6929194a3fe07c5b82f" - integrity sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -1337,12 +1326,12 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" fill-range@^7.0.1: version "7.0.1" @@ -1359,18 +1348,18 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" + flatted "^3.2.9" + keyv "^4.5.4" -flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== fs-extra@^10.0.0: version "10.1.0" @@ -1381,11 +1370,6 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" @@ -1447,25 +1431,6 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^13.19.0: - version "13.19.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8" - integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ== - dependencies: - type-fest "^0.20.2" - globals@^13.24.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" @@ -1473,6 +1438,11 @@ globals@^13.24.0: dependencies: type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -1574,19 +1544,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -1724,6 +1681,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -1768,6 +1730,13 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1849,7 +1818,7 @@ minimatch@9.0.3, minimatch@^9.0.3: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -1958,13 +1927,6 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -2016,11 +1978,6 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -2181,13 +2138,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rollup@^4.13.0: version "4.13.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.0.tgz#dd2ae144b4cdc2ea25420477f68d4937a721237a" @@ -2226,10 +2176,10 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -sass@^1.72.0: - version "1.72.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.72.0.tgz#5b9978943fcfb32b25a6a5acb102fc9dabbbf41c" - integrity sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA== +sass@^1.75.0: + version "1.75.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.75.0.tgz#91bbe87fb02dfcc34e052ddd6ab80f60d392be6c" + integrity sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -2431,10 +2381,10 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -terser@^5.30.0: - version "5.30.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.30.0.tgz#64cb2af71e16ea3d32153f84d990f9be0cdc22bf" - integrity sha512-Y/SblUl5kEyEFzhMAQdsxVHh+utAxd4IuRNJzKywY/4uzSogh3G219jqbDDxYu4MXO9CzY3tSEqmZvW6AoEDJw== +terser@^5.30.3: + version "5.30.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.30.3.tgz#f1bb68ded42408c316b548e3ec2526d7dd03f4d2" + integrity sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -2470,10 +2420,10 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typescript@^5.4.3: - version "5.4.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" - integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== +typescript@^5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== ufo@^1.1.2: version "1.1.2" @@ -2544,10 +2494,10 @@ vite-plugin-css-injected-by-js@^3.5.0: resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.0.tgz#784c0f42c2b42155eb4c726c6addfa24aba9f4fb" integrity sha512-d0QaHH9kS93J25SwRqJNEfE29PSuQS5jn51y9N9i2Yoq0FRO7rjuTeLvjM5zwklZlRrIn6SUdtOEDKyHokgJZg== -vite@^5.2.7: - version "5.2.7" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.7.tgz#e1b8a985eb54fcb9467d7f7f009d87485016df6e" - integrity sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA== +vite@^5.2.8: + version "5.2.8" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.8.tgz#a99e09939f1a502992381395ce93efa40a2844aa" + integrity sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA== dependencies: esbuild "^0.20.1" postcss "^8.4.38" @@ -2581,13 +2531,13 @@ vue-eslint-parser@^9.4.2: lodash "^4.17.21" semver "^7.3.6" -vue-i18n@^9.10.2: - version "9.10.2" - resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.10.2.tgz#6f4b5d76bce649f1e18bb9b7767b72962b3e30a3" - integrity sha512-ECJ8RIFd+3c1d3m1pctQ6ywG5Yj8Efy1oYoAKQ9neRdkLbuKLVeW4gaY5HPkD/9ssf1pOnUrmIFjx2/gkGxmEw== +vue-i18n@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.12.0.tgz#8d073b3d7b92e822dcc3268946af4ecf14b778b3" + integrity sha512-rUxCKTws8NH3XP98W71GA7btAQdAuO7j6BC5y5s1bTNQYo/CIgZQf+p7d1Zo5bo/3v8TIq9aSUMDjpfgKsC3Uw== dependencies: - "@intlify/core-base" "9.10.2" - "@intlify/shared" "9.10.2" + "@intlify/core-base" "9.12.0" + "@intlify/shared" "9.12.0" "@vue/devtools-api" "^6.5.0" vue-router@^4.3.0: @@ -2605,13 +2555,13 @@ vue-template-compiler@^2.7.14: de-indent "^1.0.2" he "^1.2.0" -vue-tsc@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-2.0.7.tgz#3177a2fe720bfa7355d3717929ee8c8d132bc5d0" - integrity sha512-LYa0nInkfcDBB7y8jQ9FQ4riJTRNTdh98zK/hzt4gEpBZQmf30dPhP+odzCa+cedGz6B/guvJEd0BavZaRptjg== +vue-tsc@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-2.0.13.tgz#6ee557705456442e0f43ec0d1774ebf5ffec54f1" + integrity sha512-a3nL3FvguCWVJUQW/jFrUxdeUtiEkbZoQjidqvMeBK//tuE2w6NWQAbdrEpY2+6nSa4kZoKZp8TZUMtHpjt4mQ== dependencies: - "@volar/typescript" "~2.1.3" - "@vue/language-core" "2.0.7" + "@volar/typescript" "2.2.0-alpha.8" + "@vue/language-core" "2.0.13" semver "^7.5.4" vue@^3.4.21: @@ -2660,11 +2610,6 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - xml-name-validator@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" From de156ef10a4606fa7391ea380d0f93446f685ded Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Fri, 12 Apr 2024 20:34:30 +0200 Subject: [PATCH 14/17] webapp: Fix lint errors --- webapp/src/components/BasePage.vue | 5 +- webapp/src/components/BootstrapAlert.vue | 4 +- webapp/src/components/FirmwareInfo.vue | 4 +- webapp/src/components/InputElement.vue | 4 +- webapp/src/components/InputSerial.vue | 2 + webapp/src/components/NavBar.vue | 24 +- webapp/src/components/PinInfo.vue | 2 + webapp/src/utils/authentication.ts | 2 +- webapp/src/views/ConfigAdminView.vue | 4 +- webapp/src/views/ConsoleInfoView.vue | 308 +++++++++++------------ webapp/src/views/HomeView.vue | 12 +- webapp/src/views/SystemInfoView.vue | 2 +- webapp/vite.config.ts | 1 + 13 files changed, 189 insertions(+), 185 deletions(-) diff --git a/webapp/src/components/BasePage.vue b/webapp/src/components/BasePage.vue index 0ec43d36..3ca9c12b 100644 --- a/webapp/src/components/BasePage.vue +++ b/webapp/src/components/BasePage.vue @@ -48,15 +48,14 @@ export default defineComponent({ showReload: { type: Boolean, required: false, default: false }, }, mounted() { - var self = this; console.log("init"); PullToRefresh.init({ mainElement: 'body', // above which element? instructionsPullToRefresh: this.$t('base.Pull'), instructionsReleaseToRefresh: this.$t('base.Release'), instructionsRefreshing: this.$t('base.Refreshing'), - onRefresh: function() { - self.$emit('reload'); + onRefresh: () => { + this.$emit('reload'); } }); }, diff --git a/webapp/src/components/BootstrapAlert.vue b/webapp/src/components/BootstrapAlert.vue index df96fb62..a629863d 100644 --- a/webapp/src/components/BootstrapAlert.vue +++ b/webapp/src/components/BootstrapAlert.vue @@ -52,7 +52,7 @@ export default defineComponent({ _countDownTimeout = undefined; }; - var countDown = ref(); + const countDown = ref(); watch(() => props.modelValue, () => { countDown.value = parseCountDown(props.modelValue); }); @@ -116,4 +116,4 @@ export default defineComponent({ }; }, }); - \ No newline at end of file + diff --git a/webapp/src/components/FirmwareInfo.vue b/webapp/src/components/FirmwareInfo.vue index 11aa25a9..7271004d 100644 --- a/webapp/src/components/FirmwareInfo.vue +++ b/webapp/src/components/FirmwareInfo.vue @@ -83,10 +83,10 @@ export default defineComponent({ }, computed: { modelAllowVersionInfo: { - get(): any { + get(): boolean { return !!this.allowVersionInfo; }, - set(value: any) { + set(value: boolean) { this.$emit('update:allowVersionInfo', value); }, }, diff --git a/webapp/src/components/InputElement.vue b/webapp/src/components/InputElement.vue index eff8e9f6..f12a1172 100644 --- a/webapp/src/components/InputElement.vue +++ b/webapp/src/components/InputElement.vue @@ -83,10 +83,12 @@ export default defineComponent({ }, computed: { model: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any get(): any { if (this.type === 'checkbox') return !!this.modelValue; return this.modelValue; }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any set(value: any) { this.$emit('update:modelValue', value); }, @@ -112,4 +114,4 @@ export default defineComponent({ } }, }); - \ No newline at end of file + diff --git a/webapp/src/components/InputSerial.vue b/webapp/src/components/InputSerial.vue index 9f5ee343..3669da62 100644 --- a/webapp/src/components/InputSerial.vue +++ b/webapp/src/components/InputSerial.vue @@ -28,9 +28,11 @@ export default defineComponent({ }, computed: { model: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any get(): any { return this.modelValue; }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any set(value: any) { this.$emit('update:modelValue', value); }, diff --git a/webapp/src/components/NavBar.vue b/webapp/src/components/NavBar.vue index 53995df7..e6eb58f2 100644 --- a/webapp/src/components/NavBar.vue +++ b/webapp/src/components/NavBar.vue @@ -146,8 +146,8 @@ export default defineComponent({ }, isEaster() { const easter = this.getEasterSunday(this.now.getFullYear()); - var easterStart = new Date(easter); - var easterEnd = new Date(easter); + const easterStart = new Date(easter); + const easterEnd = new Date(easter); easterStart.setDate(easterStart.getDate() - 2); easterEnd.setDate(easterEnd.getDate() + 1); return this.now >= easterStart && this.now < easterEnd; @@ -170,18 +170,18 @@ export default defineComponent({ this.$refs.navbarCollapse && (this.$refs.navbarCollapse as HTMLElement).classList.remove("show"); }, getEasterSunday(year: number): Date { - var f = Math.floor; - var G = year % 19; - var C = f(year / 100); - var H = (C - f(C / 4) - f((8 * C + 13) / 25) + 19 * G + 15) % 30; - var I = H - f(H / 28) * (1 - f(29 / (H + 1)) * f((21 - G) / 11)); - var J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7; - var L = I - J; - var month = 3 + f((L + 40) / 44); - var day = L + 28 - 31 * f(month / 4); + const f = Math.floor; + const G = year % 19; + const C = f(year / 100); + const H = (C - f(C / 4) - f((8 * C + 13) / 25) + 19 * G + 15) % 30; + const I = H - f(H / 28) * (1 - f(29 / (H + 1)) * f((21 - G) / 11)); + const J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7; + const L = I - J; + const month = 3 + f((L + 40) / 44); + const day = L + 28 - 31 * f(month / 4); return new Date(year, month - 1, day); } }, }); - \ No newline at end of file + diff --git a/webapp/src/components/PinInfo.vue b/webapp/src/components/PinInfo.vue index 3d4616ad..c1e84b81 100644 --- a/webapp/src/components/PinInfo.vue +++ b/webapp/src/components/PinInfo.vue @@ -84,9 +84,11 @@ export default defineComponent({ let comCur = 999999; if (this.selectedPinAssignment && category in this.selectedPinAssignment) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any comSel = (this.selectedPinAssignment as any)[category][prop]; } if (this.currentPinAssignment && category in this.currentPinAssignment) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any comCur = (this.currentPinAssignment as any)[category][prop]; } diff --git a/webapp/src/utils/authentication.ts b/webapp/src/utils/authentication.ts index 52d92fd9..f666c36b 100644 --- a/webapp/src/utils/authentication.ts +++ b/webapp/src/utils/authentication.ts @@ -41,7 +41,7 @@ export function isLoggedIn(): boolean { return (localStorage.getItem('user') != null); } -export function login(username: String, password: String) { +export function login(username: string, password: string) { const requestOptions = { method: 'GET', headers: { diff --git a/webapp/src/views/ConfigAdminView.vue b/webapp/src/views/ConfigAdminView.vue index c0954396..e0bb66dc 100644 --- a/webapp/src/views/ConfigAdminView.vue +++ b/webapp/src/views/ConfigAdminView.vue @@ -188,8 +188,8 @@ export default defineComponent({ fetch("/api/config/get?file=" + this.backupFileSelect, { headers: authHeader() }) .then(res => res.blob()) .then(blob => { - var file = window.URL.createObjectURL(blob); - var a = document.createElement('a'); + const file = window.URL.createObjectURL(blob); + const a = document.createElement('a'); a.href = file; a.download = this.backupFileSelect; document.body.appendChild(a); diff --git a/webapp/src/views/ConsoleInfoView.vue b/webapp/src/views/ConsoleInfoView.vue index fb17f62d..eba1d533 100644 --- a/webapp/src/views/ConsoleInfoView.vue +++ b/webapp/src/views/ConsoleInfoView.vue @@ -1,154 +1,154 @@ - - - - - \ No newline at end of file + + + + + diff --git a/webapp/src/views/HomeView.vue b/webapp/src/views/HomeView.vue index f05c4297..d137b05a 100644 --- a/webapp/src/views/HomeView.vue +++ b/webapp/src/views/HomeView.vue @@ -5,7 +5,7 @@