mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-11 07:01:38 +02:00
0.8.89
* merge
This commit is contained in:
parent
053a2e0079
commit
1548a00520
8 changed files with 1622 additions and 244 deletions
86
src/app.cpp
86
src/app.cpp
|
@ -14,7 +14,11 @@
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
app::app() : ah::Scheduler {} {
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
memset(mVersion, 0, sizeof(char) * 17);
|
||||
#else
|
||||
memset(mVersion, 0, sizeof(char) * 12);
|
||||
#endif
|
||||
memset(mVersionModules, 0, sizeof(char) * 12);
|
||||
}
|
||||
|
||||
|
@ -118,17 +122,21 @@ void app::setup() {
|
|||
|
||||
esp_task_wdt_reset();
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
// TODO: aufräumen
|
||||
// if (mConfig->plugin.zeroExport.enabled) {
|
||||
mZeroExport.setup(&mConfig->plugin.zeroExport, &mSys, mConfig);
|
||||
// }
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
#if defined(ENABLE_HISTORY)
|
||||
mHistory.setup(this, &mSys, mConfig, &mTimestamp);
|
||||
#endif /*ENABLE_HISTORY*/
|
||||
|
||||
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
|
||||
|
||||
// ZeroExport
|
||||
if (mConfig->plugin.zexport.enabled) {
|
||||
mzExport.setup(&mConfig->plugin.zexport, &mSys, mConfig);
|
||||
}
|
||||
|
||||
#if !defined(ETHERNET)
|
||||
//mImprov.setup(this, mConfig->sys.deviceName, mVersion);
|
||||
#endif
|
||||
|
@ -164,6 +172,15 @@ void app::loop(void) {
|
|||
if (mMqttEnabled && mNetworkConnected)
|
||||
mMqtt.loop();
|
||||
#endif
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
if(mConfig->nrf.enabled || mConfig->cmt.enabled) {
|
||||
mZeroExport.loop();
|
||||
}
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
yield();
|
||||
}
|
||||
|
||||
|
@ -197,11 +214,14 @@ void app::regularTickers(void) {
|
|||
everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp");
|
||||
#endif
|
||||
|
||||
// ZeroExport
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
if (mConfig->plugin.zexport.enabled)
|
||||
everySec(std::bind(&ZeroExportType::tickerSecond, &mzExport), "zExport");
|
||||
// TODO: aufräumen
|
||||
// if (mConfig->plugin.zeroExport.enabled) {
|
||||
everySec(std::bind(&ZeroExportType::tickerSecond, &mZeroExport), "ZeroExport");
|
||||
// }
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart");
|
||||
#if !defined(ETHERNET)
|
||||
|
@ -458,9 +478,15 @@ void app::tickSend(void) {
|
|||
mCommunication.add(iv, cmd);
|
||||
});
|
||||
|
||||
#if defined(ESP32)
|
||||
if(mConfig->nrf.enabled || mConfig->cmt.enabled) zeroexport();
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
// TODO: aufräumen
|
||||
if(mConfig->nrf.enabled || mConfig->cmt.enabled) {
|
||||
mZeroExport.loop();
|
||||
// zeroexport();
|
||||
}
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -521,7 +547,11 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::resetSystem(void) {
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
snprintf(mVersion, sizeof(mVersion), "zero-%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
#else
|
||||
snprintf(mVersion, sizeof(mVersion), "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
#endif
|
||||
snprintf(mVersionModules, sizeof(mVersionModules), "%s",
|
||||
#ifdef ENABLE_PROMETHEUS_EP
|
||||
"P"
|
||||
|
@ -635,37 +665,45 @@ void app::updateLed(void) {
|
|||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(ESP32)
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
void app::zeroexport() {
|
||||
if (!mConfig->plugin.zexport.enabled ||
|
||||
!mSys.getInverterByPos(mConfig->plugin.zexport.Iv)->isProducing()) { // check if plugin is enabled && indicate to send new value
|
||||
mConfig->plugin.zexport.lastTime = millis(); // set last timestamp
|
||||
return;
|
||||
// TODO: aufräumen
|
||||
// TODO: umziehen nach loop
|
||||
|
||||
|
||||
/*
|
||||
|
||||
if (!mConfig->plugin.zeroExport.enabled ||
|
||||
!mSys.getInverterByPos(mConfig->plugin.zeroExport.Iv)->isProducing()) { // check if plugin is enabled && indicate to send new value
|
||||
mConfig->plugin.zeroExport.lastTime = millis(); // set last timestamp
|
||||
return;
|
||||
}
|
||||
|
||||
if (millis() - mConfig->plugin.zexport.lastTime > mConfig->plugin.zexport.count_avg * 1000UL)
|
||||
if (millis() - mConfig->plugin.zeroExport.lastTime > mConfig->plugin.zeroExport.count_avg * 1000UL)
|
||||
{
|
||||
Inverter<> *iv = mSys.getInverterByPos(mConfig->plugin.zexport.Iv);
|
||||
Inverter<> *iv = mSys.getInverterByPos(mConfig->plugin.zeroExport.Iv);
|
||||
|
||||
DynamicJsonDocument doc(512);
|
||||
JsonObject object = doc.to<JsonObject>();
|
||||
|
||||
double nValue = round(mzExport.getPowertoSetnewValue());
|
||||
double nValue = round(mZeroExport.getPowertoSetnewValue());
|
||||
double twoPerVal = nValue <= (iv->getMaxPower() / 100 * 2 );
|
||||
|
||||
if(mConfig->plugin.zexport.two_percent && (nValue <= twoPerVal))
|
||||
if(mConfig->plugin.zeroExport.two_percent && (nValue <= twoPerVal))
|
||||
nValue = twoPerVal;
|
||||
|
||||
if(mConfig->plugin.zexport.max_power <= nValue)
|
||||
nValue = mConfig->plugin.zexport.max_power;
|
||||
if(mConfig->plugin.zeroExport.max_power <= nValue)
|
||||
nValue = mConfig->plugin.zeroExport.max_power;
|
||||
|
||||
if(iv->actPowerLimit == nValue) {
|
||||
mConfig->plugin.zexport.lastTime = millis(); // set last timestamp
|
||||
mConfig->plugin.zeroExport.lastTime = millis(); // set last timestamp
|
||||
return; // if PowerLimit same as befor, then skip
|
||||
}
|
||||
|
||||
object["val"] = nValue;
|
||||
object["id"] = mConfig->plugin.zexport.Iv;
|
||||
object["id"] = mConfig->plugin.zeroExport.Iv;
|
||||
object["path"] = "ctrl";
|
||||
object["cmd"] = "limit_nonpersistent_absolute";
|
||||
|
||||
|
@ -674,7 +712,9 @@ void app::zeroexport() {
|
|||
DPRINTLN(DBG_INFO, data);
|
||||
mApi.ctrlRequest(object);
|
||||
|
||||
mConfig->plugin.zexport.lastTime = millis(); // set last timestamp
|
||||
mConfig->plugin.zeroExport.lastTime = millis(); // set last timestamp
|
||||
}
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
|
14
src/app.h
14
src/app.h
|
@ -77,10 +77,12 @@ typedef Simulator<HmSystemType> SimulatorType;
|
|||
typedef Display<HmSystemType, Radio> DisplayType;
|
||||
#endif
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
#include "plugins/zeroExport/zeroExport.h"
|
||||
typedef ZeroExport<HmSystemType> ZeroExportType;
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
class app : public IApp, public ah::Scheduler {
|
||||
public:
|
||||
|
@ -353,9 +355,11 @@ class app : public IApp, public ah::Scheduler {
|
|||
void setupLed();
|
||||
void updateLed();
|
||||
|
||||
#if defined(ESP32)
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
void zeroexport();
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
void tickReboot(void) {
|
||||
DPRINTLN(DBG_INFO, F("Rebooting..."));
|
||||
|
@ -423,7 +427,11 @@ class app : public IApp, public ah::Scheduler {
|
|||
CmtRadio<> mCmtRadio;
|
||||
#endif
|
||||
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
char mVersion[17];
|
||||
#else
|
||||
char mVersion[12];
|
||||
#endif
|
||||
char mVersionModules[12];
|
||||
settings mSettings;
|
||||
settings_t *mConfig = nullptr;
|
||||
|
@ -460,9 +468,11 @@ class app : public IApp, public ah::Scheduler {
|
|||
SimulatorType mSimulator;
|
||||
#endif /*ENABLE_SIMULATOR*/
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
ZeroExportType mzExport;
|
||||
ZeroExportType mZeroExport;
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
};
|
||||
|
||||
#endif /*__APP_H__*/
|
||||
|
|
|
@ -139,24 +139,6 @@ typedef struct {
|
|||
uint16_t interval;
|
||||
} cfgMqtt_t;
|
||||
|
||||
/* Zero Export section */
|
||||
#if defined(ESP32)
|
||||
typedef struct {
|
||||
char monitor_url[ZEXPORT_ADDR_LEN];
|
||||
char json_path[ZEXPORT_ADDR_LEN];
|
||||
uint8_t query_device; // 0 - Tibber, 1 - Shelly, 2 - other (rs232?)
|
||||
uint8_t Iv; // saves the inverter that is used for regulation
|
||||
bool enabled;
|
||||
float power_avg;
|
||||
uint8_t count_avg;
|
||||
double total_power;
|
||||
unsigned long lastTime; // tic toc
|
||||
double max_power;
|
||||
bool two_percent; // ask if not go lower then 2%
|
||||
char tibber_pw[10]; // needed for tibber QWGH-ED12
|
||||
} cfgzeroExport_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
char name[MAX_NAME_LENGTH];
|
||||
|
@ -203,14 +185,133 @@ typedef struct {
|
|||
} display_t;
|
||||
#endif
|
||||
|
||||
// Plugin ZeroExport
|
||||
#define ZEROEXPORT_MAX_GROUPS 6
|
||||
#define ZEROEXPORT_GROUP_MAX_LEN_NAME 25
|
||||
#define ZEROEXPORT_GROUP_MAX_LEN_PM_URL 100
|
||||
#define ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH 100
|
||||
#define ZEROEXPORT_GROUP_MAX_LEN_PM_USER 25
|
||||
#define ZEROEXPORT_GROUP_MAX_LEN_PM_PASS 25
|
||||
#define ZEROEXPORT_GROUP_MAX_INVERTERS 3
|
||||
#define ZEROEXPORT_POWERMETER_MAX_ERRORS 5
|
||||
#define ZEROEXPORT_DEF_INV_WAITINGTIME_MS 10000
|
||||
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
enum class zeroExportState : uint8_t {
|
||||
RESET, GETPOWERMETER, GETINVERTERPOWER, FINISH
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
None = 0,
|
||||
Shelly = 1,
|
||||
Tasmota = 2,
|
||||
Mqtt = 3,
|
||||
Hichi = 4,
|
||||
Tibber = 5,
|
||||
} zeroExportPowermeterType_t;
|
||||
/*
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t ip;
|
||||
uint8_t url;
|
||||
bool login;
|
||||
uint8_t username;
|
||||
uint8_t password;
|
||||
uint8_t group;
|
||||
uint8_t phase;
|
||||
uint16_t nextRun;
|
||||
uint16_t interval;
|
||||
uint8_t error;
|
||||
uint16_t power;
|
||||
} zeroExportPowermeter_t;
|
||||
*/
|
||||
typedef enum {
|
||||
Sum = 0,
|
||||
L1 = 1,
|
||||
L2 = 2,
|
||||
L3 = 3,
|
||||
L1Sum = 4,
|
||||
L2Sum = 5,
|
||||
L3Sum = 6,
|
||||
} zeroExportInverterTarget_t;
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
int8_t id;
|
||||
int8_t target;
|
||||
bool twoPercent;
|
||||
uint16_t powerMax;
|
||||
|
||||
|
||||
float power;
|
||||
uint16_t limit;
|
||||
bool limitAck;
|
||||
float dcVoltage;
|
||||
// uint16_t waitingTime;
|
||||
} zeroExportGroupInverter_t;
|
||||
|
||||
typedef struct {
|
||||
// General
|
||||
bool enabled;
|
||||
char name[ZEROEXPORT_GROUP_MAX_LEN_NAME];
|
||||
// Powermeter
|
||||
uint8_t pm_type;
|
||||
char pm_url[ZEROEXPORT_GROUP_MAX_LEN_PM_URL];
|
||||
char pm_jsonPath[ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH];
|
||||
char pm_user[ZEROEXPORT_GROUP_MAX_LEN_PM_USER];
|
||||
char pm_pass[ZEROEXPORT_GROUP_MAX_LEN_PM_PASS];
|
||||
// Inverters
|
||||
zeroExportGroupInverter_t inverters[ZEROEXPORT_GROUP_MAX_INVERTERS];
|
||||
// Battery
|
||||
bool battEnabled;
|
||||
float battVoltageOn;
|
||||
float battVoltageOff;
|
||||
// Advanced
|
||||
uint8_t refresh;
|
||||
uint8_t powerTolerance;
|
||||
uint16_t powerMax;
|
||||
|
||||
|
||||
zeroExportState state;
|
||||
unsigned long lastRun;
|
||||
float pmPower;
|
||||
float pmPowerL1;
|
||||
float pmPowerL2;
|
||||
float pmPowerL3;
|
||||
// uint16_t power; // Aktueller Verbrauch
|
||||
// uint16_t powerLimitAkt; // Aktuelles Limit
|
||||
// uint16_t powerHyst; // Hysterese
|
||||
} zeroExportGroup_t;
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
zeroExportGroup_t groups[ZEROEXPORT_MAX_GROUPS];
|
||||
|
||||
|
||||
|
||||
// uint8_t query_device; // 0 - Tibber, 1 - Shelly, 2 - other (rs232?)
|
||||
// char monitor_url[ZEXPORT_ADDR_LEN];
|
||||
// char json_path[ZEXPORT_ADDR_LEN];
|
||||
// char tibber_pw[10]; // needed for tibber QWGH-ED12
|
||||
// uint8_t Iv; // saves the inverter that is used for regulation
|
||||
// float power_avg;
|
||||
// uint8_t count_avg;
|
||||
// double total_power;
|
||||
// unsigned long lastTime; // tic toc
|
||||
// double max_power;
|
||||
// bool two_percent; // ask if not go lower then 2%
|
||||
} zeroExport_t;
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
typedef struct {
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
display_t display;
|
||||
#endif
|
||||
char customLink[MAX_CUSTOM_LINK_LEN];
|
||||
char customLinkText[MAX_CUSTOM_LINK_TEXT_LEN];
|
||||
#if defined(ESP32)
|
||||
cfgzeroExport_t zexport;
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
zeroExport_t zeroExport;
|
||||
#endif
|
||||
} plugins_t;
|
||||
|
||||
|
@ -315,7 +416,6 @@ class settings {
|
|||
if(root.containsKey(F("nrf"))) jsonNrf(root[F("nrf")]);
|
||||
#if defined(ESP32)
|
||||
if(root.containsKey(F("cmt"))) jsonCmt(root[F("cmt")]);
|
||||
if(root.containsKey(F("zeroExport"))) jsonzeroExport(root[F("zeroExport")]);
|
||||
#endif
|
||||
if(root.containsKey(F("ntp"))) jsonNtp(root[F("ntp")]);
|
||||
if(root.containsKey(F("sun"))) jsonSun(root[F("sun")]);
|
||||
|
@ -345,7 +445,6 @@ class settings {
|
|||
jsonNrf(root[F("nrf")].to<JsonObject>(), true);
|
||||
#if defined(ESP32)
|
||||
jsonCmt(root[F("cmt")].to<JsonObject>(), true);
|
||||
jsonzeroExport(root.createNestedObject(F("zeroExport")), true);
|
||||
#endif
|
||||
jsonNtp(root[F("ntp")].to<JsonObject>(), true);
|
||||
jsonSun(root[F("sun")].to<JsonObject>(), true);
|
||||
|
@ -473,22 +572,7 @@ class settings {
|
|||
snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC);
|
||||
mCfg.mqtt.interval = 0; // off
|
||||
|
||||
// Zero-Export
|
||||
#if defined(ESP32)
|
||||
snprintf(mCfg.plugin.zexport.monitor_url, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
snprintf(mCfg.plugin.zexport.tibber_pw, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
snprintf(mCfg.plugin.zexport.json_path, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
mCfg.plugin.zexport.enabled = false;
|
||||
mCfg.plugin.zexport.count_avg = 10;
|
||||
mCfg.plugin.zexport.lastTime = millis(); // do not change!
|
||||
|
||||
mCfg.plugin.zexport.query_device = 1; // Standard shelly
|
||||
mCfg.plugin.zexport.power_avg = 10;
|
||||
mCfg.plugin.zexport.Iv = 0;
|
||||
mCfg.plugin.zexport.max_power = 600; // Max 600W to stay safe
|
||||
mCfg.plugin.zexport.two_percent = true;
|
||||
#endif
|
||||
|
||||
mCfg.inst.sendInterval = SEND_INTERVAL;
|
||||
mCfg.inst.rstYieldMidNight = false;
|
||||
mCfg.inst.rstValsNotAvail = false;
|
||||
mCfg.inst.rstValsCommStop = false;
|
||||
|
@ -523,6 +607,77 @@ class settings {
|
|||
mCfg.plugin.display.disp_dc = DEF_PIN_OFF;
|
||||
mCfg.plugin.display.pirPin = DEF_PIN_OFF;
|
||||
#endif
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
mCfg.plugin.zeroExport.enabled = false;
|
||||
for(uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||
// General
|
||||
mCfg.plugin.zeroExport.groups[group].enabled = false;
|
||||
snprintf(mCfg.plugin.zeroExport.groups[group].name, ZEROEXPORT_GROUP_MAX_LEN_NAME, "%s", DEF_ZEXPORT);
|
||||
// Powermeter
|
||||
mCfg.plugin.zeroExport.groups[group].pm_type = zeroExportPowermeterType_t::None;
|
||||
snprintf(mCfg.plugin.zeroExport.groups[group].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", DEF_ZEXPORT);
|
||||
snprintf(mCfg.plugin.zeroExport.groups[group].pm_jsonPath, ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH, "%s", DEF_ZEXPORT);
|
||||
snprintf(mCfg.plugin.zeroExport.groups[group].pm_user, ZEROEXPORT_GROUP_MAX_LEN_PM_USER, "%s", DEF_ZEXPORT);
|
||||
snprintf(mCfg.plugin.zeroExport.groups[group].pm_pass, ZEROEXPORT_GROUP_MAX_LEN_PM_PASS, "%s", DEF_ZEXPORT);
|
||||
// Inverters
|
||||
for(uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
|
||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].enabled = false;
|
||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].id = -1;
|
||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].target = -1;
|
||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].twoPercent = false;
|
||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].powerMax = 600;
|
||||
}
|
||||
// Battery
|
||||
mCfg.plugin.zeroExport.groups[group].battEnabled = false;
|
||||
mCfg.plugin.zeroExport.groups[group].battVoltageOn = 0;
|
||||
mCfg.plugin.zeroExport.groups[group].battVoltageOff = 0;
|
||||
// Advanced
|
||||
mCfg.plugin.zeroExport.groups[group].refresh = 10;
|
||||
mCfg.plugin.zeroExport.groups[group].powerTolerance = 10;
|
||||
mCfg.plugin.zeroExport.groups[group].powerMax = 600;
|
||||
//
|
||||
mCfg.plugin.zeroExport.groups[group].state = zeroExportState::RESET;
|
||||
mCfg.plugin.zeroExport.groups[group].lastRun = 0;
|
||||
mCfg.plugin.zeroExport.groups[group].pmPower = 0;
|
||||
mCfg.plugin.zeroExport.groups[group].pmPowerL1 = 0;
|
||||
mCfg.plugin.zeroExport.groups[group].pmPowerL2 = 0;
|
||||
mCfg.plugin.zeroExport.groups[group].pmPowerL3 = 0;
|
||||
|
||||
}
|
||||
// snprintf(mCfg.plugin.zeroExport.monitor_url, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
// snprintf(mCfg.plugin.zeroExport.tibber_pw, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
// snprintf(mCfg.plugin.zeroExport.json_path, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
// mCfg.plugin.zeroExport.enabled = false;
|
||||
// mCfg.plugin.zeroExport.count_avg = 10;
|
||||
// mCfg.plugin.zeroExport.lastTime = millis(); // do not change!
|
||||
|
||||
// mCfg.plugin.zeroExport.query_device = 1; // Standard shelly
|
||||
// mCfg.plugin.zeroExport.power_avg = 10;
|
||||
// mCfg.plugin.zeroExport.Iv = 0;
|
||||
// mCfg.plugin.zeroExport.max_power = 600; // Max 600W to stay safe
|
||||
// mCfg.plugin.zeroExport.two_percent = true;
|
||||
// uint8_t ip;
|
||||
// uint8_t url;
|
||||
// bool login;
|
||||
// uint8_t username;
|
||||
// uint8_t password;
|
||||
// snprintf(mCfg.plugin.zeroExport.monitor_url, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
// snprintf(mCfg.plugin.zeroExport.monitor_url, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
// snprintf(mCfg.plugin.zeroExport.monitor_url, ZEXPORT_ADDR_LEN, "%s", DEF_ZEXPORT);
|
||||
// uint8_t group;
|
||||
// uint8_t phase;
|
||||
// mCfg.plugin.zeroExport.groups[group].powermeter.nextRun = 0;
|
||||
// mCfg.plugin.zeroExport.groups[group].powermeter.interval = 10000;
|
||||
// mCfg.plugin.zeroExport.groups[group].powermeter.error = 0;
|
||||
// mCfg.plugin.zeroExport.groups[group].powermeter.power = 0;
|
||||
// mCfg.plugin.zeroExport.groups[group].inverters[inv].waitingTime = 0;
|
||||
// mCfg.plugin.zeroExport.groups[group].inverters[inv].limit = -1;
|
||||
// mCfg.plugin.zeroExport.groups[group].inverters[inv].limitAck = false;
|
||||
// Plugin ZeroExport - Ende
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void loadAddedDefaults() {
|
||||
|
@ -737,40 +892,6 @@ class settings {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(ESP32)
|
||||
void jsonzeroExport(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("en_zeroexport")] = (bool) mCfg.plugin.zexport.enabled;
|
||||
obj[F("monitor_url")] = mCfg.plugin.zexport.monitor_url;
|
||||
obj[F("json_path")] = mCfg.plugin.zexport.json_path;
|
||||
obj[F("Iv")] = mCfg.plugin.zexport.Iv;
|
||||
obj[F("power_avg")] = mCfg.plugin.zexport.power_avg;
|
||||
obj[F("query_device")] = mCfg.plugin.zexport.query_device;
|
||||
obj[F("count_avg")] = mCfg.plugin.zexport.count_avg;
|
||||
obj[F("max_power")] = mCfg.plugin.zexport.max_power;
|
||||
obj[F("total_power")] = mCfg.plugin.zexport.total_power;
|
||||
obj[F("two_percent")] = (bool)mCfg.plugin.zexport.two_percent;
|
||||
}
|
||||
else
|
||||
{
|
||||
getVal<bool>(obj, F("en_zeroexport"), &mCfg.plugin.zexport.enabled);
|
||||
getVal<bool>(obj, F("two_percent"), &mCfg.plugin.zexport.two_percent);
|
||||
|
||||
getChar(obj, F("monitor_url"), mCfg.plugin.zexport.monitor_url, ZEXPORT_ADDR_LEN);
|
||||
getChar(obj, F("json_path"), mCfg.plugin.zexport.json_path, ZEXPORT_ADDR_LEN);
|
||||
|
||||
getVal<uint8_t>(obj, F("Iv"), &mCfg.plugin.zexport.Iv);
|
||||
getVal<uint8_t>(obj, F("count_avg"), &mCfg.plugin.zexport.count_avg);
|
||||
getVal<double>(obj, F("max_power"), &mCfg.plugin.zexport.max_power);
|
||||
|
||||
getVal<float>(obj, F("power_avg"), &mCfg.plugin.zexport.power_avg);
|
||||
getVal<uint8_t>(obj, F("query_device"), &mCfg.plugin.zexport.query_device);
|
||||
|
||||
getVal<double>(obj, F("total_power"), &mCfg.plugin.zexport.total_power);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void jsonLed(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("0")] = mCfg.led.led[0];
|
||||
|
@ -787,6 +908,116 @@ class settings {
|
|||
}
|
||||
}
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
|
||||
void jsonZeroExportGroupInverter(JsonObject obj, uint8_t group, uint8_t inv, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("enabled")] = mCfg.plugin.zeroExport.groups[group].inverters[inv].enabled;
|
||||
obj[F("id")] = mCfg.plugin.zeroExport.groups[group].inverters[inv].id;
|
||||
obj[F("target")] = mCfg.plugin.zeroExport.groups[group].inverters[inv].target;
|
||||
obj[F("twoPercent")] = mCfg.plugin.zeroExport.groups[group].inverters[inv].twoPercent;
|
||||
obj[F("powerMax")] = mCfg.plugin.zeroExport.groups[group].inverters[inv].powerMax;
|
||||
} else {
|
||||
if (obj.containsKey(F("enabled")))
|
||||
getVal<bool>(obj, F("enabled"), &mCfg.plugin.zeroExport.groups[group].inverters[inv].enabled);
|
||||
if (obj.containsKey(F("id")))
|
||||
getVal<int8_t>(obj, F("id"), &mCfg.plugin.zeroExport.groups[group].inverters[inv].id);
|
||||
if (obj.containsKey(F("target")))
|
||||
getVal<int8_t>(obj, F("target"), &mCfg.plugin.zeroExport.groups[group].inverters[inv].target);
|
||||
if (obj.containsKey(F("twoPercent")))
|
||||
getVal<bool>(obj, F("twoPercent"), &mCfg.plugin.zeroExport.groups[group].inverters[inv].twoPercent);
|
||||
if (obj.containsKey(F("powerMax")))
|
||||
getVal<uint16_t>(obj, F("powerMax"), &mCfg.plugin.zeroExport.groups[group].inverters[inv].powerMax);
|
||||
}
|
||||
}
|
||||
|
||||
void jsonZeroExportGroup(JsonObject obj, uint8_t group, bool set = false) {
|
||||
if(set) {
|
||||
// General
|
||||
obj[F("enabled")] = mCfg.plugin.zeroExport.groups[group].enabled;
|
||||
obj[F("name")] = mCfg.plugin.zeroExport.groups[group].name;
|
||||
// Powermeter
|
||||
obj[F("pm_type")] = mCfg.plugin.zeroExport.groups[group].pm_type;
|
||||
obj[F("pm_url")] = mCfg.plugin.zeroExport.groups[group].pm_url;
|
||||
obj[F("pm_jsonPath")] = mCfg.plugin.zeroExport.groups[group].pm_jsonPath;
|
||||
obj[F("pm_user")] = mCfg.plugin.zeroExport.groups[group].pm_user;
|
||||
obj[F("pm_pass")] = mCfg.plugin.zeroExport.groups[group].pm_pass;
|
||||
// Inverters
|
||||
JsonArray invArr = obj.createNestedArray(F("inverters"));
|
||||
for(uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
|
||||
jsonZeroExportGroupInverter(invArr.createNestedObject(), group, inv, set);
|
||||
}
|
||||
// Battery
|
||||
obj[F("battEnabled")] = mCfg.plugin.zeroExport.groups[group].battEnabled;
|
||||
obj[F("battVoltageOn")] = mCfg.plugin.zeroExport.groups[group].battVoltageOn;
|
||||
obj[F("battVoltageOff")] = mCfg.plugin.zeroExport.groups[group].battVoltageOff;
|
||||
// Advanced
|
||||
obj[F("refresh")] = mCfg.plugin.zeroExport.groups[group].refresh;
|
||||
obj[F("powerTolerance")] = mCfg.plugin.zeroExport.groups[group].powerTolerance;
|
||||
obj[F("powerMax")] = mCfg.plugin.zeroExport.groups[group].powerMax;
|
||||
} else {
|
||||
// General
|
||||
if (obj.containsKey(F("enabled")))
|
||||
getVal<bool>(obj, F("enabled"), &mCfg.plugin.zeroExport.groups[group].enabled);
|
||||
if (obj.containsKey(F("name")))
|
||||
getChar(obj, F("name"), mCfg.plugin.zeroExport.groups[group].name, ZEXPORT_ADDR_LEN);
|
||||
// Powermeter
|
||||
if (obj.containsKey(F("pm_type")))
|
||||
getVal<uint8_t>(obj, F("pm_type"), &mCfg.plugin.zeroExport.groups[group].pm_type);
|
||||
if (obj.containsKey(F("pm_url")))
|
||||
getChar(obj, F("pm_url"), mCfg.plugin.zeroExport.groups[group].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL);
|
||||
if (obj.containsKey(F("pm_jsonPath")))
|
||||
getChar(obj, F("pm_jsonPath"), mCfg.plugin.zeroExport.groups[group].pm_jsonPath, ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH);
|
||||
if (obj.containsKey(F("pm_user")))
|
||||
getChar(obj, F("pm_user"), mCfg.plugin.zeroExport.groups[group].pm_user, ZEROEXPORT_GROUP_MAX_LEN_PM_USER);
|
||||
if (obj.containsKey(F("pm_pass")))
|
||||
getChar(obj, F("pm_pass"), mCfg.plugin.zeroExport.groups[group].pm_pass, ZEROEXPORT_GROUP_MAX_LEN_PM_PASS);
|
||||
// Inverters
|
||||
if (obj.containsKey(F("inverters"))) {
|
||||
for(uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
|
||||
jsonZeroExportGroupInverter(obj[F("inverters")][inv], group, inv, set);
|
||||
}
|
||||
}
|
||||
// Battery
|
||||
if (obj.containsKey(F("battEnabled")))
|
||||
getVal<bool>(obj, F("battEnabled"), &mCfg.plugin.zeroExport.groups[group].battEnabled);
|
||||
if (obj.containsKey(F("battVoltageOn")))
|
||||
getVal<float>(obj, F("battVoltageOn"), &mCfg.plugin.zeroExport.groups[group].battVoltageOn);
|
||||
if (obj.containsKey(F("battVoltageOff")))
|
||||
getVal<float>(obj, F("battVoltageOff"), &mCfg.plugin.zeroExport.groups[group].battVoltageOff);
|
||||
// Advanced
|
||||
if (obj.containsKey(F("refresh")))
|
||||
getVal<uint8_t>(obj, F("refresh"), &mCfg.plugin.zeroExport.groups[group].refresh);
|
||||
if (obj.containsKey(F("powerTolerance")))
|
||||
getVal<uint8_t>(obj, F("powerTolerance"), &mCfg.plugin.zeroExport.groups[group].powerTolerance);
|
||||
if (obj.containsKey(F("powerMax")))
|
||||
getVal<uint16_t>(obj, F("powerMax"), &mCfg.plugin.zeroExport.groups[group].powerMax);
|
||||
}
|
||||
}
|
||||
|
||||
void jsonZeroExport(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
obj[F("enabled")] = mCfg.plugin.zeroExport.enabled;
|
||||
JsonArray grpArr = obj.createNestedArray(F("groups"));
|
||||
for(uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||
jsonZeroExportGroup(grpArr.createNestedObject(), group, set);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj.containsKey(F("enabled")))
|
||||
getVal<bool>(obj, F("enabled"), &mCfg.plugin.zeroExport.enabled);
|
||||
if (obj.containsKey(F("groups"))) {
|
||||
for(uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||
jsonZeroExportGroup(obj[F("groups")][group], group, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
void jsonPlugin(JsonObject obj, bool set = false) {
|
||||
if(set) {
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
|
@ -810,6 +1041,11 @@ class settings {
|
|||
#endif
|
||||
obj[F("cst_lnk")] = mCfg.plugin.customLink;
|
||||
obj[F("cst_lnk_txt")] = mCfg.plugin.customLinkText;
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
jsonZeroExport(obj.createNestedObject("zeroExport"), set);
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
} else {
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
JsonObject disp = obj["disp"];
|
||||
|
@ -832,6 +1068,11 @@ class settings {
|
|||
#endif
|
||||
getChar(obj, F("cst_lnk"), mCfg.plugin.customLink, MAX_CUSTOM_LINK_LEN);
|
||||
getChar(obj, F("cst_lnk_txt"), mCfg.plugin.customLinkText, MAX_CUSTOM_LINK_TEXT_LEN);
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
jsonZeroExport(obj["zeroExport"], set);
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#if defined(ESP32)
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
|
||||
#ifndef __ZEROEXPORT__
|
||||
#define __ZEROEXPORT__
|
||||
|
@ -8,29 +8,232 @@
|
|||
#include "AsyncJson.h"
|
||||
|
||||
#include "SML.h"
|
||||
|
||||
template <class HMSYSTEM>
|
||||
|
||||
class ZeroExport {
|
||||
public:
|
||||
ZeroExport() { }
|
||||
|
||||
void setup(cfgzeroExport_t *cfg, HMSYSTEM *sys, settings_t *config) {
|
||||
// bool enabled; // true
|
||||
// uint8_t query_device; // 0 - Tibber, 1 - Shelly, 2 - other (rs232?)
|
||||
// char monitor_url[ZEXPORT_ADDR_LEN]; //
|
||||
// char json_path[ZEXPORT_ADDR_LEN]; //
|
||||
// char tibber_pw[10]; //
|
||||
// uint8_t Iv; // Id gemäß anlegen
|
||||
// float power_avg; //
|
||||
// uint8_t count_avg; //
|
||||
// double total_power; //
|
||||
// unsigned long lastTime; // tic toc
|
||||
// double max_power; // 600 W
|
||||
// bool two_percent; // P >= 2% von max_power
|
||||
|
||||
// mCfg // -> siehe oben
|
||||
// mSys // ->
|
||||
// mConfig // ->
|
||||
|
||||
public:
|
||||
ZeroExport() {
|
||||
mIsInitialized = false;
|
||||
}
|
||||
|
||||
void setup(zeroExport_t *cfg, HMSYSTEM *sys, settings_t *config) {
|
||||
mCfg = cfg;
|
||||
mSys = sys;
|
||||
mConfig = config;
|
||||
|
||||
if (!mCfg->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mIsInitialized = true;
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
if ((!mIsInitialized) || (!mCfg->enabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||
if (!mCfg->groups[group].enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (mCfg->groups[group].state) {
|
||||
case zeroExportState::RESET:
|
||||
//DBGPRINT(F("State::RESET: "));
|
||||
//DBGPRINTLN(String(group));
|
||||
mCfg->groups[group].lastRun = millis();
|
||||
// Weiter zum nächsten State
|
||||
mCfg->groups[group].state = zeroExportState::GETPOWERMETER;
|
||||
break;
|
||||
case zeroExportState::GETPOWERMETER:
|
||||
if ((millis() - mCfg->groups[group].lastRun) > (mCfg->groups[group].refresh * 1000UL)) {
|
||||
//DBGPRINT(F("State::GETPOWERMETER:"));
|
||||
//DBGPRINTLN(String(group));
|
||||
if (getPowermeterWatts(group)) {
|
||||
// Weiter zum nächsten State
|
||||
mCfg->groups[group].state = zeroExportState::GETINVERTERPOWER;
|
||||
} else {
|
||||
// Wartezeit wenn Keine Daten vom Powermeter
|
||||
mCfg->groups[group].lastRun = (millis() - (mCfg->groups[group].refresh * 100UL));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case zeroExportState::GETINVERTERPOWER:
|
||||
if ((millis() - mCfg->groups[group].lastRun) > (mCfg->groups[group].refresh * 1000UL)) {
|
||||
//DBGPRINT(F("State::GETINVERTERPOWER:"));
|
||||
//DBGPRINTLN(String(group));
|
||||
if (getInverterPowerWatts(group)) {
|
||||
// Weiter zum nächsten State
|
||||
mCfg->groups[group].state = zeroExportState::FINISH;
|
||||
} else {
|
||||
// Wartezeit wenn Keine Daten vom Powermeter
|
||||
mCfg->groups[group].lastRun = (millis() - (mCfg->groups[group].refresh * 100UL));
|
||||
}
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case 4:
|
||||
//
|
||||
mCfg->groups[group].state = zeroExportState::RESET;
|
||||
break;
|
||||
case 5:
|
||||
//
|
||||
mCfg->groups[group].state = zeroExportState::RESET;
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
//
|
||||
//DBGPRINT(F("State::?: "));
|
||||
//DBGPRINTLN(String(group));
|
||||
mCfg->groups[group].state = zeroExportState::RESET;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
if (!mCfg->groups[group].powermeter.error) {
|
||||
DBGPRINTLN(String("ok verarbeiten."));
|
||||
}
|
||||
|
||||
if (mCfg->groups[group].powermeter.error >= ZEROEXPORT_POWERMETER_MAX_ERRORS) {
|
||||
DBGPRINTLN(String("nok Notmodus."));
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// getPowermeterGroup
|
||||
mCfg->zeGroup[group].PowermeterSum = getPowermeterSum();
|
||||
// getPowermeterPhase
|
||||
for (uint8_t phase = 1; phase <= 3; phase++) {
|
||||
mCfg->zeGroup[group].PowermeterPhase[phase] = getPowermeterPhase();
|
||||
}
|
||||
// getInverterPower
|
||||
for (uint8_t inv = 0; inv < MAX; inv++) {
|
||||
mCfg->zeGroup[group].InverterpowerGroup = getInverterpowerGroup();
|
||||
for (uint8_t phase = 1; phase <= 3; phase++) {
|
||||
mCfg->zeGroup[group].InverterpowerPhase[phase] = getInverterpowerPhase();
|
||||
}
|
||||
}
|
||||
// calcPowerSum
|
||||
mCfg->zeGroup[group].LimitSumNew = mCfg->zeGroup[group].LimitSumOld + mCfg->zeGroup[group].PowermeterSum;
|
||||
// calcPowerPhase
|
||||
for (uint8_t phase = 1; phase <= 3; phase++) {
|
||||
mCfg->zeGroup[group].LimitPhaseNew[phase] = mCfg->zeGroup[group].LimitPhaseOld[phase] - mCfg->zeGroup[group].PowermeterPhase[phase];
|
||||
}
|
||||
// calcPowerInverter
|
||||
for (uint8_t inv = 0; inv < MAX; inv++) {
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// setPower
|
||||
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||
if (!mCfg->groups[group].enabled) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
// TODO: Inverter sortieren nach Leistung
|
||||
// -> Aufsteigend bei Leistungserhöhung
|
||||
// -> Absteigend bei Leistungsreduzierung
|
||||
for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
|
||||
if (!mCfg->groups[group].inverters[inv].enabled) {
|
||||
continue;
|
||||
}
|
||||
if (mCfg->groups[group].inverters[inv].waitingTime) {
|
||||
mCfg->groups[group].inverters[inv].waitingTime--;
|
||||
continue;
|
||||
}
|
||||
// Leistung erhöhen
|
||||
if (mCfg->groups[group].power < mCfg->groups[group].powerLimitAkt - mCfg->groups[group].powerHyst) {
|
||||
// mCfg->groups[group].powerLimitAkt = mCfg->groups[group].power
|
||||
|
||||
|
||||
mCfg->groups[group].inverters[inv].waitingTime = ZEROEXPORT_DEF_INV_WAITINGTIME_MS;
|
||||
return;
|
||||
}
|
||||
// Leistung reduzieren
|
||||
if (mCfg->groups[group].power > mCfg->groups[group].powerLimitAkt + mCfg->groups[group].powerHyst) {
|
||||
|
||||
|
||||
|
||||
mCfg->groups[group].inverters[inv].waitingTime = ZEROEXPORT_DEF_INV_WAITINGTIME_MS;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((Power < PowerLimit - Hyst) || (Power > PowerLimit + Hyst)) {
|
||||
if (Limit < 2%) {
|
||||
setPower(Off);
|
||||
setPowerLimit(100%)
|
||||
} else {
|
||||
setPower(On);
|
||||
setPowerLimit(Limit);
|
||||
mCfg->Inv[inv].waitingTime = ZEROEXPORT_DEF_INV_WAITINGTIME_MS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void tickerSecond() {
|
||||
//DPRINTLN(DBG_INFO, (F("tickerSecond()")));
|
||||
if (millis() - mCfg->lastTime < mCfg->count_avg * 1000UL) {
|
||||
zero(); // just refresh when it is needed. To get cpu load low.
|
||||
if ((!mIsInitialized) || (!mCfg->enabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//DPRINTLN(DBG_INFO, (F("tickerSecond()")));
|
||||
// if (millis() - mCfg->lastTime < mCfg->count_avg * 1000UL) {
|
||||
/// zero(); // just refresh when it is needed. To get cpu load low.
|
||||
// }
|
||||
}
|
||||
|
||||
// Sums up the power values of all phases and returns them.
|
||||
// If the value is negative, all power values from the inverter are taken into account
|
||||
double getPowertoSetnewValue()
|
||||
{
|
||||
/*
|
||||
float ivPower = 0;
|
||||
Inverter<> *iv;
|
||||
record_t<> *rec;
|
||||
|
@ -41,8 +244,9 @@ class ZeroExport {
|
|||
continue;
|
||||
ivPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
||||
}
|
||||
|
||||
return ((unsigned)(mCfg->total_power - mCfg->power_avg) >= mCfg->power_avg) ? ivPower + mCfg->total_power : ivPower - mCfg->total_power;
|
||||
*/
|
||||
// return ((unsigned)(mCfg->total_power - mCfg->power_avg) >= mCfg->power_avg) ? ivPower + mCfg->total_power : ivPower - mCfg->total_power;
|
||||
return 0;
|
||||
}
|
||||
//C2T2-B91B
|
||||
private:
|
||||
|
@ -51,6 +255,7 @@ class ZeroExport {
|
|||
// TODO: Need to improve here. 2048 for a JSON Obj is to big!?
|
||||
bool zero()
|
||||
{
|
||||
/*
|
||||
httpClient.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
httpClient.setUserAgent("Ahoy-Agent");
|
||||
httpClient.setConnectTimeout(1000);
|
||||
|
@ -103,6 +308,7 @@ class ZeroExport {
|
|||
return false;
|
||||
}
|
||||
httpClient.end();
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -111,12 +317,342 @@ class ZeroExport {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool getPowermeterWatts(uint8_t group) {
|
||||
bool ret = false;
|
||||
DBGPRINT(String("getPowermeterWatts: "));
|
||||
DBGPRINTLN(String(group));
|
||||
switch (mCfg->groups[group].pm_type) {
|
||||
case 1:
|
||||
ret = getPowermeterWattsShelly(group);
|
||||
break;
|
||||
// case 2:
|
||||
// ret = getPowermeterWattsTasmota(group);
|
||||
// break;
|
||||
// case 3:
|
||||
// ret = getPowermeterWattsMqtt(group);
|
||||
// break;
|
||||
// case 4:
|
||||
// ret = getPowermeterWattsHichi(group);
|
||||
// break;
|
||||
// case 5:
|
||||
// ret = getPowermeterWattsTibber(group);
|
||||
// break;
|
||||
/// default:
|
||||
/// ret = false;
|
||||
/// break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int getPowermeterWattsShelly(uint8_t group) {
|
||||
bool ret = false;
|
||||
HTTPClient http;
|
||||
// httpClient.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
httpClient.setUserAgent("Ahoy-Agent");
|
||||
// TODO: Ahoy-0.8.850024-zero
|
||||
// httpClient.setConnectTimeout(1000);
|
||||
// httpClient.setTimeout(1000);
|
||||
// httpClient.addHeader("Content-Type", "application/json");
|
||||
// httpClient.addHeader("Accept", "application/json");
|
||||
http.begin(mCfg->groups[group].pm_url);
|
||||
if (http.GET() == HTTP_CODE_OK)
|
||||
{
|
||||
|
||||
// Parsing
|
||||
DynamicJsonDocument doc(2048);
|
||||
DeserializationError error = deserializeJson(doc, http.getString());
|
||||
if (error)
|
||||
{
|
||||
DBGPRINT(String("deserializeJson() failed: "));
|
||||
DBGPRINTLN(String(error.c_str()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Shelly 3EM
|
||||
if (doc.containsKey(F("total_power"))) {
|
||||
mCfg->groups[group].pmPower = doc["total_power"];
|
||||
ret = true;
|
||||
// Shelly pro 3EM
|
||||
} else if (doc.containsKey(F("em:0"))) {
|
||||
mCfg->groups[group].pmPower = doc["em:0"]["total_act_power"];
|
||||
ret = true;
|
||||
// Keine Daten
|
||||
} else {
|
||||
mCfg->groups[group].pmPower = 0;
|
||||
}
|
||||
|
||||
// Shelly 3EM
|
||||
if (doc.containsKey(F("emeters"))) {
|
||||
mCfg->groups[group].pmPowerL1 = doc["emeters"][0]["power"];
|
||||
ret = true;
|
||||
// Shelly pro 3EM
|
||||
} else if (doc.containsKey(F("em:0"))) {
|
||||
mCfg->groups[group].pmPowerL1 = doc["em:0"]["a_act_power"];
|
||||
ret = true;
|
||||
// Shelly plus1pm plus2pm
|
||||
} else if (doc.containsKey(F("switch:0"))) {
|
||||
mCfg->groups[group].pmPowerL1 = doc["switch:0"]["apower"];
|
||||
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL1;
|
||||
ret = true;
|
||||
// Shelly Alternative
|
||||
} else if (doc.containsKey(F("apower"))) {
|
||||
mCfg->groups[group].pmPowerL1 = doc["apower"];
|
||||
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL1;
|
||||
ret = true;
|
||||
// Keine Daten
|
||||
} else {
|
||||
mCfg->groups[group].pmPowerL1 = 0;
|
||||
}
|
||||
DBGPRINT(String("pmPowerL1: "));
|
||||
DBGPRINTLN(String(mCfg->groups[group].pmPowerL1));
|
||||
|
||||
// Shelly 3EM
|
||||
if (doc.containsKey(F("emeters"))) {
|
||||
mCfg->groups[group].pmPowerL2 = doc["emeters"][1]["power"];
|
||||
ret = true;
|
||||
// Shelly pro 3EM
|
||||
} else if (doc.containsKey(F("em:0"))) {
|
||||
mCfg->groups[group].pmPowerL2 = doc["em:0"]["b_act_power"];
|
||||
ret = true;
|
||||
// Shelly plus1pm plus2pm
|
||||
} else if (doc.containsKey(F("switch:1"))) {
|
||||
mCfg->groups[group].pmPowerL2 = doc["switch.1"]["apower"];
|
||||
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL2;
|
||||
ret = true;
|
||||
// // Shelly Alternative
|
||||
// } else if (doc.containsKey(F("apower"))) {
|
||||
// mCfg->groups[group].pmPowerL2 = doc["apower"];
|
||||
// mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL2;
|
||||
// ret = true;
|
||||
// Keine Daten
|
||||
} else {
|
||||
mCfg->groups[group].pmPowerL2 = 0;
|
||||
}
|
||||
DBGPRINT(String("pmPowerL2: "));
|
||||
DBGPRINTLN(String(mCfg->groups[group].pmPowerL2));
|
||||
|
||||
// Shelly 3EM
|
||||
if (doc.containsKey(F("emeters"))) {
|
||||
mCfg->groups[group].pmPowerL3 = doc["emeters"][2]["power"];
|
||||
ret = true;
|
||||
// Shelly pro 3EM
|
||||
} else if (doc.containsKey(F("em:0"))) {
|
||||
mCfg->groups[group].pmPowerL3 = doc["em:0"]["c_act_power"];
|
||||
ret = true;
|
||||
// Shelly plus1pm plus2pm
|
||||
} else if (doc.containsKey(F("switch:2"))) {
|
||||
mCfg->groups[group].pmPowerL3 = doc["switch:2"]["apower"];
|
||||
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL3;
|
||||
ret = true;
|
||||
// // Shelly Alternative
|
||||
// } else if (doc.containsKey(F("apower"))) {
|
||||
// mCfg->groups[group].pmPowerL3 = doc["apower"];
|
||||
// mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL3;
|
||||
// ret = true;
|
||||
// Keine Daten
|
||||
} else {
|
||||
mCfg->groups[group].pmPowerL3 = 0;
|
||||
}
|
||||
DBGPRINT(String("pmPowerL3: "));
|
||||
DBGPRINTLN(String(mCfg->groups[group].pmPowerL3));
|
||||
|
||||
DBGPRINT(String("pmPower: "));
|
||||
DBGPRINTLN(String(mCfg->groups[group].pmPower));
|
||||
}
|
||||
http.end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int getPowermeterWattsTasmota(void) {
|
||||
/*
|
||||
HTTPClient http;
|
||||
char url[100] = "http://";
|
||||
strcat(url, mCfg->monitor_url);
|
||||
strcat(url, "/cm?cmd=status%2010");
|
||||
http.begin(url);
|
||||
|
||||
if (http.GET() == 200) {
|
||||
// Parsing
|
||||
DynamicJsonDocument doc(384);
|
||||
DeserializationError error = deserializeJson(doc, http.getString());
|
||||
if (error) {
|
||||
Serial.print("deserializeJson() failed: ");
|
||||
Serial.println(error.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
JsonObject Tasmota_ENERGY = doc["StatusSNS"]["ENERGY"];
|
||||
int Tasmota_Power = Tasmota_ENERGY["Power"]; // 0
|
||||
return Tasmota_Power;
|
||||
*/
|
||||
/*
|
||||
String url = "http://" + String(TASMOTA_IP) + "/cm?cmnd=status%2010";
|
||||
ParsedData = http.get(url).json();
|
||||
int Watts = ParsedData[TASMOTA_JSON_STATUS][TASMOTA_JSON_PAYLOAD_MQTT_PREFIX][TASMOTA_JSON_POWER_MQTT_LABEL].toInt();
|
||||
return Watts;
|
||||
*/
|
||||
// }
|
||||
// http.end();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getPowermeterWattsMqtt(void) {
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getPowermeterWattsHichi(void) {
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getPowermeterWattsTibber(void) {
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool getInverterPowerWatts(uint8_t group) {
|
||||
bool ret = false;
|
||||
DBGPRINT(String("getInverterPowerWatts: "));
|
||||
DBGPRINTLN(String(group));
|
||||
for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
|
||||
DBGPRINT(String("iv: "));
|
||||
DBGPRINT(String(inv));
|
||||
DBGPRINT(String(" "));
|
||||
// Wenn Inverter deaktiviert -> Eintrag ignorieren
|
||||
if (!mCfg->groups[group].inverters[inv].enabled) {
|
||||
DBGPRINT(String("(ze disabled)."));
|
||||
continue;
|
||||
}
|
||||
// Daten holen
|
||||
Inverter<> *iv;
|
||||
record_t<> *rec;
|
||||
// TODO: getInverterById
|
||||
for (uint8_t i = 0; i < mSys->getNumInverters(); i++) {
|
||||
iv = mSys->getInverterByPos(i);
|
||||
// Wenn kein Inverter -> ignorieren
|
||||
if (iv == NULL) {
|
||||
continue;
|
||||
}
|
||||
// Wenn falscher Inverter -> ignorieren
|
||||
if (iv->id != (uint8_t)mCfg->groups[group].inverters[inv].id) {
|
||||
continue;
|
||||
}
|
||||
DBGPRINT(String("("));
|
||||
DBGPRINT(String(iv->id));
|
||||
DBGPRINT(String("( gefunden)"));
|
||||
// wenn Inverter deaktiviert -> Daten ignorieren
|
||||
// if (!iv->enabled()) {
|
||||
//DBGPRINT(String(" aber deaktiviert "));
|
||||
// continue;
|
||||
// }
|
||||
// wenn Inverter nicht verfügbar -> Daten ignorieren
|
||||
if (!iv->isAvailable()) {
|
||||
DBGPRINT(String(" aber nicht erreichbar "));
|
||||
continue;
|
||||
}
|
||||
// wenn Inverter nicht produziert -> Daten ignorieren
|
||||
// if (!iv->isProducing()) {
|
||||
//DBGPRINT(String(" aber produziert nix "));
|
||||
// continue;
|
||||
// }
|
||||
// Daten abrufen
|
||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
|
||||
// TODO: gibts hier nen Timestamp? Wenn die Daten nicht aktueller sind als beim letzten Durchlauf dann brauch ich nix machen
|
||||
|
||||
mCfg->groups[group].inverters[inv].power = iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
||||
DBGPRINT(String("(P="));
|
||||
DBGPRINT(String(mCfg->groups[group].inverters[inv].power));
|
||||
DBGPRINT(String("W "));
|
||||
|
||||
mCfg->groups[group].inverters[inv].limit = iv->actPowerLimit;
|
||||
DBGPRINT(String("Li="));
|
||||
DBGPRINT(String(mCfg->groups[group].inverters[inv].limit));
|
||||
DBGPRINT(String("% "));
|
||||
|
||||
mCfg->groups[group].inverters[inv].limitAck = iv->powerLimitAck;
|
||||
DBGPRINT(String("Ack= "));
|
||||
DBGPRINT(String(mCfg->groups[group].inverters[inv].limitAck));
|
||||
DBGPRINT(String(" "));
|
||||
|
||||
mCfg->groups[group].inverters[inv].dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec);
|
||||
DBGPRINT(String("U="));
|
||||
DBGPRINT(String(mCfg->groups[group].inverters[inv].dcVoltage));
|
||||
DBGPRINT(String("V) "));
|
||||
// TODO: Eingang muss konfigurierbar sein
|
||||
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
DBGPRINTLN(String(""));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// private member variables
|
||||
cfgzeroExport_t *mCfg;
|
||||
bool mIsInitialized = false;
|
||||
zeroExport_t *mCfg;
|
||||
settings_t *mConfig;
|
||||
HMSYSTEM *mSys;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Shelly 1pm
|
||||
Der Shelly 1pm verfügt über keine eigene Spannungsmessung sondern geht von 220V * Korrekturfaktor aus. Dadurch wird die Leistungsmessung verfälscht und der Shelly ist ungeeignet.
|
||||
|
||||
|
||||
http://192.168.xxx.xxx/status
|
||||
Shelly 3em (oder em3) :
|
||||
ok
|
||||
{"wifi_sta":{"connected":true,"ssid":"Odyssee2001","ip":"192.168.100.85","rssi":-23},"cloud":{"enabled":false,"connected":false},"mqtt":{"connected":true},"time":"17:13","unixtime":1709223219,"serial":27384,"has_update":false,"mac":"3494547B94EE","cfg_changed_cnt":1,"actions_stats":{"skipped":0},"relays":[{"ison":false,"has_timer":false,"timer_started":0,"timer_duration":0,"timer_remaining":0,"overpower":false,"is_valid":true,"source":"input"}],"emeters":[{"power":51.08,"pf":0.27,"current":0.78,"voltage":234.90,"is_valid":true,"total":1686297.2,"total_returned":428958.4},{"power":155.02,"pf":0.98,"current":0.66,"voltage":235.57,"is_valid":true,"total":878905.6,"total_returned":4.1},{"power":6.75,"pf":0.26,"current":0.11,"voltage":234.70,"is_valid":true,"total":206151.1,"total_returned":0.0}],"total_power":212.85,"emeter_n":{"current":0.00,"ixsum":1.29,"mismatch":false,"is_valid":false},"fs_mounted":true,"v_data":1,"ct_calst":0,"update":{"status":"idle","has_update":false,"new_version":"20230913-114244/v1.14.0-gcb84623","old_version":"20230913-114244/v1.14.0-gcb84623","beta_version":"20231107-165007/v1.14.1-rc1-g0617c15"},"ram_total":49920,"ram_free":30192,"fs_size":233681,"fs_free":154616,"uptime":13728721}
|
||||
|
||||
|
||||
Shelly plus 2pm :
|
||||
ok
|
||||
{"ble":{},"cloud":{"connected":false},"input:0":{"id":0,"state":false},"input:1":{"id":1,"state":false},"mqtt":{"connected":true},"switch:0":{"id":0, "source":"MQTT", "output":false, "apower":0.0, "voltage":237.0, "freq":50.0, "current":0.000, "pf":0.00, "aenergy":{"total":62758.285,"by_minute":[0.000,0.000,0.000],"minute_ts":1709223337},"temperature":{"tC":35.5, "tF":96.0}},"switch:1":{"id":1, "source":"MQTT", "output":false, "apower":0.0, "voltage":237.1, "freq":50.0, "current":0.000, "pf":0.00, "aenergy":{"total":61917.211,"by_minute":[0.000,0.000,0.000],"minute_ts":1709223337},"temperature":{"tC":35.5, "tF":96.0}},"sys":{"mac":"B0B21C10A478","restart_required":false,"time":"17:15","unixtime":1709223338,"uptime":8746115,"ram_size":245016,"ram_free":141004,"fs_size":458752,"fs_free":135168,"cfg_rev":7,"kvs_rev":0,"schedule_rev":0,"webhook_rev":0,"available_updates":{"stable":{"version":"1.2.2"}}},"wifi":{"sta_ip":"192.168.100.87","status":"got ip","ssid":"Odyssee2001","rssi":-62},"ws":{"connected":false}}
|
||||
|
||||
http://192.168.xxx.xxx/rpc/Shelly.GetStatus
|
||||
Shelly plus 1pm :
|
||||
nok keine negativen Leistungswerte
|
||||
{"ble":{},"cloud":{"connected":false},"input:0":{"id":0,"state":false},"mqtt":{"connected":true},"switch:0":{"id":0, "source":"MQTT", "output":false, "apower":0.0, "voltage":235.9, "current":0.000, "aenergy":{"total":20393.619,"by_minute":[0.000,0.000,0.000],"minute_ts":1709223441},"temperature":{"tC":34.6, "tF":94.3}},"sys":{"mac":"FCB467A66E3C","restart_required":false,"time":"17:17","unixtime":1709223443,"uptime":8644483,"ram_size":246256,"ram_free":143544,"fs_size":458752,"fs_free":147456,"cfg_rev":9,"kvs_rev":0,"schedule_rev":0,"webhook_rev":0,"available_updates":{"stable":{"version":"1.2.2"}}},"wifi":{"sta_ip":"192.168.100.88","status":"got ip","ssid":"Odyssee2001","rssi":-42},"ws":{"connected":false}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#endif /*__ZEROEXPORT__*/
|
||||
|
||||
#endif /* #if defined(ESP32) */
|
|
@ -618,22 +618,6 @@ class RestApi {
|
|||
obj[F("interval")] = String(mConfig->mqtt.interval);
|
||||
}
|
||||
|
||||
#if defined(ESP32)
|
||||
void getzeroExport(JsonObject obj) {
|
||||
obj[F("en_zeroexport")] = (bool) mConfig->plugin.zexport.enabled;
|
||||
obj[F("two_percent")] = (bool) mConfig->plugin.zexport.two_percent;
|
||||
obj[F("monitor_url")] = String(mConfig->plugin.zexport.monitor_url);
|
||||
obj[F("json_path")] = String(mConfig->plugin.zexport.json_path);
|
||||
obj[F("count_avg")] = (uint8_t)mConfig->plugin.zexport.count_avg;
|
||||
obj[F("max_power")] = (double)mConfig->plugin.zexport.max_power;
|
||||
obj[F("Iv")] = (uint8_t)mConfig->plugin.zexport.Iv;
|
||||
obj[F("power_avg")] = (float)mConfig->plugin.zexport.power_avg;
|
||||
obj[F("query_device")] = (float)mConfig->plugin.zexport.query_device;
|
||||
obj[F("total_power")] = (double)mConfig->plugin.zexport.total_power;
|
||||
//obj[F("device")] = (uint8_t)mCfg.plugin.zexport.device;
|
||||
}
|
||||
#endif
|
||||
|
||||
void getNtp(JsonObject obj) {
|
||||
obj[F("addr")] = String(mConfig->ntp.addr);
|
||||
obj[F("port")] = String(mConfig->ntp.port);
|
||||
|
@ -730,6 +714,49 @@ class RestApi {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
void getZeroExport(JsonObject obj) {
|
||||
obj[F("enabled")] = (bool) mConfig->plugin.zeroExport.enabled;
|
||||
// Groups
|
||||
obj[F("max_groups")] = ZEROEXPORT_MAX_GROUPS;
|
||||
JsonArray arrGroup = obj.createNestedArray(F("groups"));
|
||||
for(uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||
JsonObject objGroup = arrGroup.createNestedObject();
|
||||
// General
|
||||
objGroup[F("id")] = (uint8_t)group;
|
||||
objGroup[F("enabled")] = (bool)mConfig->plugin.zeroExport.groups[group].enabled;
|
||||
objGroup[F("name")] = String(mConfig->plugin.zeroExport.groups[group].name);
|
||||
// Powermeter
|
||||
objGroup[F("pm_type")] = (uint8_t)mConfig->plugin.zeroExport.groups[group].pm_type;
|
||||
objGroup[F("pm_url")] = String(mConfig->plugin.zeroExport.groups[group].pm_url);
|
||||
objGroup[F("pm_jsonPath")] = String(mConfig->plugin.zeroExport.groups[group].pm_jsonPath);
|
||||
objGroup[F("pm_user")] = String(mConfig->plugin.zeroExport.groups[group].pm_user);
|
||||
objGroup[F("pm_pass")] = String(mConfig->plugin.zeroExport.groups[group].pm_pass);
|
||||
// Inverters
|
||||
objGroup[F("max_inverters")] = ZEROEXPORT_GROUP_MAX_INVERTERS;
|
||||
JsonArray arrInv = objGroup.createNestedArray(F("inverters"));
|
||||
for(uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
|
||||
JsonObject objGroupInv = arrInv.createNestedObject();
|
||||
objGroupInv[F("enabled")] = (bool)mConfig->plugin.zeroExport.groups[group].inverters[inv].enabled;
|
||||
objGroupInv[F("id")] = (int8_t)mConfig->plugin.zeroExport.groups[group].inverters[inv].id;
|
||||
objGroupInv[F("target")] = (int8_t)mConfig->plugin.zeroExport.groups[group].inverters[inv].target;
|
||||
objGroupInv[F("twoPercent")] = (bool)mConfig->plugin.zeroExport.groups[group].inverters[inv].twoPercent;
|
||||
objGroupInv[F("powerMax")] = (uint16_t)mConfig->plugin.zeroExport.groups[group].inverters[inv].powerMax;
|
||||
}
|
||||
// Battery
|
||||
objGroup[F("battEnabled")] = (bool)mConfig->plugin.zeroExport.groups[group].battEnabled;
|
||||
objGroup[F("battVoltageOn")] = ah::round3((float)mConfig->plugin.zeroExport.groups[group].battVoltageOn);
|
||||
objGroup[F("battVoltageOff")] = ah::round3((float)mConfig->plugin.zeroExport.groups[group].battVoltageOff);
|
||||
// Advanced
|
||||
objGroup[F("refresh")] = (uint8_t)mConfig->plugin.zeroExport.groups[group].refresh;
|
||||
objGroup[F("powerTolerance")] = (uint8_t)mConfig->plugin.zeroExport.groups[group].powerTolerance;
|
||||
objGroup[F("powerMax")] = (uint16_t)mConfig->plugin.zeroExport.groups[group].powerMax;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
void getMqttInfo(JsonObject obj) {
|
||||
obj[F("enabled")] = (mConfig->mqtt.broker[0] != '\0');
|
||||
obj[F("connected")] = mApp->getMqttIsConnected();
|
||||
|
@ -798,10 +825,11 @@ class RestApi {
|
|||
#if defined(PLUGIN_DISPLAY)
|
||||
getDisplay(obj.createNestedObject(F("display")));
|
||||
#endif
|
||||
|
||||
#if defined(ESP32)
|
||||
getzeroExport(obj.createNestedObject(F("zeroExport")));
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
getZeroExport(obj.createNestedObject(F("zeroExport")));
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
}
|
||||
|
||||
#if !defined(ETHERNET)
|
||||
|
@ -955,7 +983,42 @@ class RestApi {
|
|||
iv->config->powerLevel = jsonIn[F("pa")];
|
||||
iv->config->disNightCom = jsonIn[F("disnightcom")];
|
||||
mApp->saveSettings(false); // without reboot
|
||||
} else {
|
||||
}
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
else if(F("ze_save_group") == jsonIn[F("cmd")]) {
|
||||
// General
|
||||
uint8_t group = jsonIn[F("id")];
|
||||
mConfig->plugin.zeroExport.groups[group].enabled = jsonIn[F("enabled")];
|
||||
snprintf(mConfig->plugin.zeroExport.groups[group].name, ZEROEXPORT_GROUP_MAX_LEN_NAME, "%s", jsonIn[F("name")].as<const char*>());
|
||||
// Powermeter
|
||||
mConfig->plugin.zeroExport.groups[group].pm_type = jsonIn[F("pm_type")];
|
||||
snprintf(mConfig->plugin.zeroExport.groups[group].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", jsonIn[F("pm_url")].as<const char*>());
|
||||
snprintf(mConfig->plugin.zeroExport.groups[group].pm_jsonPath, ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH, "%s", jsonIn[F("pm_jsonPath")].as<const char*>());
|
||||
snprintf(mConfig->plugin.zeroExport.groups[group].pm_user, ZEROEXPORT_GROUP_MAX_LEN_PM_USER, "%s", jsonIn[F("pm_user")].as<const char*>());
|
||||
snprintf(mConfig->plugin.zeroExport.groups[group].pm_pass, ZEROEXPORT_GROUP_MAX_LEN_PM_PASS, "%s", jsonIn[F("pm_pass")].as<const char*>());
|
||||
// Inverters
|
||||
for(uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
|
||||
mConfig->plugin.zeroExport.groups[group].inverters[inv].enabled = jsonIn[F("inverters")][inv][F("enabled")];
|
||||
mConfig->plugin.zeroExport.groups[group].inverters[inv].id = jsonIn[F("inverters")][inv][F("id")];
|
||||
mConfig->plugin.zeroExport.groups[group].inverters[inv].target = jsonIn[F("inverters")][inv][F("target")];
|
||||
mConfig->plugin.zeroExport.groups[group].inverters[inv].twoPercent = jsonIn[F("inverters")][inv][F("twoPercent")];
|
||||
mConfig->plugin.zeroExport.groups[group].inverters[inv].powerMax = jsonIn[F("inverters")][inv][F("powerMax")];
|
||||
}
|
||||
// Battery
|
||||
mConfig->plugin.zeroExport.groups[group].battEnabled = jsonIn[F("battEnabled")];
|
||||
mConfig->plugin.zeroExport.groups[group].battVoltageOn = jsonIn[F("battVoltageOn")];
|
||||
mConfig->plugin.zeroExport.groups[group].battVoltageOff = jsonIn[F("battVoltageOff")];
|
||||
// Advanced
|
||||
mConfig->plugin.zeroExport.groups[group].refresh = jsonIn[F("refresh")];
|
||||
mConfig->plugin.zeroExport.groups[group].powerTolerance = jsonIn[F("powerTolerance")];
|
||||
mConfig->plugin.zeroExport.groups[group].powerMax = jsonIn[F("powerMax")];
|
||||
// Global
|
||||
mApp->saveSettings(false); // without reboot
|
||||
}
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
else {
|
||||
jsonOut[F("error")] = F("ERR_UNKNOWN_CMD");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -304,50 +304,20 @@
|
|||
</fieldset>
|
||||
</div>
|
||||
|
||||
<!-- Zero Export -->
|
||||
<button type="button" class="s_collapsible" id="zeroExport_button">Zero Export</button>
|
||||
<!-- Plugin ZeroExport -->
|
||||
<button type="button" class="s_collapsible" id="zeroExport_button">{#ZE}</button>
|
||||
<div class="s_content" id="zeroExport">
|
||||
<fieldset class="mb-4">
|
||||
<legend class="des">Zero Export</legend>
|
||||
<legend class="des">{#ZE}</legend>
|
||||
<div id="zeroType"></div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3">Enable zero export</div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="en_zeroexport"/></div>
|
||||
<p>Please select your favorite query interface:</p>
|
||||
<div class="col-12 col-sm-3 my-2">{#ZE_ENABLED}</div>
|
||||
<div class="col-12 col-sm-9"><input type="checkbox" name="ze_enabled"/></div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-sm-3 my-2">Monitor IP: </div>
|
||||
<input type="radio" id="html" name="dev_Tibber" value="Tibber">
|
||||
<label for="html">Tibber</label>
|
||||
<input type="radio" id="css" name="dev_Shelly" value="Shelly">
|
||||
<label for="css">Shelly</label>
|
||||
<input type="radio" id="javascript" name="dev_Other" value="Other">
|
||||
<label for="javascript">Other</label>
|
||||
|
||||
<div class="col-12 col-sm-9">
|
||||
<input type="text" name="monitor_url" maxlength="100">A JSON-Format is required to work properly.<br>
|
||||
HICHI: http://IP_Address/cm?cmnd=status%208</div>
|
||||
|
||||
<div class="col-12 col-sm-3 my-2">Prio Inverter</div>
|
||||
<div class="col-12 col-sm-9"><select name="iv" id="Inv_ID"></select>Which Inverter should be regulated.</div>
|
||||
|
||||
<div class="col-12 col-sm-3 my-2">JSON Path: </div>
|
||||
<div class="col-12 col-sm-9"><input type="text" name="json_path" maxlength="100">Only for HICHI needed!</div>
|
||||
|
||||
<div class="col-8 col-sm-3">2% protection: </div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="two_percent"/></div>
|
||||
<br>
|
||||
<div class="col-8 col-sm-3">Max Power: </div>
|
||||
<div class="col-4 col-sm-9"><input type="number" name="max_power" min="8" ></div>
|
||||
<br>
|
||||
<div class="col-12 col-sm-3 my-2">Refresh rate (sec.)<input type="number" name="count_avg" min="0" max="255"></div>
|
||||
<div class="col-12 col-sm-3 my-2">Power tolerances (Watt)<input type="number" name="power_avg" min="0" max="255"></div>
|
||||
</div>
|
||||
<p name="total_power">Total: n/a</p>
|
||||
<div id="ze_groups"></div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<!-- Plugin ZeroExport - Ende -->
|
||||
|
||||
<div class="row mb-4 mt-4">
|
||||
<div class="col-8 col-sm-3">{#BTN_REBOOT_SUCCESSFUL_SAVE}</div>
|
||||
|
@ -1201,54 +1171,383 @@
|
|||
document.getElementById("date").innerHTML = toIsoDateStr((new Date((++ts) * 1000)));
|
||||
}
|
||||
|
||||
function parsezeroExport(obj, type, ) {
|
||||
if ("ESP8266" == type) {
|
||||
/*IF_PLUGIN_ZEROEXPORT*/
|
||||
// Plugin ZeroExport
|
||||
function ZeroExportGroup_Modal(obj, ivObj) {
|
||||
|
||||
// Tab_General
|
||||
var cbEnabled = ml("input", {name: "enabled", type: "checkbox"}, null);
|
||||
cbEnabled.checked = (obj.enabled);
|
||||
|
||||
// Tab_Powermeter
|
||||
|
||||
// Tab_Inverter
|
||||
maxInv = obj["max_inverters"];
|
||||
|
||||
var lines = [];
|
||||
|
||||
lines.push(ml("tr", {}, [
|
||||
ml("th", {style: "width: 10%;"}, ml("input", {name: "invMax", id: "invMax", type: "hidden", value: maxInv}, null)),
|
||||
ml("th", {style: "width: 10%;"}, "{#ZE_GROUP_TAB_INVERTER_ENABLED}"),
|
||||
ml("th", {}, "{#ZE_GROUP_TAB_INVERTER_NAME}"),
|
||||
ml("th", {}, "{#ZE_GROUP_TAB_INVERTER_SUM}"),
|
||||
ml("th", {style: "width: 10%;"}, "{#ZE_GROUP_TAB_INVERTER_TWOPERCENT}"),
|
||||
ml("th", {style: "width: 15%;"}, "{#ZE_GROUP_TAB_INVERTER_POWERMAX}"),
|
||||
]));
|
||||
|
||||
for(var inv = 0; inv < maxInv; inv++) {
|
||||
lines.push(ml("tr", {}, [
|
||||
ml("td", {}, String(inv)),
|
||||
ml("td", {},
|
||||
ml("div", {}, [
|
||||
ml("input", {name: "invEnabled"+inv, class: "text", id: "invEnabled"+inv, type: "checkbox"}, null)
|
||||
]),
|
||||
),
|
||||
ml("td", {},
|
||||
ml("div", {}, [
|
||||
ml("select", {name: "invId"+inv, class: "text", id: "invId"+inv}, null),
|
||||
]),
|
||||
),
|
||||
ml("td", {},
|
||||
ml("div", {}, [
|
||||
ml("select", {name: "invTarget"+inv, class: "text", id: "invTarget"+inv}, null),
|
||||
]),
|
||||
),
|
||||
ml("td", {},
|
||||
ml("div", {}, [
|
||||
ml("input", {name: "invTwoPercent"+inv, class: "text", id: "invTwoPercent"+inv, type: "checkbox"}, null)
|
||||
]),
|
||||
),
|
||||
ml("td", {},
|
||||
ml("div", {}, [
|
||||
ml("input", {name: "invPowerMax"+inv, class: "text", id: "invPowerMax"+inv, type: "number", min: "0", max: "65535"}, null)
|
||||
]),
|
||||
),
|
||||
]));
|
||||
}
|
||||
|
||||
// Tab_Battery
|
||||
var cb_battEnabled = ml("input", {name: "battEnabled", type: "checkbox"}, null);
|
||||
cb_battEnabled.checked = (obj.battEnabled);
|
||||
|
||||
// Tab_Advanced
|
||||
|
||||
// Tab
|
||||
var html = ml("div", {}, [
|
||||
tabs(["{#ZE_GROUP_TAB_GENERAL}", "{#ZE_GROUP_TAB_POWERMETER}", "{#ZE_GROUP_TAB_INVERTER}", "{#ZE_GROUP_TAB_BATTERY}", "{#ZE_GROUP_TAB_ADVANCED}"]),
|
||||
// General
|
||||
ml("div", {id: "div{#ZE_GROUP_TAB_GENERAL}", class: "tab-content"}, [
|
||||
divRow("{#ZE_GROUP_TAB_GENERAL_GRUPPE}", String(obj.id)),
|
||||
divRow("{#ZE_GROUP_TAB_GENERAL_ENABLE}", cbEnabled),
|
||||
divRow("{#ZE_GROUP_TAB_GENERAL_NAME}", ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)),
|
||||
]),
|
||||
// Powermeter
|
||||
ml("div", {id: "div{#ZE_GROUP_TAB_POWERMETER}", class: "tab-content hide"}, [
|
||||
divRow("{#ZE_GROUP_TAB_POWERMETER_TYPE}",
|
||||
ml("select", {name: "pm_type", class: "text", id: "pm_type"}, null),
|
||||
),
|
||||
divRow("{#ZE_GROUP_TAB_POWERMETER_URL}", [
|
||||
ml("input", {name: "pm_url", class: "text", type: "text", value: obj.pm_url, maxlength: "100"}, null),
|
||||
// TODO: Hilfstexte -> übersetzen mit lang.json
|
||||
ml("p", {}, "(3em) - http://IP/status"),
|
||||
ml("p", {}, "(pro3em) - http://IP/rpc/Shelly.GetStatus"),
|
||||
ml("p", {}, "(plus1pm) - http://IP/rpc/Shelly.GetStatus"),
|
||||
ml("p", {}, "(plus2pm) - http://IP/rpc/Shelly.GetStatus"),
|
||||
ml("p", {}, "(plus1pmAlternative) - http://IP/rpc/switch.GetStatus?id=0"),
|
||||
ml("p", {}, "(plus2pmAlternative) - http://IP/rpc/switch.GetStatus?id=0"),
|
||||
// ml("p", {}, "A JSON-Format is required to work properly.<br>HICHI: http://IP_Address/cm?cmnd=status%208"),
|
||||
]),
|
||||
divRow("{#ZE_GROUP_TAB_POWERMETER_JSONPATH}", [
|
||||
ml("input", {name: "pm_jsonPath", class: "text", type: "text", value: obj.pm_jsonPath}, null),
|
||||
// TODO: Hilfstexte -> übersetzen mit lang.json
|
||||
// ml("p", {}, "Only for HICHI needed!"),
|
||||
]),
|
||||
divRow("{#ZE_GROUP_TAB_POWERMETER_USER}",
|
||||
ml("input", {name: "pm_user", class: "text", type: "text", value: obj.pm_user}, null),
|
||||
),
|
||||
divRow("{#ZE_GROUP_TAB_POWERMETER_PASS}",
|
||||
ml("input", {name: "pm_pass", class: "text", type: "text", value: obj.pm_pass}, null),
|
||||
),
|
||||
]),
|
||||
// Inverter
|
||||
ml("div", {id: "div{#ZE_GROUP_TAB_INVERTER}", class: "tab-content hide"}, [
|
||||
ml("table", {class: "table"}, ml("tbody", {}, lines)),
|
||||
]),
|
||||
// Battery
|
||||
ml("div", {id: "div{#ZE_GROUP_TAB_BATTERY}", class: "tab-content hide"}, [
|
||||
divRow("{#ZE_GROUP_TAB_BATTERY_BATTENABLED}", cb_battEnabled),
|
||||
divRow("{#ZE_GROUP_TAB_BATTERY_BATTVOLTAGEON}", ml("input", {name: "battVoltageOn", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battVoltageOn}, null)),
|
||||
divRow("{#ZE_GROUP_TAB_BATTERY_BATTVOLTAGEOFF}", ml("input", {name: "battVoltageOff", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battVoltageOff}, null)),
|
||||
]),
|
||||
// Advanced
|
||||
ml("div", {id: "div{#ZE_GROUP_TAB_ADVANCED}", class: "tab-content hide"}, [
|
||||
divRow("{#ZE_GROUP_TAB_ADVANCED_REFRESH}", ml("input", {name: "refresh", class: "text", type: "number", min: "0", max: "255", value: obj.refresh}, null)),
|
||||
divRow("{#ZE_GROUP_TAB_ADVANCED_POWERTOLERANCE}", ml("input", {name: "powerTolerance", class: "text", type: "number", min: "0", max: "255", value: obj.powerTolerance}, null)),
|
||||
divRow("{#ZE_GROUP_TAB_ADVANCED_POWERMAX}", ml("input", {name: "powerMax", class: "text", type: "number", min: "0", max: "65535", value: obj.powerMax}, null)),
|
||||
]),
|
||||
// Global
|
||||
ml("div", {class: "row mt-5"}, [
|
||||
ml("div", {class: "col-8", id: "res"}, ""),
|
||||
ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#ZE_GROUP_EDIT_BTN_SAVE}", class: "btn", onclick: function() { save(); }}, null))
|
||||
])
|
||||
]);
|
||||
|
||||
modal("{#ZE_GROUP_EDIT_MODAL}: " + obj.id, html);
|
||||
// ser.dispatchEvent(new Event('change'));
|
||||
|
||||
// Inhalt für pm_type aus config laden und in eine Funktion ausgliedern
|
||||
var e = document.getElementById("pm_type");
|
||||
selDelAllOpt(e);
|
||||
// TODO: übersetzen?
|
||||
e.appendChild(opt("0", "---"));
|
||||
e.appendChild(opt("1", "Shelly"));
|
||||
e.appendChild(opt("2", "Tasmota"));
|
||||
e.appendChild(opt("3", "Mqtt"));
|
||||
e.appendChild(opt("4", "Hichi"));
|
||||
e.appendChild(opt("5", "Tibber"));
|
||||
for (var i = 0; i < e.options.length; i++) {
|
||||
if (e.options[i].value == obj.pm_type) {
|
||||
e.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Tab_Inverters
|
||||
// - Enabled
|
||||
for (var inv = 0; inv < maxInv; inv++) {
|
||||
var e = document.getElementById("invEnabled"+inv);
|
||||
e.checked = (obj.inverters[inv].enabled);
|
||||
}
|
||||
// - InverterId
|
||||
for (var inv = 0; inv < maxInv; inv++) {
|
||||
var e = document.getElementById("invId"+inv);
|
||||
selDelAllOpt(e);
|
||||
e.appendChild(opt("-1", "---"));
|
||||
for (var i = 0; i < ivObj.inverter.length; i++) {
|
||||
e.appendChild(opt((ivObj.inverter[i].id), (ivObj.inverter[i].name)));
|
||||
}
|
||||
for (var i = 0; i < (e.length); i++) {
|
||||
if (e.options[i].value == obj.inverters[inv].id) {
|
||||
e.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// - Target
|
||||
for (var inv = 0; inv < maxInv; inv++) {
|
||||
var e = document.getElementById("invTarget"+inv);
|
||||
selDelAllOpt(e);
|
||||
// TODO: übersetzen?
|
||||
e.appendChild(opt("-1", "---"));
|
||||
e.appendChild(opt("0", "Sum"));
|
||||
e.appendChild(opt("1", "L1"));
|
||||
e.appendChild(opt("2", "L2"));
|
||||
e.appendChild(opt("3", "L3"));
|
||||
e.appendChild(opt("4", "L1 + Sum"));
|
||||
e.appendChild(opt("5", "L2 + Sum"));
|
||||
e.appendChild(opt("6", "L3 + Sum"));
|
||||
for (var i = 0; i < e.options.length; i++) {
|
||||
if (e.options[i].value == obj.inverters[inv].target) {
|
||||
e.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// - twoPercent
|
||||
for (var inv = 0; inv < maxInv; inv++) {
|
||||
var e = document.getElementById("invTwoPercent"+inv);
|
||||
e.checked = (obj.inverters[inv].twoPercent);
|
||||
}
|
||||
// - powerMax
|
||||
for (var inv = 0; inv < maxInv; inv++) {
|
||||
var e = document.getElementById("invPowerMax"+inv);
|
||||
e.value = (obj.inverters[inv].powerMax);
|
||||
}
|
||||
|
||||
function save() {
|
||||
var o = new Object();
|
||||
o.cmd = "ze_save_group"
|
||||
// o.token = "*"
|
||||
// General
|
||||
o.id = obj.id
|
||||
o.enabled = document.getElementsByName("enabled")[0].checked;
|
||||
o.name = document.getElementsByName("name")[0].value;
|
||||
// Powermeter
|
||||
//o.pm_type = document.getElementsByName("pm_type")[0].selectedIndex;
|
||||
var e = document.getElementsByName("pm_type")[0];
|
||||
o.pm_type = e.options[e.selectedIndex].value;
|
||||
o.pm_url = document.getElementsByName("pm_url")[0].value;
|
||||
o.pm_jsonPath = document.getElementsByName("pm_jsonPath")[0].value;
|
||||
o.pm_user = document.getElementsByName("pm_user")[0].value;
|
||||
o.pm_pass = document.getElementsByName("pm_pass")[0].value;
|
||||
// Inverters
|
||||
o.invMax = document.getElementById("invMax").value;
|
||||
o.inverters = [];
|
||||
for(var inv = 0; inv < o.invMax; inv++) {
|
||||
var q = new Object();
|
||||
q.enabled = document.getElementById("invEnabled"+inv).checked;
|
||||
var e = document.getElementById("invId"+inv);
|
||||
q.id = e.options[e.selectedIndex].value;
|
||||
var e = document.getElementById("invTarget"+inv);
|
||||
q.target = e.options[e.selectedIndex].value;
|
||||
q.twoPercent = document.getElementById("invTwoPercent"+inv).checked;
|
||||
q.powerMax = document.getElementById("invPowerMax"+inv).value;
|
||||
o.inverters.push(q);
|
||||
}
|
||||
// Battery
|
||||
o.battEnabled = document.getElementsByName("battEnabled")[0].checked;
|
||||
o.battVoltageOn = document.getElementsByName("battVoltageOn")[0].value;
|
||||
o.battVoltageOff = document.getElementsByName("battVoltageOff")[0].value;
|
||||
// Advanced
|
||||
o.refresh = document.getElementsByName("refresh")[0].value;
|
||||
o.powerTolerance = document.getElementsByName("powerTolerance")[0].value;
|
||||
o.powerMax = document.getElementsByName("powerMax")[0].value;
|
||||
// Global
|
||||
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
|
||||
}
|
||||
|
||||
function cb(obj2) {
|
||||
var e = document.getElementById("res");
|
||||
if(!obj2.success)
|
||||
e.innerHTML = "{#ERROR}" + obj2.error;
|
||||
else {
|
||||
modalClose();
|
||||
getAjax("/api/setup", parse);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ZeroExportGroup_Del(obj) {
|
||||
var html = ml("div", {class: "row"}, [
|
||||
ml("div", {class: "col-9"}, "{#ZE_GROUP_DELETE_SURE} (" + obj.name + ")"),
|
||||
ml("div", {class: "col-3 a-r"}, ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#ZE_GROUP_DELETE_BTN_YES}", class: "btn", onclick: function() { del(); }}, null)))
|
||||
]);
|
||||
modal("{#ZE_GROUP_DELETE_MODAL}: " + obj.name, html);
|
||||
|
||||
function del() {
|
||||
// TODO: Es wäre gut, wenn die Defaultwerte nicht hier sondern wie in der settings.h gesetzt würden.
|
||||
var o = new Object();
|
||||
o.cmd = "ze_save_group";
|
||||
// General
|
||||
o.id = obj.id;
|
||||
o.enabled = false;
|
||||
o.name = "";
|
||||
// Powermeter
|
||||
o.pm_type = 0;
|
||||
o.pm_url = "";
|
||||
o.pm_jsonPath = "";
|
||||
o.pm_user = "";
|
||||
o.pm_pass = "";
|
||||
// Inverters
|
||||
o.invMax = obj.inverters.length;
|
||||
o.inverters = [];
|
||||
for(var inv = 0; inv < o.invMax; inv++) {
|
||||
var q = new Object();
|
||||
q.enabled = false;
|
||||
var e = document.getElementById("invId"+inv);
|
||||
q.id = -1;
|
||||
var e = document.getElementById("invTarget"+inv);
|
||||
q.target = -1;
|
||||
q.twoPercent = false;
|
||||
q.powerMax = 0;
|
||||
o.inverters.push(q);
|
||||
}
|
||||
// Battery
|
||||
o.battEnabled = false;
|
||||
o.battVoltageOn = 0;
|
||||
o.battVoltageOff = 0;
|
||||
// Advanced
|
||||
o.refresh = 10;
|
||||
o.powerTolerance = 10;
|
||||
o.powerMax = 600;
|
||||
// Global
|
||||
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
|
||||
}
|
||||
|
||||
function cb(obj) {
|
||||
if(obj.success) {
|
||||
modalClose();
|
||||
getAjax("/api/setup", parse);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Plugin ZeroExport - Ende
|
||||
/*ENDIF_PLUGIN_ZEROEXPORT*/
|
||||
|
||||
function parseZeroExport(obj, type) {
|
||||
|
||||
/*IF_PLUGIN_ZEROEXPORT*/
|
||||
// Plugin ZeroExport
|
||||
|
||||
// enabled
|
||||
document.getElementsByName("ze_enabled")[0].checked = obj["enabled"];
|
||||
|
||||
// groups
|
||||
maxGroups = obj["max_groups"];
|
||||
|
||||
var lines = [];
|
||||
|
||||
lines.push(ml("tr", {}, [
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_ENABLED}"),
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_ID}"),
|
||||
ml("th", {style: "text-align: center;"}, "{#ZE_GROUP_NAME}"),
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_POWERTOTAL}"),
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_EDIT}"),
|
||||
ml("th", {style: "width: 10%; text-align: center;"}, "{#ZE_GROUP_DELETE}")
|
||||
]));
|
||||
|
||||
for(let group = 0; group < obj.groups.length; group++) {
|
||||
lines.push(ml("tr", {}, [
|
||||
ml("td", {style: "text-align: left;", }, badge(obj.groups[group].enabled, (obj.groups[group].enabled) ? "{#ENABLED}" : "{#DISABLED}")),
|
||||
ml("td", {style: "text-align: center;", }, String(obj.groups[group].id)),
|
||||
ml("td", {style: "text-align: left;", }, String(obj.groups[group].name)),
|
||||
ml("td", {style: "text-align: right;", id: "groupPowerTotal"+group}, "n/a"),
|
||||
ml("td", {style: "text-align: center;", onclick: function() {
|
||||
function zeroGetIvList(ivObj) {
|
||||
ZeroExportGroup_Modal(obj.groups[group], ivObj)
|
||||
}
|
||||
getAjax("/api/inverter/list", zeroGetIvList)
|
||||
}}, svg(iconGear, 25, 25, "icon icon-fg pointer")),
|
||||
ml("td", {style: "text-align: center;", onclick: function() {ZeroExportGroup_Del(obj.groups[group]);}}, svg(iconDel, 25, 25, "icon icon-fg pointer"))
|
||||
]));
|
||||
}
|
||||
|
||||
// TODO: Das Add sollte anders / überhaupt gelöst werden
|
||||
var add = new Object();
|
||||
add.enabled = true;
|
||||
add.id = obj.groups.length;
|
||||
add.name = "";
|
||||
// add.ch_max_pwr = [400,400,400,400,400,400];
|
||||
// add.ch_name = [];
|
||||
// add.ch_yield_cor = [];
|
||||
// add.freq = 12;
|
||||
// add.pa = 30;
|
||||
|
||||
var e = document.getElementById("ze_groups");
|
||||
e.innerHTML = ""; // remove all childs
|
||||
e.append(ml("table", {class: "table"}, ml("tbody", {}, lines)));
|
||||
if(maxGroups > obj.groups.length) {
|
||||
e.append(ml("div", {class: "row my-3"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "{#BTN_INV_ADD}", class: "btn", onclick: function() { ZeroExportGroup_Modal(add); }}, null))));
|
||||
}
|
||||
|
||||
// ivGlob(obj);
|
||||
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
/*ELIF_PLUGIN_ZEROEXPORT*/
|
||||
if ("ESP32-S3" != type) {
|
||||
// TODO: entfernen wenn ELIF funktioniert
|
||||
var e = document.getElementById("zeroExport");
|
||||
e.remove();
|
||||
|
||||
var e = document.getElementById("zeroExport_button");
|
||||
e.textContent += " (only for ESP32 available)";
|
||||
e.textContent += " (only for ESP32-S3 available)";
|
||||
e.disabled = true;
|
||||
element.classList.add("disabled");
|
||||
// TODO: übersetzen? / Überflüssig? Das Modul ist so immer sichtbar und zeigt was es braucht.
|
||||
}
|
||||
/*ENDIF_PLUGIN_ZEROEXPORT*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementsByName("en_zeroexport")[0].checked = obj["en_zeroexport"];
|
||||
document.getElementsByName("two_percent")[0].checked = obj["two_percent"];
|
||||
|
||||
document.getElementsByName("dev_Tibber")[0].checked = (obj["query_device"] == 1);
|
||||
document.getElementsByName("dev_Shelly")[0].checked = (obj["query_device"] == 2);
|
||||
document.getElementsByName("dev_Other")[0].checked = (obj["query_device"] == 3);
|
||||
|
||||
|
||||
getAjax("/api/inverter/list", parseZeroIv);
|
||||
|
||||
for(var i of [["monitor_url", "monitor_url"], ["power_avg", "power_avg"], ["count_avg", "count_avg"], ["json_path", "json_path"], ["max_power", "max_power"], ["query_device", "query_device"]])
|
||||
if(null != obj[i[1]])
|
||||
document.getElementsByName(i[0])[0].value = obj[i[1]];
|
||||
|
||||
document.getElementsByName("total_power")[0].innerHTML = "Total: " + obj["total_power"].toFixed(2) + "W";
|
||||
document.getElementById("Inv_ID").selectedIndex = obj["Iv"];
|
||||
}
|
||||
|
||||
function parseZeroIv(root)
|
||||
{
|
||||
for(var i = 0; i < root.inverter.length; i++)
|
||||
root.inverter[i];
|
||||
|
||||
select = document.getElementById('Inv_ID');
|
||||
parseInt(select.value)
|
||||
|
||||
if(null == root) return;
|
||||
root = root.inverter;
|
||||
for(var i = 0; i < root.length; i++) {
|
||||
inv = root[i];
|
||||
var opt = document.createElement('option');
|
||||
opt.value = inv.id;
|
||||
opt.innerHTML = inv.name;
|
||||
select.appendChild(opt);
|
||||
}
|
||||
}
|
||||
|
||||
function parse(root) {
|
||||
|
@ -1265,10 +1564,10 @@
|
|||
/*IF_ESP32*/
|
||||
parseCmtRadio(root["radioCmt"], root["system"]["esp_type"], root["system"]);
|
||||
/*ENDIF_ESP32*/
|
||||
parsezeroExport(root["zeroExport"], root["system"]["esp_type"]);
|
||||
|
||||
parseSerial(root["serial"]);
|
||||
parseDisplay(root["display"], root["system"]["esp_type"], root["system"]);
|
||||
parseZeroExport(root["zeroExport"], root["system"]["esp_type"]);
|
||||
|
||||
getAjax("/api/inverter/list", parseIv);
|
||||
}
|
||||
|
|
|
@ -767,6 +767,191 @@
|
|||
"token": "NO_NETWORK_FOUND",
|
||||
"en": "no network found",
|
||||
"de": "kein Netzwerk gefunden"
|
||||
},
|
||||
{
|
||||
"token": "ZE",
|
||||
"en": "Demand-optimized power control",
|
||||
"de": "Bedarfsorientierte Leistungsregelung"
|
||||
},
|
||||
{
|
||||
"token": "ZE_ENABLED",
|
||||
"en": "Enabled",
|
||||
"de": "Aktiviert"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_ENABLED",
|
||||
"en": "State:",
|
||||
"de": "Status:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_ID",
|
||||
"en": "Group:",
|
||||
"de": "Gruppe:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_NAME",
|
||||
"en": "Name:",
|
||||
"de": "Name:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_POWERTOTAL",
|
||||
"en": "PowerTotal (W):",
|
||||
"de": "Leistung (W):"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_EDIT",
|
||||
"en": "Edit",
|
||||
"de": "Bearbeiten"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_DELETE",
|
||||
"en": "Delete",
|
||||
"de": "Löschen"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_EDIT_MODAL",
|
||||
"en": "Edit group",
|
||||
"de": "Gruppe bearbeiten"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_GENERAL",
|
||||
"en": "General:",
|
||||
"de": "Allgemein:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_GENERAL_GRUPPE",
|
||||
"en": "Group:",
|
||||
"de": "Gruppe:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_GENERAL_ENABLE",
|
||||
"en": "Enabled:",
|
||||
"de": "Aktiviert:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_GENERAL_NAME",
|
||||
"en": "Name:",
|
||||
"de": "Name:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_POWERMETER",
|
||||
"en": "Powermeter",
|
||||
"de": "Leistungsmessung"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_POWERMETER_TYPE",
|
||||
"en": "Type:",
|
||||
"de": "Typ:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_POWERMETER_URL",
|
||||
"en": "Url:",
|
||||
"de": "Url:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_POWERMETER_JSONPATH",
|
||||
"en": "JSON Path:",
|
||||
"de": "JSON Pfad:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_POWERMETER_USER",
|
||||
"en": "Username:",
|
||||
"de": "Benutzername:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_POWERMETER_PASS",
|
||||
"en": "Password:",
|
||||
"de": "Passwort:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_INVERTER",
|
||||
"en": "Inverter",
|
||||
"de": "Wechselrichter"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_INVERTER_ENABLED",
|
||||
"en": "Enabled:",
|
||||
"de": "Aktiviert:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_INVERTER_NAME",
|
||||
"en": "Name",
|
||||
"de": "Name"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_INVERTER_SUM",
|
||||
"en": "Sum",
|
||||
"de": "Gesamt"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_INVERTER_TWOPERCENT",
|
||||
"en": "2%",
|
||||
"de": "2%"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_INVERTER_POWERMAX",
|
||||
"en": "Power (Max)",
|
||||
"de": "Leistung (Max)"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_BATTERY",
|
||||
"en": "Battery",
|
||||
"de": "Batterie"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_BATTERY_BATTENABLED",
|
||||
"en": "Enabled:",
|
||||
"de": "Aktiviert:"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_BATTERY_BATTVOLTAGEON",
|
||||
"en": "Voltage on (Volt):",
|
||||
"de": "Spannung Ein (Volt):"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_BATTERY_BATTVOLTAGEOFF",
|
||||
"en": "Voltage off (Volt):",
|
||||
"de": "Spannung Aus (Volt):"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_ADVANCED",
|
||||
"en": "Advanced",
|
||||
"de": "Erweitert"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_ADVANCED_REFRESH",
|
||||
"en": "Refresh rate (sec):",
|
||||
"de": "Aktualisierung (sec):"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_ADVANCED_POWERTOLERANCE",
|
||||
"en": "Power tolerances (Watt):",
|
||||
"de": "Leistung Toleranz (Watt)"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_TAB_ADVANCED_POWERMAX",
|
||||
"en": "Group Power max (Watt):",
|
||||
"de": "Gruppe Leistung Max (Watt):"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_EDIT_BTN_SAVE",
|
||||
"en": "save",
|
||||
"de": "speichern"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_DELETE_MODAL",
|
||||
"en": "Delete group",
|
||||
"de": "Gruppe löschen "
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_DELETE_SURE",
|
||||
"en": "do you really want to delete group?",
|
||||
"de": "Willst du die Gruppe wirklich löschen?"
|
||||
},
|
||||
{
|
||||
"token": "ZE_GROUP_DELETE_BTN_YES",
|
||||
"en": "yes",
|
||||
"de": "ja"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -549,39 +549,6 @@ class Web {
|
|||
mConfig->mqtt.port = request->arg("mqttPort").toInt();
|
||||
mConfig->mqtt.interval = request->arg("mqttInterval").toInt();
|
||||
|
||||
// zero-export
|
||||
#if defined(ESP32)
|
||||
mConfig->plugin.zexport.enabled = (request->arg("en_zeroexport") == "on");
|
||||
mConfig->plugin.zexport.two_percent = (request->arg("two_percent") == "on");
|
||||
mConfig->plugin.zexport.Iv = request->arg("Iv").toInt();
|
||||
mConfig->plugin.zexport.count_avg = request->arg("count_avg").toInt();
|
||||
mConfig->plugin.zexport.max_power = request->arg("max_power").toDouble();
|
||||
mConfig->plugin.zexport.power_avg = request->arg("power_avg").toFloat();
|
||||
mConfig->plugin.zexport.query_device = request->arg("query_device").toInt();
|
||||
mConfig->plugin.zexport.total_power = request->arg("total_power").toDouble();
|
||||
|
||||
if (request->arg("monitor_url") != "") {
|
||||
String addr = request->arg("monitor_url");
|
||||
addr.trim();
|
||||
addr.toCharArray(mConfig->plugin.zexport.monitor_url, ZEXPORT_ADDR_LEN);
|
||||
} else
|
||||
mConfig->plugin.zexport.monitor_url[0] = '\0';
|
||||
|
||||
if (request->arg("json_path") != "") {
|
||||
String addr = request->arg("json_path");
|
||||
addr.trim();
|
||||
addr.toCharArray(mConfig->plugin.zexport.json_path, ZEXPORT_ADDR_LEN);
|
||||
} else
|
||||
mConfig->plugin.zexport.json_path[0] = '\0';
|
||||
|
||||
if (request->arg("tibber_pw") != "") {
|
||||
String addr = request->arg("tibber_pw");
|
||||
addr.trim();
|
||||
addr.toCharArray(mConfig->plugin.zexport.tibber_pw, 10);
|
||||
} else
|
||||
mConfig->plugin.zexport.tibber_pw[0] = '\0';
|
||||
#endif
|
||||
|
||||
// serial console
|
||||
mConfig->serial.debug = (request->arg("serDbg") == "on");
|
||||
mConfig->serial.privacyLog = (request->arg("priv") == "on");
|
||||
|
@ -619,6 +586,43 @@ class Web {
|
|||
mConfig->plugin.display.pirPin = (mConfig->plugin.display.screenSaver != DISP_TYPE_T2_SH1106_128X64) ? DEF_PIN_OFF : request->arg("pir_pin").toInt(); // pir pin only for motion screensaver
|
||||
#endif // otherweise default value
|
||||
|
||||
// Plugin ZeroExport
|
||||
#if defined(PLUGIN_ZEROEXPORT)
|
||||
mConfig->plugin.zeroExport.enabled = (request->arg("ze_enabled") == "on");
|
||||
// TODO: sortieren
|
||||
// mConfig->plugin.zeroExport.enabled = (request->arg("en_zeroexport") == "on");
|
||||
// mConfig->plugin.zeroExport.two_percent = (request->arg("two_percent") == "on");
|
||||
// mConfig->plugin.zeroExport.Iv = request->arg("Iv").toInt();
|
||||
// mConfig->plugin.zeroExport.count_avg = request->arg("count_avg").toInt();
|
||||
// mConfig->plugin.zeroExport.max_power = request->arg("max_power").toDouble();
|
||||
// mConfig->plugin.zeroExport.power_avg = request->arg("power_avg").toFloat();
|
||||
// mConfig->plugin.zeroExport.query_device = request->arg("query_device").toInt();
|
||||
// mConfig->plugin.zeroExport.total_power = request->arg("total_power").toDouble();
|
||||
/*
|
||||
if (request->arg("monitor_url") != "") {
|
||||
String addr = request->arg("monitor_url");
|
||||
addr.trim();
|
||||
addr.toCharArray(mConfig->plugin.zeroExport.monitor_url, ZEXPORT_ADDR_LEN);
|
||||
} else
|
||||
mConfig->plugin.zeroExport.monitor_url[0] = '\0';
|
||||
|
||||
if (request->arg("json_path") != "") {
|
||||
String addr = request->arg("json_path");
|
||||
addr.trim();
|
||||
addr.toCharArray(mConfig->plugin.zeroExport.json_path, ZEXPORT_ADDR_LEN);
|
||||
} else
|
||||
mConfig->plugin.zeroExport.json_path[0] = '\0';
|
||||
|
||||
if (request->arg("tibber_pw") != "") {
|
||||
String addr = request->arg("tibber_pw");
|
||||
addr.trim();
|
||||
addr.toCharArray(mConfig->plugin.zeroExport.tibber_pw, 10);
|
||||
} else
|
||||
mConfig->plugin.zeroExport.tibber_pw[0] = '\0';
|
||||
*/
|
||||
#endif
|
||||
// Plugin ZeroExport - Ende
|
||||
|
||||
mApp->saveSettings((request->arg("reboot") == "on"));
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue