diff --git a/include/WebApi.h b/include/WebApi.h index 309a790c..1d01b62d 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -11,6 +11,7 @@ #include "WebApi_mqtt.h" #include "WebApi_network.h" #include "WebApi_ntp.h" +#include "WebApi_power.h" #include "WebApi_sysstatus.h" #include "WebApi_webapp.h" #include "WebApi_ws_live.h" @@ -36,6 +37,7 @@ private: WebApiMqttClass _webApiMqtt; WebApiNetworkClass _webApiNetwork; WebApiNtpClass _webApiNtp; + WebApiPowerClass _webApiPower; WebApiSysstatusClass _webApiSysstatus; WebApiWebappClass _webApiWebapp; WebApiWsLiveClass _webApiWsLive; diff --git a/include/WebApi_power.h b/include/WebApi_power.h new file mode 100644 index 00000000..60cabfbd --- /dev/null +++ b/include/WebApi_power.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +class WebApiPowerClass { +public: + void init(AsyncWebServer* server); + void loop(); + +private: + void onPowerPost(AsyncWebServerRequest* request); + + AsyncWebServer* _server; +}; \ No newline at end of file diff --git a/src/WebApi.cpp b/src/WebApi.cpp index 6de8c8f4..e6e3c2c6 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -27,6 +27,7 @@ void WebApiClass::init() _webApiMqtt.init(&_server); _webApiNetwork.init(&_server); _webApiNtp.init(&_server); + _webApiPower.init(&_server); _webApiSysstatus.init(&_server); _webApiWebapp.init(&_server); _webApiWsLive.init(&_server); @@ -46,6 +47,7 @@ void WebApiClass::loop() _webApiMqtt.loop(); _webApiNetwork.loop(); _webApiNtp.loop(); + _webApiPower.loop(); _webApiSysstatus.loop(); _webApiWebapp.loop(); _webApiWsLive.loop(); diff --git a/src/WebApi_power.cpp b/src/WebApi_power.cpp new file mode 100644 index 00000000..319134c2 --- /dev/null +++ b/src/WebApi_power.cpp @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 Thomas Basler and others + */ +#include "WebApi_power.h" +#include "ArduinoJson.h" +#include "AsyncJson.h" +#include "Hoymiles.h" + +void WebApiPowerClass::init(AsyncWebServer* server) +{ + using std::placeholders::_1; + + _server = server; + + _server->on("/api/power/config", HTTP_POST, std::bind(&WebApiPowerClass::onPowerPost, this, _1)); +} + +void WebApiPowerClass::loop() +{ +} + +void WebApiPowerClass::onPowerPost(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("serial") + && root.containsKey("power"))) { + retMsg[F("message")] = F("Values are missing!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("serial")].as() == 0) { + retMsg[F("message")] = F("Serial must be a number > 0!"); + response->setLength(); + request->send(response); + return; + } + + uint64_t serial = strtoll(root[F("serial")].as().c_str(), NULL, 16); + uint16_t power = root[F("power")].as(); + + auto inv = Hoymiles.getInverterBySerial(serial); + if (inv == nullptr) { + retMsg[F("message")] = F("Invalid inverter specified!"); + response->setLength(); + request->send(response); + return; + } + + inv->sendPowerControlRequest(Hoymiles.getRadio(), power); + + retMsg[F("type")] = F("success"); + retMsg[F("message")] = F("Settings saved!"); + + response->setLength(); + request->send(response); +} \ No newline at end of file