Adding enable/disable option and pin to control a switch/relais to power the Huawei PSU
This commit is contained in:
parent
db7ad52a4d
commit
0b5c47cd2e
@ -119,6 +119,7 @@ struct CONFIG_T {
|
|||||||
float PowerLimiter_VoltageLoadCorrectionFactor;
|
float PowerLimiter_VoltageLoadCorrectionFactor;
|
||||||
|
|
||||||
bool Battery_Enabled;
|
bool Battery_Enabled;
|
||||||
|
bool Huawei_Enabled;
|
||||||
|
|
||||||
char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
|
char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
|
||||||
bool Security_AllowReadonly;
|
bool Security_AllowReadonly;
|
||||||
|
|||||||
@ -45,10 +45,12 @@ struct RectifierParameters_t {
|
|||||||
|
|
||||||
class HuaweiCanClass {
|
class HuaweiCanClass {
|
||||||
public:
|
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 loop();
|
||||||
void setValue(float in, uint8_t parameterType);
|
void setValue(float in, uint8_t parameterType);
|
||||||
RectifierParameters_t& get();
|
void setPower(bool power);
|
||||||
|
|
||||||
|
RectifierParameters_t * get();
|
||||||
unsigned long getLastUpdate();
|
unsigned long getLastUpdate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -62,6 +64,7 @@ private:
|
|||||||
SPIClass *hspi;
|
SPIClass *hspi;
|
||||||
MCP_CAN *CAN;
|
MCP_CAN *CAN;
|
||||||
uint8_t _huawei_irq;
|
uint8_t _huawei_irq;
|
||||||
|
uint8_t _huawei_power;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,7 @@ struct PinMapping_t {
|
|||||||
uint8_t huawei_clk;
|
uint8_t huawei_clk;
|
||||||
uint8_t huawei_irq;
|
uint8_t huawei_irq;
|
||||||
uint8_t huawei_cs;
|
uint8_t huawei_cs;
|
||||||
|
uint8_t huawei_power;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PinMappingClass {
|
class PinMappingClass {
|
||||||
|
|||||||
@ -2,14 +2,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <AsyncJson.h>
|
||||||
|
|
||||||
class WebApiHuaweiClass {
|
class WebApiHuaweiClass {
|
||||||
public:
|
public:
|
||||||
void init(AsyncWebServer* server);
|
void init(AsyncWebServer* server);
|
||||||
void loop();
|
void loop();
|
||||||
|
void getJsonData(JsonObject& root);
|
||||||
private:
|
private:
|
||||||
void onStatus(AsyncWebServerRequest* request);
|
void onStatus(AsyncWebServerRequest* request);
|
||||||
|
void onAdminGet(AsyncWebServerRequest* request);
|
||||||
|
void onAdminPost(AsyncWebServerRequest* request);
|
||||||
void onPost(AsyncWebServerRequest* request);
|
void onPost(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
AsyncWebServer* _server;
|
AsyncWebServer* _server;
|
||||||
|
|||||||
@ -109,3 +109,5 @@
|
|||||||
#define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001
|
#define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001
|
||||||
|
|
||||||
#define BATTERY_ENABLED false
|
#define BATTERY_ENABLED false
|
||||||
|
|
||||||
|
#define HUAWEI_ENABLED false
|
||||||
|
|||||||
@ -138,6 +138,9 @@ bool ConfigurationClass::write()
|
|||||||
JsonObject battery = doc.createNestedObject("battery");
|
JsonObject battery = doc.createNestedObject("battery");
|
||||||
battery["enabled"] = config.Battery_Enabled;
|
battery["enabled"] = config.Battery_Enabled;
|
||||||
|
|
||||||
|
JsonObject huawei = doc.createNestedObject("huawei");
|
||||||
|
huawei["enabled"] = config.Huawei_Enabled;
|
||||||
|
|
||||||
// Serialize JSON to file
|
// Serialize JSON to file
|
||||||
if (serializeJson(doc, f) == 0) {
|
if (serializeJson(doc, f) == 0) {
|
||||||
MessageOutput.println("Failed to write file");
|
MessageOutput.println("Failed to write file");
|
||||||
@ -303,6 +306,9 @@ bool ConfigurationClass::read()
|
|||||||
JsonObject battery = doc["battery"];
|
JsonObject battery = doc["battery"];
|
||||||
config.Battery_Enabled = battery["enabled"] | BATTERY_ENABLED;
|
config.Battery_Enabled = battery["enabled"] | BATTERY_ENABLED;
|
||||||
|
|
||||||
|
JsonObject huawei = doc["huawei"];
|
||||||
|
config.Huawei_Enabled = huawei["enabled"] | HUAWEI_ENABLED;
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
HuaweiCanClass HuaweiCan;
|
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);
|
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
|
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()
|
unsigned long HuaweiCanClass::getLastUpdate()
|
||||||
@ -179,3 +183,9 @@ void HuaweiCanClass::setValue(float in, uint8_t parameterType)
|
|||||||
MessageOutput.println("Error Sending Message...");
|
MessageOutput.println("Error Sending Message...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HuaweiCanClass::setPower(bool power) {
|
||||||
|
digitalWrite(_huawei_power, power);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -72,6 +72,7 @@ PinMappingClass::PinMappingClass()
|
|||||||
_pinMapping.huawei_clk = HUAWEI_PIN_SCLK;
|
_pinMapping.huawei_clk = HUAWEI_PIN_SCLK;
|
||||||
_pinMapping.huawei_cs = HUAWEI_PIN_CS;
|
_pinMapping.huawei_cs = HUAWEI_PIN_CS;
|
||||||
_pinMapping.huawei_irq = HUAWEI_PIN_IRQ;
|
_pinMapping.huawei_irq = HUAWEI_PIN_IRQ;
|
||||||
|
_pinMapping.huawei_power = HUAWEI_PIN_POWER;
|
||||||
}
|
}
|
||||||
|
|
||||||
PinMapping_t& PinMappingClass::get()
|
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_clk = doc[i]["huawei"]["clk"] | HUAWEI_PIN_SCLK;
|
||||||
_pinMapping.huawei_irq = doc[i]["huawei"]["irq"] | HUAWEI_PIN_IRQ;
|
_pinMapping.huawei_irq = doc[i]["huawei"]["irq"] | HUAWEI_PIN_IRQ;
|
||||||
_pinMapping.huawei_cs = doc[i]["huawei"]["cs"] | HUAWEI_PIN_CS;
|
_pinMapping.huawei_cs = doc[i]["huawei"]["cs"] | HUAWEI_PIN_CS;
|
||||||
|
_pinMapping.huawei_power = doc[i]["huawei"]["power"] | HUAWEI_PIN_POWER;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -176,5 +178,6 @@ bool PinMappingClass::isValidHuaweiConfig()
|
|||||||
&& _pinMapping.huawei_mosi > 0
|
&& _pinMapping.huawei_mosi > 0
|
||||||
&& _pinMapping.huawei_clk > 0
|
&& _pinMapping.huawei_clk > 0
|
||||||
&& _pinMapping.huawei_irq > 0
|
&& _pinMapping.huawei_irq > 0
|
||||||
&& _pinMapping.huawei_cs > 0;
|
&& _pinMapping.huawei_cs > 0
|
||||||
|
&& _pinMapping.huawei_power > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "WebApi_Huawei.h"
|
#include "WebApi_Huawei.h"
|
||||||
#include "Huawei_can.h"
|
#include "Huawei_can.h"
|
||||||
|
#include "Configuration.h"
|
||||||
#include "WebApi.h"
|
#include "WebApi.h"
|
||||||
#include "WebApi_errors.h"
|
#include "WebApi_errors.h"
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
@ -16,6 +17,8 @@ void WebApiHuaweiClass::init(AsyncWebServer* server)
|
|||||||
_server = server;
|
_server = server;
|
||||||
|
|
||||||
_server->on("/api/huawei/status", HTTP_GET, std::bind(&WebApiHuaweiClass::onStatus, this, _1));
|
_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));
|
_server->on("/api/huawei/limit/config", HTTP_POST, std::bind(&WebApiHuaweiClass::onPost, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +26,33 @@ void WebApiHuaweiClass::loop()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")]["u"] = "V";
|
||||||
|
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")]["u"] = "W";
|
||||||
|
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")]["u"] = "A";
|
||||||
|
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")]["u"] = "W";
|
||||||
|
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")]["u"] = "°C";
|
||||||
|
root[F("efficiency")]["v"] = rp->efficiency;
|
||||||
|
root[F("efficiency")]["u"] = "%";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void WebApiHuaweiClass::onStatus(AsyncWebServerRequest* request)
|
void WebApiHuaweiClass::onStatus(AsyncWebServerRequest* request)
|
||||||
{
|
{
|
||||||
if (!WebApi.checkCredentialsReadonly(request)) {
|
if (!WebApi.checkCredentialsReadonly(request)) {
|
||||||
@ -31,30 +61,7 @@ void WebApiHuaweiClass::onStatus(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
getJsonData(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")]["u"] = "V";
|
|
||||||
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")]["u"] = "W";
|
|
||||||
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")]["u"] = "A";
|
|
||||||
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")]["u"] = "W";
|
|
||||||
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")]["u"] = "°C";
|
|
||||||
root[F("efficiency")]["v"] = rp.efficiency;
|
|
||||||
root[F("efficiency")]["u"] = "%";
|
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -166,3 +173,83 @@ void WebApiHuaweiClass::onPost(AsyncWebServerRequest* request)
|
|||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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<bool>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@ -183,6 +183,10 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
|
|
||||||
JsonObject vedirectObj = root.createNestedObject("vedirect");
|
JsonObject vedirectObj = root.createNestedObject("vedirect");
|
||||||
vedirectObj[F("enabled")] = Configuration.get().Vedirect_Enabled;
|
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<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, String topic)
|
void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, String topic)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user