From 0b5c47cd2e33bc408d15f8d1a19074d0ba43bcf0 Mon Sep 17 00:00:00 2001 From: MalteSchm Date: Sun, 26 Mar 2023 11:00:37 +0200 Subject: [PATCH] Adding enable/disable option and pin to control a switch/relais to power the Huawei PSU --- include/Configuration.h | 1 + include/Huawei_can.h | 7 ++- include/PinMapping.h | 1 + include/WebApi_Huawei.h | 7 ++- include/defaults.h | 2 + src/Configuration.cpp | 6 ++ src/Huawei_can.cpp | 18 ++++-- src/PinMapping.cpp | 5 +- src/WebApi_Huawei.cpp | 129 +++++++++++++++++++++++++++++++++------- src/WebApi_ws_live.cpp | 4 ++ 10 files changed, 150 insertions(+), 30 deletions(-) diff --git a/include/Configuration.h b/include/Configuration.h index c44355709..f0cceb743 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -119,6 +119,7 @@ struct CONFIG_T { float PowerLimiter_VoltageLoadCorrectionFactor; bool Battery_Enabled; + bool Huawei_Enabled; char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1]; bool Security_AllowReadonly; diff --git a/include/Huawei_can.h b/include/Huawei_can.h index 4018d2721..bcc541028 100644 --- a/include/Huawei_can.h +++ b/include/Huawei_can.h @@ -45,10 +45,12 @@ struct RectifierParameters_t { class HuaweiCanClass { public: - void init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs); + void init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs, uint8_t huawei_power); void loop(); void setValue(float in, uint8_t parameterType); - RectifierParameters_t& get(); + void setPower(bool power); + + RectifierParameters_t * get(); unsigned long getLastUpdate(); private: @@ -62,6 +64,7 @@ class HuaweiCanClass { SPIClass *hspi; MCP_CAN *CAN; uint8_t _huawei_irq; + uint8_t _huawei_power; }; diff --git a/include/PinMapping.h b/include/PinMapping.h index 87c216bd6..920be6c87 100644 --- a/include/PinMapping.h +++ b/include/PinMapping.h @@ -38,6 +38,7 @@ struct PinMapping_t { uint8_t huawei_clk; uint8_t huawei_irq; uint8_t huawei_cs; + uint8_t huawei_power; }; class PinMappingClass { diff --git a/include/WebApi_Huawei.h b/include/WebApi_Huawei.h index a75b7937f..1eed61391 100644 --- a/include/WebApi_Huawei.h +++ b/include/WebApi_Huawei.h @@ -2,15 +2,18 @@ #pragma once #include +#include class WebApiHuaweiClass { public: void init(AsyncWebServer* server); void loop(); - + void getJsonData(JsonObject& root); private: void onStatus(AsyncWebServerRequest* request); + void onAdminGet(AsyncWebServerRequest* request); + void onAdminPost(AsyncWebServerRequest* request); void onPost(AsyncWebServerRequest* request); - + AsyncWebServer* _server; }; \ No newline at end of file diff --git a/include/defaults.h b/include/defaults.h index 18c211e76..7fffe192a 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -109,3 +109,5 @@ #define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001 #define BATTERY_ENABLED false + +#define HUAWEI_ENABLED false diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 53a2df841..bf5b70d22 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -138,6 +138,9 @@ bool ConfigurationClass::write() JsonObject battery = doc.createNestedObject("battery"); battery["enabled"] = config.Battery_Enabled; + JsonObject huawei = doc.createNestedObject("huawei"); + huawei["enabled"] = config.Huawei_Enabled; + // Serialize JSON to file if (serializeJson(doc, f) == 0) { MessageOutput.println("Failed to write file"); @@ -303,6 +306,9 @@ bool ConfigurationClass::read() JsonObject battery = doc["battery"]; config.Battery_Enabled = battery["enabled"] | BATTERY_ENABLED; + JsonObject huawei = doc["huawei"]; + config.Huawei_Enabled = huawei["enabled"] | HUAWEI_ENABLED; + f.close(); return true; } diff --git a/src/Huawei_can.cpp b/src/Huawei_can.cpp index 2c3136da6..6c7dee277 100644 --- a/src/Huawei_can.cpp +++ b/src/Huawei_can.cpp @@ -11,7 +11,7 @@ HuaweiCanClass HuaweiCan; -void HuaweiCanClass::init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs) +void HuaweiCanClass::init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huawei_clk, uint8_t huawei_irq, uint8_t huawei_cs, uint8_t huawei_power) { hspi = new SPIClass(VSPI); @@ -32,11 +32,15 @@ void HuaweiCanClass::init(uint8_t huawei_miso, uint8_t huawei_mosi, uint8_t huaw CAN->setMode(MCP_NORMAL); // Change to normal mode to allow messages to be transmitted + pinMode(huawei_power, OUTPUT); + digitalWrite(huawei_power,HIGH); + _huawei_power = huawei_power; + } -RectifierParameters_t& HuaweiCanClass::get() +RectifierParameters_t * HuaweiCanClass::get() { - return _rp; + return &_rp; } unsigned long HuaweiCanClass::getLastUpdate() @@ -178,4 +182,10 @@ void HuaweiCanClass::setValue(float in, uint8_t parameterType) } else { MessageOutput.println("Error Sending Message..."); } -} \ No newline at end of file +} + +void HuaweiCanClass::setPower(bool power) { + digitalWrite(_huawei_power, power); +} + + diff --git a/src/PinMapping.cpp b/src/PinMapping.cpp index 79ac3c535..807d567d2 100644 --- a/src/PinMapping.cpp +++ b/src/PinMapping.cpp @@ -72,6 +72,7 @@ PinMappingClass::PinMappingClass() _pinMapping.huawei_clk = HUAWEI_PIN_SCLK; _pinMapping.huawei_cs = HUAWEI_PIN_CS; _pinMapping.huawei_irq = HUAWEI_PIN_IRQ; + _pinMapping.huawei_power = HUAWEI_PIN_POWER; } PinMapping_t& PinMappingClass::get() @@ -135,6 +136,7 @@ bool PinMappingClass::init(const String& deviceMapping) _pinMapping.huawei_clk = doc[i]["huawei"]["clk"] | HUAWEI_PIN_SCLK; _pinMapping.huawei_irq = doc[i]["huawei"]["irq"] | HUAWEI_PIN_IRQ; _pinMapping.huawei_cs = doc[i]["huawei"]["cs"] | HUAWEI_PIN_CS; + _pinMapping.huawei_power = doc[i]["huawei"]["power"] | HUAWEI_PIN_POWER; return true; } @@ -176,5 +178,6 @@ bool PinMappingClass::isValidHuaweiConfig() && _pinMapping.huawei_mosi > 0 && _pinMapping.huawei_clk > 0 && _pinMapping.huawei_irq > 0 - && _pinMapping.huawei_cs > 0; + && _pinMapping.huawei_cs > 0 + && _pinMapping.huawei_power > 0; } diff --git a/src/WebApi_Huawei.cpp b/src/WebApi_Huawei.cpp index 4b23aed5b..1b2cd5b42 100644 --- a/src/WebApi_Huawei.cpp +++ b/src/WebApi_Huawei.cpp @@ -4,6 +4,7 @@ */ #include "WebApi_Huawei.h" #include "Huawei_can.h" +#include "Configuration.h" #include "WebApi.h" #include "WebApi_errors.h" #include @@ -16,6 +17,8 @@ void WebApiHuaweiClass::init(AsyncWebServer* server) _server = server; _server->on("/api/huawei/status", HTTP_GET, std::bind(&WebApiHuaweiClass::onStatus, this, _1)); + _server->on("/api/huawei/config", HTTP_GET, std::bind(&WebApiHuaweiClass::onAdminGet, this, _1)); + _server->on("/api/huawei/config", HTTP_POST, std::bind(&WebApiHuaweiClass::onAdminPost, this, _1)); _server->on("/api/huawei/limit/config", HTTP_POST, std::bind(&WebApiHuaweiClass::onPost, this, _1)); } @@ -23,39 +26,43 @@ void WebApiHuaweiClass::loop() { } -void WebApiHuaweiClass::onStatus(AsyncWebServerRequest* request) -{ - if (!WebApi.checkCredentialsReadonly(request)) { - return; - } - - AsyncJsonResponse* response = new AsyncJsonResponse(); - JsonObject root = response->getRoot(); - - const RectifierParameters_t& rp = HuaweiCan.get(); +void WebApiHuaweiClass::getJsonData(JsonObject& root) { + const RectifierParameters_t * rp = HuaweiCan.get(); root["data_age"] = (millis() - HuaweiCan.getLastUpdate()) / 1000; - root[F("input_voltage")]["v"] = rp.input_voltage; + root[F("input_voltage")]["v"] = rp->input_voltage; root[F("input_voltage")]["u"] = "V"; - root[F("input_current")]["v"] = rp.input_current; + root[F("input_current")]["v"] = rp->input_current; root[F("input_current")]["u"] = "A"; - root[F("input_power")]["v"] = rp.input_power; + root[F("input_power")]["v"] = rp->input_power; root[F("input_power")]["u"] = "W"; - root[F("output_voltage")]["v"] = rp.output_voltage; + root[F("output_voltage")]["v"] = rp->output_voltage; root[F("output_voltage")]["u"] = "V"; - root[F("output_current")]["v"] = rp.output_current; + root[F("output_current")]["v"] = rp->output_current; root[F("output_current")]["u"] = "A"; - root[F("max_output_current")]["v"] = rp.max_output_current; + root[F("max_output_current")]["v"] = rp->max_output_current; root[F("max_output_current")]["u"] = "A"; - root[F("output_power")]["v"] = rp.output_power; + root[F("output_power")]["v"] = rp->output_power; root[F("output_power")]["u"] = "W"; - root[F("input_temp")]["v"] = rp.input_temp; + root[F("input_temp")]["v"] = rp->input_temp; root[F("input_temp")]["u"] = "°C"; - root[F("output_temp")]["v"] = rp.output_temp; + root[F("output_temp")]["v"] = rp->output_temp; root[F("output_temp")]["u"] = "°C"; - root[F("efficiency")]["v"] = rp.efficiency; + root[F("efficiency")]["v"] = rp->efficiency; root[F("efficiency")]["u"] = "%"; +} + +void WebApiHuaweiClass::onStatus(AsyncWebServerRequest* request) +{ + if (!WebApi.checkCredentialsReadonly(request)) { + return; + } + + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject root = response->getRoot(); + getJsonData(root); + response->setLength(); request->send(response); } @@ -165,4 +172,84 @@ void WebApiHuaweiClass::onPost(AsyncWebServerRequest* request) response->setLength(); request->send(response); -} \ No newline at end of file +} + + + + +void WebApiHuaweiClass::onAdminGet(AsyncWebServerRequest* request) +{ + if (!WebApi.checkCredentialsReadonly(request)) { + return; + } + + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject root = response->getRoot(); + const CONFIG_T& config = Configuration.get(); + + root[F("enabled")] = config.Huawei_Enabled; + + response->setLength(); + request->send(response); +} + +void WebApiHuaweiClass::onAdminPost(AsyncWebServerRequest* request) +{ + if (!WebApi.checkCredentials(request)) { + return; + } + + 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!"); + retMsg[F("code")] = WebApiError::GenericNoValueFound; + response->setLength(); + request->send(response); + return; + } + + String json = request->getParam("data", true)->value(); + + if (json.length() > 1024) { + retMsg[F("message")] = F("Data too large!"); + retMsg[F("code")] = WebApiError::GenericDataTooLarge; + response->setLength(); + request->send(response); + return; + } + + DynamicJsonDocument root(1024); + DeserializationError error = deserializeJson(root, json); + + if (error) { + retMsg[F("message")] = F("Failed to parse data!"); + retMsg[F("code")] = WebApiError::GenericParseError; + response->setLength(); + request->send(response); + return; + } + + if (!(root.containsKey("enabled"))) { + retMsg[F("message")] = F("Values are missing!"); + retMsg[F("code")] = WebApiError::GenericValueMissing; + response->setLength(); + request->send(response); + return; + } + + CONFIG_T& config = Configuration.get(); + config.Huawei_Enabled = root[F("enabled")].as(); + Configuration.write(); + + retMsg[F("type")] = F("success"); + retMsg[F("message")] = F("Settings saved!"); + retMsg[F("code")] = WebApiError::GenericSuccess; + + response->setLength(); + request->send(response); + + HuaweiCan.setPower(config.Huawei_Enabled); +} diff --git a/src/WebApi_ws_live.cpp b/src/WebApi_ws_live.cpp index 4ade13f77..4e35f083a 100644 --- a/src/WebApi_ws_live.cpp +++ b/src/WebApi_ws_live.cpp @@ -183,6 +183,10 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root) JsonObject vedirectObj = root.createNestedObject("vedirect"); vedirectObj[F("enabled")] = Configuration.get().Vedirect_Enabled; + + JsonObject huaweiObj = root.createNestedObject("huawei"); + huaweiObj[F("enabled")] = Configuration.get().Huawei_Enabled; + } void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, String topic)