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 {} {
|
app::app() : ah::Scheduler {} {
|
||||||
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
memset(mVersion, 0, sizeof(char) * 17);
|
memset(mVersion, 0, sizeof(char) * 17);
|
||||||
|
#else
|
||||||
|
memset(mVersion, 0, sizeof(char) * 12);
|
||||||
|
#endif
|
||||||
memset(mVersionModules, 0, sizeof(char) * 12);
|
memset(mVersionModules, 0, sizeof(char) * 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,17 +122,21 @@ void app::setup() {
|
||||||
|
|
||||||
esp_task_wdt_reset();
|
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)
|
#if defined(ENABLE_HISTORY)
|
||||||
mHistory.setup(this, &mSys, mConfig, &mTimestamp);
|
mHistory.setup(this, &mSys, mConfig, &mTimestamp);
|
||||||
#endif /*ENABLE_HISTORY*/
|
#endif /*ENABLE_HISTORY*/
|
||||||
|
|
||||||
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
|
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
|
||||||
|
|
||||||
// ZeroExport
|
|
||||||
if (mConfig->plugin.zexport.enabled) {
|
|
||||||
mzExport.setup(&mConfig->plugin.zexport, &mSys, mConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(ETHERNET)
|
#if !defined(ETHERNET)
|
||||||
//mImprov.setup(this, mConfig->sys.deviceName, mVersion);
|
//mImprov.setup(this, mConfig->sys.deviceName, mVersion);
|
||||||
#endif
|
#endif
|
||||||
|
@ -164,6 +172,15 @@ void app::loop(void) {
|
||||||
if (mMqttEnabled && mNetworkConnected)
|
if (mMqttEnabled && mNetworkConnected)
|
||||||
mMqtt.loop();
|
mMqtt.loop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Plugin ZeroExport
|
||||||
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
|
if(mConfig->nrf.enabled || mConfig->cmt.enabled) {
|
||||||
|
mZeroExport.loop();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,11 +214,14 @@ void app::regularTickers(void) {
|
||||||
everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp");
|
everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ZeroExport
|
// Plugin ZeroExport
|
||||||
#if defined(PLUGIN_ZEROEXPORT)
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
if (mConfig->plugin.zexport.enabled)
|
// TODO: aufräumen
|
||||||
everySec(std::bind(&ZeroExportType::tickerSecond, &mzExport), "zExport");
|
// if (mConfig->plugin.zeroExport.enabled) {
|
||||||
|
everySec(std::bind(&ZeroExportType::tickerSecond, &mZeroExport), "ZeroExport");
|
||||||
|
// }
|
||||||
#endif
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
|
|
||||||
every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart");
|
every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart");
|
||||||
#if !defined(ETHERNET)
|
#if !defined(ETHERNET)
|
||||||
|
@ -458,9 +478,15 @@ void app::tickSend(void) {
|
||||||
mCommunication.add(iv, cmd);
|
mCommunication.add(iv, cmd);
|
||||||
});
|
});
|
||||||
|
|
||||||
#if defined(ESP32)
|
// Plugin ZeroExport
|
||||||
if(mConfig->nrf.enabled || mConfig->cmt.enabled) zeroexport();
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
|
// TODO: aufräumen
|
||||||
|
if(mConfig->nrf.enabled || mConfig->cmt.enabled) {
|
||||||
|
mZeroExport.loop();
|
||||||
|
// zeroexport();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +547,11 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) {
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void app::resetSystem(void) {
|
void app::resetSystem(void) {
|
||||||
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
snprintf(mVersion, sizeof(mVersion), "zero-%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
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",
|
snprintf(mVersionModules, sizeof(mVersionModules), "%s",
|
||||||
#ifdef ENABLE_PROMETHEUS_EP
|
#ifdef ENABLE_PROMETHEUS_EP
|
||||||
"P"
|
"P"
|
||||||
|
@ -635,37 +665,45 @@ void app::updateLed(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#if defined(ESP32)
|
// Plugin ZeroExport
|
||||||
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
void app::zeroexport() {
|
void app::zeroexport() {
|
||||||
if (!mConfig->plugin.zexport.enabled ||
|
return;
|
||||||
!mSys.getInverterByPos(mConfig->plugin.zexport.Iv)->isProducing()) { // check if plugin is enabled && indicate to send new value
|
// TODO: aufräumen
|
||||||
mConfig->plugin.zexport.lastTime = millis(); // set last timestamp
|
// 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;
|
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);
|
DynamicJsonDocument doc(512);
|
||||||
JsonObject object = doc.to<JsonObject>();
|
JsonObject object = doc.to<JsonObject>();
|
||||||
|
|
||||||
double nValue = round(mzExport.getPowertoSetnewValue());
|
double nValue = round(mZeroExport.getPowertoSetnewValue());
|
||||||
double twoPerVal = nValue <= (iv->getMaxPower() / 100 * 2 );
|
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;
|
nValue = twoPerVal;
|
||||||
|
|
||||||
if(mConfig->plugin.zexport.max_power <= nValue)
|
if(mConfig->plugin.zeroExport.max_power <= nValue)
|
||||||
nValue = mConfig->plugin.zexport.max_power;
|
nValue = mConfig->plugin.zeroExport.max_power;
|
||||||
|
|
||||||
if(iv->actPowerLimit == nValue) {
|
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
|
return; // if PowerLimit same as befor, then skip
|
||||||
}
|
}
|
||||||
|
|
||||||
object["val"] = nValue;
|
object["val"] = nValue;
|
||||||
object["id"] = mConfig->plugin.zexport.Iv;
|
object["id"] = mConfig->plugin.zeroExport.Iv;
|
||||||
object["path"] = "ctrl";
|
object["path"] = "ctrl";
|
||||||
object["cmd"] = "limit_nonpersistent_absolute";
|
object["cmd"] = "limit_nonpersistent_absolute";
|
||||||
|
|
||||||
|
@ -674,7 +712,9 @@ void app::zeroexport() {
|
||||||
DPRINTLN(DBG_INFO, data);
|
DPRINTLN(DBG_INFO, data);
|
||||||
mApi.ctrlRequest(object);
|
mApi.ctrlRequest(object);
|
||||||
|
|
||||||
mConfig->plugin.zexport.lastTime = millis(); // set last timestamp
|
mConfig->plugin.zeroExport.lastTime = millis(); // set last timestamp
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
typedef Display<HmSystemType, Radio> DisplayType;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Plugin ZeroExport
|
||||||
#if defined(PLUGIN_ZEROEXPORT)
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
#include "plugins/zeroExport/zeroExport.h"
|
#include "plugins/zeroExport/zeroExport.h"
|
||||||
typedef ZeroExport<HmSystemType> ZeroExportType;
|
typedef ZeroExport<HmSystemType> ZeroExportType;
|
||||||
#endif
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
|
|
||||||
class app : public IApp, public ah::Scheduler {
|
class app : public IApp, public ah::Scheduler {
|
||||||
public:
|
public:
|
||||||
|
@ -353,9 +355,11 @@ class app : public IApp, public ah::Scheduler {
|
||||||
void setupLed();
|
void setupLed();
|
||||||
void updateLed();
|
void updateLed();
|
||||||
|
|
||||||
#if defined(ESP32)
|
// Plugin ZeroExport
|
||||||
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
void zeroexport();
|
void zeroexport();
|
||||||
#endif
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
|
|
||||||
void tickReboot(void) {
|
void tickReboot(void) {
|
||||||
DPRINTLN(DBG_INFO, F("Rebooting..."));
|
DPRINTLN(DBG_INFO, F("Rebooting..."));
|
||||||
|
@ -423,7 +427,11 @@ class app : public IApp, public ah::Scheduler {
|
||||||
CmtRadio<> mCmtRadio;
|
CmtRadio<> mCmtRadio;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
char mVersion[17];
|
char mVersion[17];
|
||||||
|
#else
|
||||||
|
char mVersion[12];
|
||||||
|
#endif
|
||||||
char mVersionModules[12];
|
char mVersionModules[12];
|
||||||
settings mSettings;
|
settings mSettings;
|
||||||
settings_t *mConfig = nullptr;
|
settings_t *mConfig = nullptr;
|
||||||
|
@ -460,9 +468,11 @@ class app : public IApp, public ah::Scheduler {
|
||||||
SimulatorType mSimulator;
|
SimulatorType mSimulator;
|
||||||
#endif /*ENABLE_SIMULATOR*/
|
#endif /*ENABLE_SIMULATOR*/
|
||||||
|
|
||||||
|
// Plugin ZeroExport
|
||||||
#if defined(PLUGIN_ZEROEXPORT)
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
ZeroExportType mzExport;
|
ZeroExportType mZeroExport;
|
||||||
#endif
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__APP_H__*/
|
#endif /*__APP_H__*/
|
||||||
|
|
|
@ -139,24 +139,6 @@ typedef struct {
|
||||||
uint16_t interval;
|
uint16_t interval;
|
||||||
} cfgMqtt_t;
|
} 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 {
|
typedef struct {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
char name[MAX_NAME_LENGTH];
|
char name[MAX_NAME_LENGTH];
|
||||||
|
@ -203,14 +185,133 @@ typedef struct {
|
||||||
} display_t;
|
} display_t;
|
||||||
#endif
|
#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 {
|
typedef struct {
|
||||||
#if defined(PLUGIN_DISPLAY)
|
#if defined(PLUGIN_DISPLAY)
|
||||||
display_t display;
|
display_t display;
|
||||||
#endif
|
#endif
|
||||||
char customLink[MAX_CUSTOM_LINK_LEN];
|
char customLink[MAX_CUSTOM_LINK_LEN];
|
||||||
char customLinkText[MAX_CUSTOM_LINK_TEXT_LEN];
|
char customLinkText[MAX_CUSTOM_LINK_TEXT_LEN];
|
||||||
#if defined(ESP32)
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
cfgzeroExport_t zexport;
|
zeroExport_t zeroExport;
|
||||||
#endif
|
#endif
|
||||||
} plugins_t;
|
} plugins_t;
|
||||||
|
|
||||||
|
@ -315,7 +416,6 @@ class settings {
|
||||||
if(root.containsKey(F("nrf"))) jsonNrf(root[F("nrf")]);
|
if(root.containsKey(F("nrf"))) jsonNrf(root[F("nrf")]);
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
if(root.containsKey(F("cmt"))) jsonCmt(root[F("cmt")]);
|
if(root.containsKey(F("cmt"))) jsonCmt(root[F("cmt")]);
|
||||||
if(root.containsKey(F("zeroExport"))) jsonzeroExport(root[F("zeroExport")]);
|
|
||||||
#endif
|
#endif
|
||||||
if(root.containsKey(F("ntp"))) jsonNtp(root[F("ntp")]);
|
if(root.containsKey(F("ntp"))) jsonNtp(root[F("ntp")]);
|
||||||
if(root.containsKey(F("sun"))) jsonSun(root[F("sun")]);
|
if(root.containsKey(F("sun"))) jsonSun(root[F("sun")]);
|
||||||
|
@ -345,7 +445,6 @@ class settings {
|
||||||
jsonNrf(root[F("nrf")].to<JsonObject>(), true);
|
jsonNrf(root[F("nrf")].to<JsonObject>(), true);
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
jsonCmt(root[F("cmt")].to<JsonObject>(), true);
|
jsonCmt(root[F("cmt")].to<JsonObject>(), true);
|
||||||
jsonzeroExport(root.createNestedObject(F("zeroExport")), true);
|
|
||||||
#endif
|
#endif
|
||||||
jsonNtp(root[F("ntp")].to<JsonObject>(), true);
|
jsonNtp(root[F("ntp")].to<JsonObject>(), true);
|
||||||
jsonSun(root[F("sun")].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);
|
snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC);
|
||||||
mCfg.mqtt.interval = 0; // off
|
mCfg.mqtt.interval = 0; // off
|
||||||
|
|
||||||
// Zero-Export
|
mCfg.inst.sendInterval = SEND_INTERVAL;
|
||||||
#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.rstYieldMidNight = false;
|
mCfg.inst.rstYieldMidNight = false;
|
||||||
mCfg.inst.rstValsNotAvail = false;
|
mCfg.inst.rstValsNotAvail = false;
|
||||||
mCfg.inst.rstValsCommStop = false;
|
mCfg.inst.rstValsCommStop = false;
|
||||||
|
@ -523,6 +607,77 @@ class settings {
|
||||||
mCfg.plugin.display.disp_dc = DEF_PIN_OFF;
|
mCfg.plugin.display.disp_dc = DEF_PIN_OFF;
|
||||||
mCfg.plugin.display.pirPin = DEF_PIN_OFF;
|
mCfg.plugin.display.pirPin = DEF_PIN_OFF;
|
||||||
#endif
|
#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() {
|
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) {
|
void jsonLed(JsonObject obj, bool set = false) {
|
||||||
if(set) {
|
if(set) {
|
||||||
obj[F("0")] = mCfg.led.led[0];
|
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) {
|
void jsonPlugin(JsonObject obj, bool set = false) {
|
||||||
if(set) {
|
if(set) {
|
||||||
#if defined(PLUGIN_DISPLAY)
|
#if defined(PLUGIN_DISPLAY)
|
||||||
|
@ -810,6 +1041,11 @@ class settings {
|
||||||
#endif
|
#endif
|
||||||
obj[F("cst_lnk")] = mCfg.plugin.customLink;
|
obj[F("cst_lnk")] = mCfg.plugin.customLink;
|
||||||
obj[F("cst_lnk_txt")] = mCfg.plugin.customLinkText;
|
obj[F("cst_lnk_txt")] = mCfg.plugin.customLinkText;
|
||||||
|
// Plugin ZeroExport
|
||||||
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
|
jsonZeroExport(obj.createNestedObject("zeroExport"), set);
|
||||||
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
} else {
|
} else {
|
||||||
#if defined(PLUGIN_DISPLAY)
|
#if defined(PLUGIN_DISPLAY)
|
||||||
JsonObject disp = obj["disp"];
|
JsonObject disp = obj["disp"];
|
||||||
|
@ -832,6 +1068,11 @@ class settings {
|
||||||
#endif
|
#endif
|
||||||
getChar(obj, F("cst_lnk"), mCfg.plugin.customLink, MAX_CUSTOM_LINK_LEN);
|
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);
|
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__
|
#ifndef __ZEROEXPORT__
|
||||||
#define __ZEROEXPORT__
|
#define __ZEROEXPORT__
|
||||||
|
@ -8,29 +8,232 @@
|
||||||
#include "AsyncJson.h"
|
#include "AsyncJson.h"
|
||||||
|
|
||||||
#include "SML.h"
|
#include "SML.h"
|
||||||
|
|
||||||
template <class HMSYSTEM>
|
template <class HMSYSTEM>
|
||||||
|
|
||||||
class ZeroExport {
|
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;
|
mCfg = cfg;
|
||||||
mSys = sys;
|
mSys = sys;
|
||||||
mConfig = config;
|
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() {
|
void tickerSecond() {
|
||||||
//DPRINTLN(DBG_INFO, (F("tickerSecond()")));
|
if ((!mIsInitialized) || (!mCfg->enabled)) {
|
||||||
if (millis() - mCfg->lastTime < mCfg->count_avg * 1000UL) {
|
return;
|
||||||
zero(); // just refresh when it is needed. To get cpu load low.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//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.
|
// 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
|
// If the value is negative, all power values from the inverter are taken into account
|
||||||
double getPowertoSetnewValue()
|
double getPowertoSetnewValue()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
float ivPower = 0;
|
float ivPower = 0;
|
||||||
Inverter<> *iv;
|
Inverter<> *iv;
|
||||||
record_t<> *rec;
|
record_t<> *rec;
|
||||||
|
@ -41,8 +244,9 @@ class ZeroExport {
|
||||||
continue;
|
continue;
|
||||||
ivPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
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
|
//C2T2-B91B
|
||||||
private:
|
private:
|
||||||
|
@ -51,6 +255,7 @@ class ZeroExport {
|
||||||
// TODO: Need to improve here. 2048 for a JSON Obj is to big!?
|
// TODO: Need to improve here. 2048 for a JSON Obj is to big!?
|
||||||
bool zero()
|
bool zero()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
httpClient.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
httpClient.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||||
httpClient.setUserAgent("Ahoy-Agent");
|
httpClient.setUserAgent("Ahoy-Agent");
|
||||||
httpClient.setConnectTimeout(1000);
|
httpClient.setConnectTimeout(1000);
|
||||||
|
@ -103,6 +308,7 @@ class ZeroExport {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
httpClient.end();
|
httpClient.end();
|
||||||
|
*/
|
||||||
return true;
|
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
|
// private member variables
|
||||||
cfgzeroExport_t *mCfg;
|
bool mIsInitialized = false;
|
||||||
|
zeroExport_t *mCfg;
|
||||||
settings_t *mConfig;
|
settings_t *mConfig;
|
||||||
HMSYSTEM *mSys;
|
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 /*__ZEROEXPORT__*/
|
||||||
|
|
||||||
#endif /* #if defined(ESP32) */
|
#endif /* #if defined(ESP32) */
|
|
@ -618,22 +618,6 @@ class RestApi {
|
||||||
obj[F("interval")] = String(mConfig->mqtt.interval);
|
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) {
|
void getNtp(JsonObject obj) {
|
||||||
obj[F("addr")] = String(mConfig->ntp.addr);
|
obj[F("addr")] = String(mConfig->ntp.addr);
|
||||||
obj[F("port")] = String(mConfig->ntp.port);
|
obj[F("port")] = String(mConfig->ntp.port);
|
||||||
|
@ -730,6 +714,49 @@ class RestApi {
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
void getMqttInfo(JsonObject obj) {
|
||||||
obj[F("enabled")] = (mConfig->mqtt.broker[0] != '\0');
|
obj[F("enabled")] = (mConfig->mqtt.broker[0] != '\0');
|
||||||
obj[F("connected")] = mApp->getMqttIsConnected();
|
obj[F("connected")] = mApp->getMqttIsConnected();
|
||||||
|
@ -798,10 +825,11 @@ class RestApi {
|
||||||
#if defined(PLUGIN_DISPLAY)
|
#if defined(PLUGIN_DISPLAY)
|
||||||
getDisplay(obj.createNestedObject(F("display")));
|
getDisplay(obj.createNestedObject(F("display")));
|
||||||
#endif
|
#endif
|
||||||
|
// Plugin ZeroExport
|
||||||
#if defined(ESP32)
|
#if defined(PLUGIN_ZEROEXPORT)
|
||||||
getzeroExport(obj.createNestedObject(F("zeroExport")));
|
getZeroExport(obj.createNestedObject(F("zeroExport")));
|
||||||
#endif
|
#endif
|
||||||
|
// Plugin ZeroExport - Ende
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(ETHERNET)
|
#if !defined(ETHERNET)
|
||||||
|
@ -955,7 +983,42 @@ class RestApi {
|
||||||
iv->config->powerLevel = jsonIn[F("pa")];
|
iv->config->powerLevel = jsonIn[F("pa")];
|
||||||
iv->config->disNightCom = jsonIn[F("disnightcom")];
|
iv->config->disNightCom = jsonIn[F("disnightcom")];
|
||||||
mApp->saveSettings(false); // without reboot
|
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");
|
jsonOut[F("error")] = F("ERR_UNKNOWN_CMD");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,50 +304,20 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Zero Export -->
|
<!-- Plugin ZeroExport -->
|
||||||
<button type="button" class="s_collapsible" id="zeroExport_button">Zero Export</button>
|
<button type="button" class="s_collapsible" id="zeroExport_button">{#ZE}</button>
|
||||||
<div class="s_content" id="zeroExport">
|
<div class="s_content" id="zeroExport">
|
||||||
<fieldset class="mb-4">
|
<fieldset class="mb-4">
|
||||||
<legend class="des">Zero Export</legend>
|
<legend class="des">{#ZE}</legend>
|
||||||
<div id="zeroType"></div>
|
<div id="zeroType"></div>
|
||||||
|
<div class="row mb-3">
|
||||||
<div class="row mb-3">
|
<div class="col-12 col-sm-3 my-2">{#ZE_ENABLED}</div>
|
||||||
<div class="col-8 col-sm-3">Enable zero export</div>
|
<div class="col-12 col-sm-9"><input type="checkbox" name="ze_enabled"/></div>
|
||||||
<div class="col-4 col-sm-9"><input type="checkbox" name="en_zeroexport"/></div>
|
</div>
|
||||||
<p>Please select your favorite query interface:</p>
|
<div id="ze_groups"></div>
|
||||||
</div>
|
</fieldset>
|
||||||
|
|
||||||
<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>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Plugin ZeroExport - Ende -->
|
||||||
|
|
||||||
<div class="row mb-4 mt-4">
|
<div class="row mb-4 mt-4">
|
||||||
<div class="col-8 col-sm-3">{#BTN_REBOOT_SUCCESSFUL_SAVE}</div>
|
<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)));
|
document.getElementById("date").innerHTML = toIsoDateStr((new Date((++ts) * 1000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsezeroExport(obj, type, ) {
|
/*IF_PLUGIN_ZEROEXPORT*/
|
||||||
if ("ESP8266" == type) {
|
// 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");
|
var e = document.getElementById("zeroExport");
|
||||||
e.remove();
|
e.remove();
|
||||||
|
|
||||||
var e = document.getElementById("zeroExport_button");
|
var e = document.getElementById("zeroExport_button");
|
||||||
e.textContent += " (only for ESP32 available)";
|
e.textContent += " (only for ESP32-S3 available)";
|
||||||
e.disabled = true;
|
e.disabled = true;
|
||||||
element.classList.add("disabled");
|
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) {
|
function parse(root) {
|
||||||
|
@ -1265,10 +1564,10 @@
|
||||||
/*IF_ESP32*/
|
/*IF_ESP32*/
|
||||||
parseCmtRadio(root["radioCmt"], root["system"]["esp_type"], root["system"]);
|
parseCmtRadio(root["radioCmt"], root["system"]["esp_type"], root["system"]);
|
||||||
/*ENDIF_ESP32*/
|
/*ENDIF_ESP32*/
|
||||||
parsezeroExport(root["zeroExport"], root["system"]["esp_type"]);
|
|
||||||
|
|
||||||
parseSerial(root["serial"]);
|
parseSerial(root["serial"]);
|
||||||
parseDisplay(root["display"], root["system"]["esp_type"], root["system"]);
|
parseDisplay(root["display"], root["system"]["esp_type"], root["system"]);
|
||||||
|
parseZeroExport(root["zeroExport"], root["system"]["esp_type"]);
|
||||||
|
|
||||||
getAjax("/api/inverter/list", parseIv);
|
getAjax("/api/inverter/list", parseIv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -767,6 +767,191 @@
|
||||||
"token": "NO_NETWORK_FOUND",
|
"token": "NO_NETWORK_FOUND",
|
||||||
"en": "no network found",
|
"en": "no network found",
|
||||||
"de": "kein Netzwerk gefunden"
|
"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.port = request->arg("mqttPort").toInt();
|
||||||
mConfig->mqtt.interval = request->arg("mqttInterval").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
|
// serial console
|
||||||
mConfig->serial.debug = (request->arg("serDbg") == "on");
|
mConfig->serial.debug = (request->arg("serDbg") == "on");
|
||||||
mConfig->serial.privacyLog = (request->arg("priv") == "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
|
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
|
#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"));
|
mApp->saveSettings((request->arg("reboot") == "on"));
|
||||||
|
|
||||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len);
|
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