diff --git a/include/WebApi.h b/include/WebApi.h index efd0c0d..309a790 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include "WebApi_config.h" #include "WebApi_devinfo.h" #include "WebApi_dtu.h" #include "WebApi_eventlog.h" @@ -25,6 +26,7 @@ private: AsyncWebServer _server; AsyncEventSource _events; + WebApiConfigClass _webApiConfig; WebApiDevInfoClass _webApiDevInfo; WebApiDtuClass _webApiDtu; WebApiEventlogClass _webApiEventlog; diff --git a/include/WebApi_config.h b/include/WebApi_config.h new file mode 100644 index 0000000..42bea04 --- /dev/null +++ b/include/WebApi_config.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +class WebApiConfigClass { +public: + void init(AsyncWebServer* server); + void loop(); + +private: + void onConfigGet(AsyncWebServerRequest* request); + void onConfigDelete(AsyncWebServerRequest* request); + void onConfigUploadFinish(AsyncWebServerRequest* request); + void onConfigUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final); + + AsyncWebServer* _server; +}; \ No newline at end of file diff --git a/src/WebApi.cpp b/src/WebApi.cpp index 9206c1f..6de8c8f 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -17,6 +17,7 @@ void WebApiClass::init() { _server.addHandler(&_events); + _webApiConfig.init(&_server); _webApiDevInfo.init(&_server); _webApiDtu.init(&_server); _webApiEventlog.init(&_server); @@ -35,6 +36,7 @@ void WebApiClass::init() void WebApiClass::loop() { + _webApiConfig.loop(); _webApiDevInfo.loop(); _webApiDtu.loop(); _webApiEventlog.loop(); diff --git a/src/WebApi_config.cpp b/src/WebApi_config.cpp new file mode 100644 index 0000000..7bda713 --- /dev/null +++ b/src/WebApi_config.cpp @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 Thomas Basler and others + */ +#include "WebApi_config.h" +#include "ArduinoJson.h" +#include "AsyncJson.h" +#include "Configuration.h" +#include + +void WebApiConfigClass::init(AsyncWebServer* server) +{ + using std::placeholders::_1; + using std::placeholders::_2; + using std::placeholders::_3; + using std::placeholders::_4; + using std::placeholders::_5; + using std::placeholders::_6; + + _server = server; + + _server->on("/api/config/get", HTTP_GET, std::bind(&WebApiConfigClass::onConfigGet, this, _1)); + _server->on("/api/config/delete", HTTP_POST, std::bind(&WebApiConfigClass::onConfigDelete, this, _1)); + _server->on("/api/config/upload", HTTP_POST, + std::bind(&WebApiConfigClass::onConfigUploadFinish, this, _1), + std::bind(&WebApiConfigClass::onConfigUpload, this, _1, _2, _3, _4, _5, _6)); +} + +void WebApiConfigClass::loop() +{ +} + +void WebApiConfigClass::onConfigGet(AsyncWebServerRequest* request) +{ + request->send(LittleFS, CONFIG_FILENAME, String(), true); +} + +void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request) +{ + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject retMsg = response->getRoot(); + retMsg[F("type")] = F("warning"); + + if (!request->hasParam("data", true)) { + retMsg[F("message")] = F("No values found!"); + response->setLength(); + request->send(response); + return; + } + + String json = request->getParam("data", true)->value(); + + if (json.length() > 1024) { + retMsg[F("message")] = F("Data too large!"); + response->setLength(); + request->send(response); + return; + } + + DynamicJsonDocument root(1024); + DeserializationError error = deserializeJson(root, json); + + if (error) { + retMsg[F("message")] = F("Failed to parse data!"); + response->setLength(); + request->send(response); + return; + } + + if (!(root.containsKey("delete"))) { + retMsg[F("message")] = F("Values are missing!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("delete")].as() == false) { + retMsg[F("message")] = F("Not deleted anything!"); + response->setLength(); + request->send(response); + return; + } + + retMsg[F("type")] = F("success"); + retMsg[F("message")] = F("Configuration resettet. Rebooting now..."); + + response->setLength(); + request->send(response); + + LittleFS.remove(CONFIG_FILENAME); + ESP.restart(); +} + +void WebApiConfigClass::onConfigUploadFinish(AsyncWebServerRequest* request) +{ + // the request handler is triggered after the upload has finished... + // create the response, add header, and send response + + AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", "OK"); + response->addHeader("Connection", "close"); + response->addHeader("Access-Control-Allow-Origin", "*"); + request->send(response); + yield(); + delay(1000); + yield(); + ESP.restart(); +} + +void WebApiConfigClass::onConfigUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) +{ + if (!index) { + // open the file on first call and store the file handle in the request object + request->_tempFile = LittleFS.open(CONFIG_FILENAME, "w"); + } + + if (len) { + // stream the incoming chunk to the opened file + request->_tempFile.write(data, len); + } + + if (final) { + // close the file handle as the upload is now done + request->_tempFile.close(); + } +} \ No newline at end of file