Browse Source

0.8.1030016-zero

0.8.1030016-zero
pull/1647/head
tictrick 8 months ago
committed by GitHub
parent
commit
e3c8a96ca1
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      src/config/settings.h
  2. 2
      src/defines.h
  3. 46
      src/platformio.ini
  4. 129
      src/plugins/zeroExport/powermeter.h
  5. 144
      src/plugins/zeroExport/zeroExport.h
  6. 16
      src/web/RestApi.h
  7. 56
      src/web/html/setup.html
  8. 11
      src/web/lang.json

12
src/config/settings.h

@ -206,7 +206,7 @@ typedef struct {
#define ZEROEXPORT_MAX_QUEUE_ENTRIES 64
#define ZEROEXPORT_MAX_GROUPS 8
#define ZEROEXPORT_GROUP_MAX_LEN_NAME 25
#define ZEROEXPORT_GROUP_MAX_LEN_PM_URL 100
#define ZEROEXPORT_GROUP_MAX_LEN_PM_SRC 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
@ -288,7 +288,7 @@ typedef struct {
uint8_t pm_refresh;
unsigned long pm_peviousTsp;
uint8_t pm_type;
char pm_url[ZEROEXPORT_GROUP_MAX_LEN_PM_URL];
char pm_src[ZEROEXPORT_GROUP_MAX_LEN_PM_SRC];
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];
@ -674,7 +674,7 @@ class settings {
mCfg.plugin.zeroExport.groups[group].pm_refresh = 5;
mCfg.plugin.zeroExport.groups[group].pm_peviousTsp = 0;
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_src, ZEROEXPORT_GROUP_MAX_LEN_PM_SRC, "%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);
@ -1033,7 +1033,7 @@ class settings {
// Powermeter
obj[F("pm_refresh")] = mCfg.plugin.zeroExport.groups[group].pm_refresh;
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_src")] = mCfg.plugin.zeroExport.groups[group].pm_src;
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;
@ -1067,8 +1067,8 @@ class settings {
getVal<uint8_t>(obj, F("pm_refresh"), &mCfg.plugin.zeroExport.groups[group].pm_refresh);
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_src")))
getChar(obj, F("pm_src"), mCfg.plugin.zeroExport.groups[group].pm_src, ZEROEXPORT_GROUP_MAX_LEN_PM_SRC );
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")))

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 8
#define VERSION_PATCH 1030013
#define VERSION_PATCH 1030016
//-------------------------------------
typedef struct {
uint8_t ch;

46
src/platformio.ini

@ -40,7 +40,6 @@ build_flags =
build_unflags =
-std=gnu++11
[env:esp8266-minimal]
platform = espressif8266
board = esp12e
@ -148,7 +147,7 @@ monitor_filters =
esp8266_exception_decoder
[env:esp32-wroom32-minimal]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_d32
build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD
@ -156,7 +155,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-wroom32]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_d32
build_flags = ${env:esp32-wroom32-minimal.build_flags}
-DENABLE_MQTT
@ -167,7 +166,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-wroom32-de]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_d32
build_flags = ${env:esp32-wroom32.build_flags}
-DLANG_DE
@ -175,7 +174,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-wroom32-prometheus]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_d32
build_flags = ${env:esp32-wroom32.build_flags}
-DENABLE_PROMETHEUS_EP
@ -183,7 +182,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-wroom32-prometheus-de]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_d32
build_flags = ${env:esp32-wroom32-prometheus.build_flags}
-DLANG_DE
@ -219,7 +218,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-s2-mini]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_s2_mini
build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD
@ -242,7 +241,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-s2-mini-de]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_s2_mini
build_flags = ${env:esp32-s2-mini.build_flags}
-DLANG_DE
@ -250,7 +249,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-c3-mini]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_c3_mini
build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD
@ -273,7 +272,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-c3-mini-de]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = lolin_c3_mini
build_flags = ${env:esp32-c3-mini.build_flags}
-DLANG_DE
@ -281,7 +280,7 @@ monitor_filters =
esp32_exception_decoder
[env:opendtufusion-minimal]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env.build_flags}
@ -306,19 +305,18 @@ monitor_filters =
esp32_exception_decoder, colorize
[env:opendtufusion]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env:opendtufusion-minimal.build_flags}
-DENABLE_MQTT
-DPLUGIN_DISPLAY
-DENABLE_HISTORY
-DPLUGIN_ZEROEXPORT
monitor_filters =
esp32_exception_decoder, colorize
[env:opendtufusion-de]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env:opendtufusion.build_flags}
@ -326,8 +324,24 @@ build_flags = ${env:opendtufusion.build_flags}
monitor_filters =
esp32_exception_decoder, colorize
[env:opendtufusion-zero_export]
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env:opendtufusion.build_flags}
-DPLUGIN_ZEROEXPORT
monitor_filters =
esp32_exception_decoder, colorize
[env:opendtufusion-zero_export-de]
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env:opendtufusion-zero_export.build_flags}
-DLANG_DE
[env:opendtufusion-ethernet]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env:opendtufusion-minimal.build_flags}
@ -347,7 +361,7 @@ monitor_filters =
esp32_exception_decoder, colorize
[env:opendtufusion-ethernet-de]
platform = espressif32@6.5.0
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env:opendtufusion-ethernet.build_flags}

129
src/plugins/zeroExport/powermeter.h

@ -14,7 +14,6 @@
#include "config/settings.h"
#if defined(ZEROEXPORT_POWERMETER_TIBBER)
#include <base64.h>
#include <string.h>
#include <list>
@ -47,7 +46,8 @@ class powermeter {
* @param *log
* @returns void
*/
bool setup(zeroExport_t *cfg, PubMqttType *mqtt, JsonObject *log) {
bool setup(IApp *app, zeroExport_t *cfg, PubMqttType *mqtt, JsonObject *log) {
mApp = app;
mCfg = cfg;
mMqtt = mqtt;
mLog = log;
@ -65,15 +65,22 @@ class powermeter {
if (millis() - mPreviousTsp <= 1000) return; // skip when it is to fast
mPreviousTsp = millis();
if (mCfg->debug) DBGPRINTLN(F("pm Takt:"));
bool result = false;
float power = 0.0;
for (u_short group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
if ((!mCfg->groups[group].enabled) || (mCfg->groups[group].sleep)) continue;
if ((millis() - mCfg->groups[group].pm_peviousTsp) <= ((uint16_t)mCfg->groups[group].pm_refresh * 1000)) continue;
if ((millis() - mCfg->groups[group].pm_peviousTsp) < ((uint16_t)mCfg->groups[group].pm_refresh * 1000)) continue;
mCfg->groups[group].pm_peviousTsp = millis();
if (mCfg->debug) DBGPRINTLN(F("pm Do:"));
result = false;
power = 0.0;
switch (mCfg->groups[group].pm_type) {
#if defined(ZEROEXPORT_POWERMETER_SHELLY)
case zeroExportPowermeterType_t::Shelly:
@ -91,9 +98,14 @@ class powermeter {
break;
#endif
#if defined(ZEROEXPORT_POWERMETER_TIBBER)
/* Anscheinend nutzt bei mir Tibber auch diese Freq.
862.75 MHz - keine Verbindung
863.00 MHz - geht (standard) jedoch hat Tibber dann Probleme... => 4 & 5 Balken
863.25 MHz - geht (ohne Tibber Probleme) => 3 & 4 Balken
*/
case zeroExportPowermeterType_t::Tibber:
if (mCfg->groups[group].pm_refresh < 3) mCfg->groups[group].pm_refresh = 3;
result = getPowermeterWattsTibber(*mLog, group, &power);
mPreviousTsp += 2000; // Zusätzliche Pause
break;
#endif
#if defined(ZEROEXPORT_POWERMETER_SHRDZM)
@ -103,22 +115,14 @@ class powermeter {
#endif
}
// if (mMqtt->isConnected()) mMqtt->publish(String("zero/state/groups/" + String(group) + "/result").c_str(), String(ret).c_str(), false);
if (result) {
bufferWrite(power, group);
// MQTT - Powermeter
if (mCfg->debug) {
if (mMqtt->isConnected()) {
// P
mqttObj["Sum"] = ah::round1(power);
// mqttObj["L1"] = ah::round1(power.P1);
// mqttObj["L2"] = ah::round1(power.P2);
// mqttObj["L3"] = ah::round1(power.P3);
mMqtt->publish(String("zero/state/groups/" + String(group) + "/powermeter/P").c_str(), mqttDoc.as<std::string>().c_str(), false);
mqttDoc.clear();
// W (TODO)
}
if (mMqtt->isConnected()) {
mMqtt->publish(String("zero/state/groups/" + String(group) + "/powermeter/P").c_str(), String(ah::round1(power)).c_str(), false);
}
}
}
@ -149,13 +153,33 @@ class powermeter {
float min = 0.0;
for (int i = 0; i < 5; i++) {
if (i == 0) min = mPowermeterBuffer[group][i];
if ( min > mPowermeterBuffer[group][i]) min = mPowermeterBuffer[group][i];
if (i == 0)
min = mPowermeterBuffer[group][i];
if (min > mPowermeterBuffer[group][i])
min = mPowermeterBuffer[group][i];
}
return min;
}
/** getDataMAX
* Holt die Daten vom Powermeter
* @param group
* @returns value
*/
float getDataMAX(uint8_t group) {
float max = 0.0;
for (int i = 0; i < 5; i++) {
if (i == 0)
max = mPowermeterBuffer[group][i];
if (max < mPowermeterBuffer[group][i])
max = mPowermeterBuffer[group][i];
}
return max;
}
/** onMqttConnect
*
*/
@ -163,12 +187,12 @@ class powermeter {
#if defined(ZEROEXPORT_POWERMETER_MQTT)
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
if (!strcmp(mCfg->groups[group].pm_jsonPath, "")) continue;
if (!strcmp(mCfg->groups[group].pm_src, "")) continue;
if (!mCfg->groups[group].enabled) continue;
if (mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) {
mMqtt->subscribeExtern(String(mCfg->groups[group].pm_jsonPath).c_str(), QOS_2);
mMqtt->subscribeExtern(String(mCfg->groups[group].pm_src).c_str(), QOS_2);
}
}
@ -176,7 +200,7 @@ class powermeter {
}
/** onMqttMessage
*
* This function is needed for all mqtt connections between ahoy and other devices.
*/
void onMqttMessage(JsonObject obj) {
String topic = String(obj["topic"]);
@ -188,27 +212,35 @@ class powermeter {
if (!mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) continue;
if (!strcmp(mCfg->groups[group].pm_jsonPath, "")) continue;
if (!strcmp(mCfg->groups[group].pm_src, "")) continue;
if (strcmp(mCfg->groups[group].pm_jsonPath, String(topic).c_str())) continue;
if (strcmp(mCfg->groups[group].pm_src, String(topic).c_str())) continue;
float power = 0.0;
power = (uint16_t)obj["val"];
// //TODO: datajson 100 enough?
// // this if-statement need to check if value contains a json object.
// // is it so, then deserialize it and get the values (Shelly GEN2)
// DynamicJsonDocument datajson(100);
// if (!deserializeJson(datajson, obj["val"]))
// {
// switch (mCfg->groups[group].pm_target) {
// case 0: power = datajson["a_act_power"]; break;
// case 1: power = datajson["b_act_power"]; break;
// case 2: power = datajson["c_act_power"]; break;
// case 3: power = datajson["total_act_power"]; break;
// }
// } else {
// //TODO: check if parse is possible here? Is that right?
power = (uint16_t)obj["val"];
// }
bufferWrite(power, group);
// MQTT - Powermeter
if (mCfg->debug) {
if (mMqtt->isConnected()) {
// P
mqttObj["Sum"] = ah::round1(power);
/// mqttObj["L1"] = ah::round1(power.P1);
/// mqttObj["L2"] = ah::round1(power.P2);
/// mqttObj["L3"] = ah::round1(power.P3);
mMqtt->publish(String("zero/state/groups/" + String(group) + "/powermeter/P").c_str(), mqttDoc.as<std::string>().c_str(), false);
mqttDoc.clear();
// W (TODO)
mMqtt->publish(String("zero/state/groups/" + String(group) + "/powermeter/P").c_str(), String(ah::round1(power)).c_str(), false);
}
}
@ -246,8 +278,9 @@ class powermeter {
zeroExport_t *mCfg;
PubMqttType *mMqtt = nullptr;
JsonObject *mLog;
IApp *mApp = nullptr;
unsigned long mPreviousTsp = 0;
unsigned long mPreviousTsp = millis();
float mPowermeterBuffer[ZEROEXPORT_MAX_GROUPS][5] = {0};
short mPowermeterBufferPos[ZEROEXPORT_MAX_GROUPS] = {0};
@ -260,8 +293,9 @@ class powermeter {
*/
void setHeader(HTTPClient *h) {
h->setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
h->setUserAgent("Ahoy-Agent");
// TODO: Ahoy-0.8.850024-zero
/// h->setUserAgent("Ahoy-Agent");
/// // TODO: Ahoy-0.8.850024-zero
h->setUserAgent(mApp->getVersion());
h->setConnectTimeout(500);
h->setTimeout(1000);
h->addHeader("Content-Type", "application/json");
@ -280,7 +314,7 @@ class powermeter {
setHeader(&http);
String url = String("http://") + String(mCfg->groups[group].pm_url) + String("/") + String(mCfg->groups[group].pm_jsonPath);
String url = String("http://") + String(mCfg->groups[group].pm_src) + String("/") + String(mCfg->groups[group].pm_jsonPath);
logObj["HTTP_URL"] = url;
http.begin(url);
@ -373,8 +407,8 @@ class powermeter {
http.addHeader("Content-Type", "application/json");
http.addHeader("Accept", "application/json");
// String url = String("http://") + String(mCfg->groups[group].pm_url) + String("/") + String(mCfg->groups[group].pm_jsonPath);
String url = String(mCfg->groups[group].pm_url);
// String url = String("http://") + String(mCfg->groups[group].pm_src) + String("/") + String(mCfg->groups[group].pm_jsonPath);
String url = String(mCfg->groups[group].pm_src);
logObj["HTTP_URL"] = url;
http.begin(url);
@ -482,23 +516,12 @@ class powermeter {
{{0x01, 0x00, 0x02, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterExport}};
bool getPowermeterWattsTibber(JsonObject logObj, uint8_t group, float *power) {
mPreviousTsp = mPreviousTsp + 2000; // Zusätzliche Pause
bool result = false;
logObj["mod"] = "getPowermeterWattsTibber";
String auth;
if (strlen(mCfg->groups[group].pm_user) > 0 && strlen(mCfg->groups[group].pm_pass) > 0) {
auth = base64::encode(String(mCfg->groups[group].pm_user) + String(":") + String(mCfg->groups[group].pm_pass));
snprintf(mCfg->groups[group].pm_user, ZEROEXPORT_GROUP_MAX_LEN_PM_USER, "%s", DEF_ZEXPORT);
snprintf(mCfg->groups[group].pm_pass, ZEROEXPORT_GROUP_MAX_LEN_PM_PASS, "%s", auth.c_str());
//@TODO:mApp->saveSettings(false);
} else {
auth = mCfg->groups[group].pm_pass;
}
String url = String("http://") + mCfg->groups[group].pm_url + String("/") + String(mCfg->groups[group].pm_jsonPath);
String auth = mCfg->groups[group].pm_pass;
String url = String("http://") + mCfg->groups[group].pm_src + String("/") + String(mCfg->groups[group].pm_jsonPath);
setHeader(&http);
http.begin(url);
@ -551,7 +574,7 @@ class powermeter {
setHeader(&http);
String url =
String("http://") + String(mCfg->groups[group].pm_url) +
String("http://") + String(mCfg->groups[group].pm_src) +
String("/") + String(mCfg->groups[group].pm_jsonPath + String("?user=") + String(mCfg->groups[group].pm_user) + String("&password=") + String(mCfg->groups[group].pm_pass));
http.begin(url);

144
src/plugins/zeroExport/zeroExport.h

@ -47,7 +47,7 @@ class ZeroExport {
mApi = api;
mMqtt = mqtt;
mIsInitialized = mPowermeter.setup(mCfg, mqtt, &mLog);
mIsInitialized = mPowermeter.setup(mApp, mCfg, mqtt, &mLog);
}
/** loop
@ -106,18 +106,14 @@ class ZeroExport {
return;
}
// Calc Data->groupPower
uint16_t groupPower = 0;
for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
groupPower += mCfg->groups[group].inverters[inv].power;
}
mLog["gP"] = groupPower;
// Calc Data->groupLimit
uint16_t groupPower = 0;
uint16_t groupLimit = 0;
for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
groupLimit += mCfg->groups[group].inverters[inv].limit;
groupPower += mCfg->groups[group].inverters[inv].power; // Calc Data->groupPower
groupLimit += mCfg->groups[group].inverters[inv].limit; // Calc Data->groupLimit
}
mLog["gP"] = groupPower;
mLog["gL"] = groupLimit;
// Batteryprotection
@ -485,6 +481,17 @@ class ZeroExport {
mLog["i"] = inv;
mCfg->groups[group].inverters[inv].waitAck = 0;
mLog["wA"] = mCfg->groups[group].inverters[inv].waitAck;
mCfg->groups[group].inverters[inv].limit = mCfg->groups[group].inverters[inv].powerMin;
iv->powerLimit[0] = static_cast<uint16_t>(mCfg->groups[group].inverters[inv].limit * 10.0);
iv->powerLimit[1] = AbsolutNonPersistent;
if (iv->setDevControlRequest(ActivePowerContr)) {
mApp->triggerTickSend(iv->id);
mCfg->groups[group].inverters[inv].waitAck = 60;
mCfg->groups[group].inverters[inv].action = zeroExportAction_t::doNone;
mCfg->groups[group].inverters[inv].actionTimer = 0;
mCfg->groups[group].inverters[inv].actionTimestamp = millis();
}
sendLog();
clearLog();
}
@ -637,53 +644,41 @@ class ZeroExport {
if (obj["path"] == "ctrl" && obj["cmd"] == "zero") {
int8_t topicGroup = getGroupFromTopic(topic.c_str());
if (topicGroup != -1)
mLog["g"] = topicGroup;
int8_t topicInverter = getInverterFromTopic(topic.c_str());
if (topicInverter == -1)
mLog["i"] = topicInverter;
if (topicGroup != -1) mLog["g"] = topicGroup;
if (topicInverter == -1) mLog["i"] = topicInverter;
mLog["k"] = topic;
// "topic":"ctrl/zero/enabled"
if (topic.indexOf("ctrl/zero/enabled") != -1) {
mCfg->enabled = (bool)obj["val"];
mLog["k"] = "ctrl/zero/enabled";
mLog["v"] = mCfg->enabled;
}
if (topic.indexOf("ctrl/zero/enabled") != -1) mCfg->enabled = mLog["v"] = (bool)obj["val"];
// "topic":"ctrl/zero/sleep"
if (topic.indexOf("ctrl/zero/sleep") != -1) {
mCfg->sleep = (bool)obj["val"];
mLog["k"] = "ctrl/zero/sleep";
mLog["v"] = mCfg->sleep;
}
else if (topic.indexOf("ctrl/zero/sleep") != -1) mCfg->sleep = mLog["v"] = (bool)obj["val"];
else if ((topicGroup >= 0) && (topicGroup < ZEROEXPORT_MAX_GROUPS))
{
String stopicGroup = String(topicGroup);
if ((topicGroup >= 0) && (topicGroup < ZEROEXPORT_MAX_GROUPS)) {
// "topic":"ctrl/zero/groups/+/enabled"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/enabled") != -1) {
mCfg->groups[topicGroup].enabled = (bool)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/enabled";
mLog["v"] = mCfg->groups[topicGroup].enabled;
}
if (topic.endsWith("/enabled")) mCfg->groups[topicGroup].enabled = mLog["v"] = (bool)obj["val"];
// "topic":"ctrl/zero/groups/+/sleep"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/sleep") != -1) {
mCfg->groups[topicGroup].sleep = (bool)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/sleep";
mLog["v"] = mCfg->groups[topicGroup].sleep;
}
else if (topic.endsWith("/sleep")) mCfg->groups[topicGroup].sleep = mLog["v"] = (bool)obj["val"];
// Auf Eis gelegt, dafür 2 Gruppen mehr
// 0.8.103008.2
// // "topic":"ctrl/zero/groups/+/pm_ip"
// if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/pm_ip") != -1) {
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", obj[F("val")].as<const char *>());
// snprintf(mCfg->groups[topicGroup].pm_src, ZEROEXPORT_GROUP_MAX_LEN_PM_SRC, "%s", obj[F("val")].as<const char *>());
/// TODO:
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", obj[F("val")].as<const char *>());
// strncpy(mCfg->groups[topicGroup].pm_url, obj[F("val")], ZEROEXPORT_GROUP_MAX_LEN_PM_URL);
// strncpy(mCfg->groups[topicGroup].pm_url, String(obj[F("val")]).c_str(), ZEROEXPORT_GROUP_MAX_LEN_PM_URL);
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", String(obj[F("val")]).c_str());
// snprintf(mCfg->groups[topicGroup].pm_src, ZEROEXPORT_GROUP_MAX_LEN_PM_SRC, "%s", obj[F("val")].as<const char *>());
// strncpy(mCfg->groups[topicGroup].pm_src, obj[F("val")], ZEROEXPORT_GROUP_MAX_LEN_PM_SRC);
// strncpy(mCfg->groups[topicGroup].pm_src, String(obj[F("val")]).c_str(), ZEROEXPORT_GROUP_MAX_LEN_PM_SRC);
// snprintf(mCfg->groups[topicGroup].pm_src, ZEROEXPORT_GROUP_MAX_LEN_PM_SRC, "%s", String(obj[F("val")]).c_str());
// mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/pm_ip";
// mLog["v"] = mCfg->groups[topicGroup].pm_url;
// mLog["v"] = mCfg->groups[topicGroup].pm_src;
// }
//
// // "topic":"ctrl/zero/groups/+/pm_jsonPath"
@ -695,55 +690,37 @@ class ZeroExport {
// }
// "topic":"ctrl/zero/groups/+/battery/switch"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/battery/switch") != -1) {
mCfg->groups[topicGroup].battSwitch = (bool)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/battery/switch";
mLog["v"] = mCfg->groups[topicGroup].battSwitch;
}
else if (topic.endsWith("/battery/switch")) mCfg->groups[topicGroup].battSwitch = mLog["v"] = (bool)obj["val"];
// "topic":"ctrl/zero/groups/+/advanced/setPoint"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/advanced/setPoint") != -1) {
mCfg->groups[topicGroup].setPoint = (int16_t)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/advanced/setPoint";
mLog["v"] = mCfg->groups[topicGroup].setPoint;
}
else if (topic.indexOf("/advanced/") != -1)
{
// "topic":"ctrl/zero/groups/+/advanced/setPoint"
if (topic.endsWith("/setPoint")) mCfg->groups[topicGroup].setPoint = mLog["v"] = (int16_t)obj["val"];
// "topic":"ctrl/zero/groups/+/advanced/powerTolerance"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/advanced/powerTolerance") != -1) {
mCfg->groups[topicGroup].powerTolerance = (uint8_t)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/advanced/powerTolerance";
mLog["v"] = mCfg->groups[topicGroup].powerTolerance;
}
// "topic":"ctrl/zero/groups/+/advanced/powerTolerance"
else if (topic.endsWith("/powerTolerance")) mCfg->groups[topicGroup].powerTolerance = mLog["v"] = (uint8_t)obj["val"];
// "topic":"ctrl/zero/groups/+/advanced/powerMax"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/advanced/powerMax") != -1) {
mCfg->groups[topicGroup].powerMax = (uint16_t)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/advanced/powerMax";
mLog["v"] = mCfg->groups[topicGroup].powerMax;
// "topic":"ctrl/zero/groups/+/advanced/powerMax"
else if (topic.endsWith("/powerMax")) mCfg->groups[topicGroup].powerMax = mLog["v"] = (uint16_t)obj["val"];
}
if ((topicInverter >= 0) && (topicInverter < ZEROEXPORT_GROUP_MAX_INVERTERS)) {
// "topic":"ctrl/zero/groups/+/inverter/+/enabled"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/inverter/" + String(topicInverter) + "/enabled") != -1) {
mCfg->groups[topicGroup].inverters[topicInverter].enabled = (bool)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/inverter/" + String(topicInverter) + "/enabled";
mLog["v"] = mCfg->groups[topicGroup].inverters[topicInverter].enabled;
}
// "topic":"ctrl/zero/groups/+/inverter/+/powerMin"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/inverter/" + String(topicInverter) + "/powerMin") != -1) {
mCfg->groups[topicGroup].inverters[topicInverter].powerMin = (uint16_t)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/inverter/" + String(topicInverter) + "/powerMin";
mLog["v"] = mCfg->groups[topicGroup].inverters[topicInverter].powerMin;
}
// "topic":"ctrl/zero/groups/+/inverter/+/powerMax"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/inverter/" + String(topicInverter) + "/powerMax") != -1) {
mCfg->groups[topicGroup].inverters[topicInverter].powerMax = (uint16_t)obj["val"];
mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/inverter/" + String(topicInverter) + "/powerMax";
mLog["v"] = mCfg->groups[topicGroup].inverters[topicInverter].powerMax;
else if (topic.indexOf("/inverter/") != -1)
{
if ((topicInverter >= 0) && (topicInverter < ZEROEXPORT_GROUP_MAX_INVERTERS))
{
// "topic":"ctrl/zero/groups/+/inverter/+/enabled"
if (topic.endsWith("/enabled")) mCfg->groups[topicGroup].inverters[topicInverter].enabled = mLog["v"] = (bool)obj["val"];
// "topic":"ctrl/zero/groups/+/inverter/+/powerMin"
else if (topic.endsWith("/powerMin")) mCfg->groups[topicGroup].inverters[topicInverter].powerMin = mLog["v"] = (uint16_t)obj["val"];
// "topic":"ctrl/zero/groups/+/inverter/+/powerMax"
else if (topic.endsWith("/powerMax")) mCfg->groups[topicGroup].inverters[topicInverter].powerMax = mLog["v"] = (uint16_t)obj["val"];
else mLog["k"] = "error";
}
}
else {
mLog["k"] = "error";
}
}
}
@ -791,6 +768,7 @@ class ZeroExport {
while (*pGroupSection != '/' && digitsCopied < 2) strGroup[digitsCopied++] = *pGroupSection++;
strGroup[digitsCopied] = '\0';
int8_t group = atoi(strGroup);
mLog["getGroupFromTopic"] = group;
return group;
}

16
src/web/RestApi.h

@ -20,6 +20,7 @@
#include "ESPAsyncWebServer.h"
#include "plugins/history.h"
#include <base64.h>
#if defined(F) && defined(ESP32)
#undef F
@ -839,7 +840,7 @@ class RestApi {
// Powermeter
objGroup[F("pm_refresh")] = (uint8_t)mConfig->plugin.zeroExport.groups[group].pm_refresh;
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_src")] = String(mConfig->plugin.zeroExport.groups[group].pm_src);
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);
@ -1159,10 +1160,17 @@ class RestApi {
// Powermeter
mConfig->plugin.zeroExport.groups[group].pm_refresh = jsonIn[F("pm_refresh")];
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_src, ZEROEXPORT_GROUP_MAX_LEN_PM_SRC, "%s", jsonIn[F("pm_src")].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*>());
if (jsonIn[F("pm_pass")] != F("****"))
{
String auth = base64::encode(String(jsonIn[F("pm_user")]) + String(":") + String(jsonIn[F("pm_pass")]));
snprintf(mConfig->plugin.zeroExport.groups[group].pm_user, ZEROEXPORT_GROUP_MAX_LEN_PM_USER, "%s", String(jsonIn[F("pm_user")]).c_str());
snprintf(mConfig->plugin.zeroExport.groups[group].pm_pass, ZEROEXPORT_GROUP_MAX_LEN_PM_PASS, "%s", auth.c_str());
}
mConfig->plugin.zeroExport.groups[group].pm_target = jsonIn[F("pm_target")];
// Inverters
for(uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {

56
src/web/html/setup.html

@ -1389,25 +1389,21 @@
divRow("{#ZE_GROUP_TAB_POWERMETER_REFRESH}",
ml("input", {name: "pm_refresh", class: "text", type: "number", min: "1", max: "30", step: "1", value: obj.pm_refresh}, null),
),
// TODO: URL -> IP
divRow("{#ZE_GROUP_TAB_POWERMETER_TARGET}",
ml("select", {name: "pm_target", class: "text", id: "pm_target"}, null),
),
divRow("{#ZE_GROUP_TAB_POWERMETER_IP}", [
ml("input", {name: "pm_url", class: "text", type: "text", value: obj.pm_url, maxlength: "100"}, null),
divRow("{#ZE_GROUP_TAB_POWERMETER_SRC}", [
ml("input", {name: "pm_src", class: "text", type: "text", value: obj.pm_src, maxlength: "100"}, null),
]),
divRow("{#ZE_GROUP_TAB_POWERMETER_JSONPATH}", [
ml("input", {name: "pm_jsonPath", class: "text", type: "text", value: obj.pm_jsonPath}, null),
]),
divRow("{#ZE_GROUP_TAB_POWERMETER_USER}",
ml("input", {name: "pm_user", class: "text", type: "text", value: "" }, null),
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: "password", value: "****"}, null),
),
divRow("{#ZE_GROUP_TAB_POWERMETER_TOPIC}",
ml("input", {id: 3, name: "pm_topic", class: "text", type: "text", value: ""}, null),
),
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
divRow("Hinweis: ",
ml("a", {href: "https://docs.ahoydtu.de/de/latest/zeroExport.html"}, "Bitte beachten Sie die Ausf&uuml;llhinweise in der Dokumentation."),
@ -1513,9 +1509,8 @@
}
// add addEventListener
const selectElement = document.querySelector("#pm_type");
//selectElement.addEventListener("change", (event) => { pm_type_dropdown() });
selectElement.addEventListener("change", (event) => { pm_type_dropdown() });
const se_pm_type = document.querySelector("#pm_type");
se_pm_type.addEventListener("change", (event) => { pm_type_dropdown() });
// run event one time
pm_type_dropdown();
@ -1571,6 +1566,31 @@
}
}
// add addEventListener
const se_battCfg = document.querySelector("#battCfg");
se_battCfg.addEventListener("change", (event) => { battCfg_dropdown() });
// run event one time
battCfg_dropdown();
function battCfg_dropdown()
{
var e = document.getElementsByName("battCfg")[0];
var value = e.options[e.selectedIndex].text;
var divsToHide = document.getElementById("divBattery");
// Formular for Powermeter-DropDown
// show all DIVs and remove only what is not necessary
// 1 = pm_refresh, 2 = pm_target, 3 = pm_src, 4 = pm_jsonPath, 5 = pm_user, 6 = pm_pass
for(var i = 0; i < divsToHide.childElementCount; i++) divsToHide.childNodes[i].style.display = '';
if(value == "---") for(var i = 1; i < divsToHide.childElementCount; i++) divsToHide.childNodes[i].style.display = 'none';
else if(value == "Inverter U dc") {
divsToHide.childNodes[1].style.display = 'none';
}
}
function pm_type_dropdown()
{
var e = document.getElementsByName("pm_type")[0];
@ -1580,21 +1600,27 @@
// Formular for Powermeter-DropDown
// show all DIVs and remove only what is not necessary
// 1 = pm_refresh, 2 = pm_target, 3 = pm_src, 4 = pm_jsonPath, 5 = pm_user, 6 = pm_pass
for(var i = 0; i < divsToHide.childElementCount; i++) divsToHide.childNodes[i].style.display = '';
if(value == "---") for(var i = 1; i < divsToHide.childElementCount; i++) divsToHide.childNodes[i].style.display = 'none';
else if(value == "Shelly") {
divsToHide.childNodes[7].style.display = 'none';
divsToHide.childNodes[5].style.display = 'none';
divsToHide.childNodes[6].style.display = 'none';
}
else if(value == "Mqtt") {
divsToHide.childNodes[3].style.display = 'none';
divsToHide.childNodes[1].style.display = 'none';
divsToHide.childNodes[2].style.display = 'none';
divsToHide.childNodes[4].style.display = 'none';
divsToHide.childNodes[5].style.display = 'none';
divsToHide.childNodes[6].style.display = 'none';
}
else if(value == "Tibber") {
divsToHide.childNodes[4].style.display = 'none';
divsToHide.childNodes[7].style.display = 'none';
}
else if(value == "Shrdzm") {
divsToHide.childNodes[1].style.display = 'none';
divsToHide.childNodes[2].style.display = 'none';
}
}
@ -1611,7 +1637,7 @@
o.pm_refresh = document.getElementsByName("pm_refresh")[0].value;
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_src = document.getElementsByName("pm_src")[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;
@ -1678,7 +1704,7 @@
// Powermeter
o.pm_refresh = 5;
o.pm_type = 0;
o.pm_url = "";
o.pm_src = "";
o.pm_jsonPath = "";
o.pm_user = "";
o.pm_pass = "";

11
src/web/lang.json

@ -894,9 +894,9 @@
"de": "Typ:"
},
{
"token": "ZE_GROUP_TAB_POWERMETER_IP",
"en": "IP:",
"de": "IP:"
"token": "ZE_GROUP_TAB_POWERMETER_SRC",
"en": "IP / Topic:",
"de": "IP / Topic:"
},
{
"token": "ZE_GROUP_TAB_POWERMETER_JSONPATH",
@ -913,11 +913,6 @@
"en": "Password:",
"de": "Passwort:"
},
{
"token": "ZE_GROUP_TAB_POWERMETER_TOPIC",
"en": "Topic:",
"de": "Topic:"
},
{
"token": "ZE_GROUP_TAB_POWERMETER_TARGET",
"en": "Target:",

Loading…
Cancel
Save