From 1a87a59ee6d078b1d35bd3497378a50fe2b85cc8 Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Fri, 31 May 2024 19:13:34 +0200 Subject: [PATCH 1/6] Update zeroExport.h auf DynamicJsonDocument vorbereitet --- src/plugins/zeroExport/zeroExport.h | 256 +++++++++++++++++----------- 1 file changed, 156 insertions(+), 100 deletions(-) diff --git a/src/plugins/zeroExport/zeroExport.h b/src/plugins/zeroExport/zeroExport.h index f91c2e47..4bd400b5 100644 --- a/src/plugins/zeroExport/zeroExport.h +++ b/src/plugins/zeroExport/zeroExport.h @@ -15,6 +15,8 @@ #include "AsyncJson.h" #include "powermeter.h" +#include "utils/DynamicJsonHandler.h" + template class ZeroExport { @@ -47,9 +49,16 @@ class ZeroExport { mApi = api; mMqtt = mqtt; - mIsInitialized = mPowermeter.setup(mApp, mCfg, mqtt, &mLog); + mIsInitialized = mPowermeter.setup(mApp, mCfg, mqtt, &_log); } + + /*void printJson() { + serializeJson(doc, Serial); + Serial.println(); + serializeJsonPretty(doc, Serial); + }*/ + /** loop * Arbeitsschleife * @param void @@ -83,26 +92,24 @@ class ZeroExport { zeroExportGroupInverter_t *CfgGroupInv = &CfgGroup->inverters[inv]; Inverter<> *iv = mSys->getInverterByPos(Queue.id); - mLog["g"] = group; - mLog["i"] = inv; + _log.addProperty("g", group); + _log.addProperty("i", inv); // Check Data->iv if (!iv->isAvailable()) { if (mCfg->debug) { - mLog["nA"] = "!isAvailable"; + _log.addProperty("nA", "!isAvailable"); sendLog(); } - clearLog(); return; } // Check Data->waitAck if (CfgGroupInv->waitAck > 0) { if (mCfg->debug) { - mLog["wA"] = CfgGroupInv->waitAck; + _log.addProperty("wA", CfgGroupInv->waitAck); sendLog(); } - clearLog(); return; } @@ -113,16 +120,19 @@ class ZeroExport { 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; + + _log.addProperty("gP", groupPower); + _log.addProperty("gL", groupLimit); // Batteryprotection - mLog["bEn"] = (uint8_t)CfgGroup->battCfg; + _log.addProperty("bEn", (uint8_t)CfgGroup->battCfg); + switch (CfgGroup->battCfg) { case zeroExportBatteryCfg::none: if (CfgGroup->battSwitch != true) { CfgGroup->battSwitch = true; - mLog["bA"] = "turn on"; + + _log.addProperty("bA", "turn on"); } break; case zeroExportBatteryCfg::invUdc: @@ -131,34 +141,34 @@ class ZeroExport { if (CfgGroup->battSwitch != true) { if (CfgGroup->battValue > CfgGroup->battLimitOn) { CfgGroup->battSwitch = true; - mLog["bA"] = "turn on"; + _log.addProperty("bA", "turn on"); } if ((CfgGroup->battValue > CfgGroup->battLimitOff) && (CfgGroupInv->power > 0)) { CfgGroup->battSwitch = true; - mLog["bA"] = "turn on"; + _log.addProperty("bA", "turn on"); } } else { if (CfgGroup->battValue < CfgGroup->battLimitOff) { CfgGroup->battSwitch = false; - mLog["bA"] = "turn off"; + _log.addProperty("bA", "turn off"); } } - mLog["bU"] = ah::round1(CfgGroup->battValue); + _log.addProperty("bU", ah::round1(CfgGroup->battValue)); break; default: if (CfgGroup->battSwitch == true) { CfgGroup->battSwitch = false; - mLog["bA"] = "turn off"; + _log.addProperty("bA", "turn off"); } break; } - mLog["bSw"] = CfgGroup->battSwitch; + _log.addProperty("bSw", CfgGroup->battSwitch); // Controller // Führungsgröße w in Watt int16_t w = CfgGroup->setPoint; - mLog["w"] = w; + _log.addProperty("w", w); // Regelgröße x in Watt int16_t x = 0.0; @@ -167,18 +177,17 @@ class ZeroExport { } else { x = mPowermeter.getDataAVG(group); } - mLog["x"] = x; + _log.addProperty("x", x); // Regelabweichung e in Watt int16_t e = w - x; - mLog["e"] = e; + _log.addProperty("e", e); // Keine Regelung innerhalb der Toleranzgrenzen if ((e < CfgGroup->powerTolerance) && (e > -CfgGroup->powerTolerance)) { e = 0; - mLog["eK"] = e; + _log.addProperty("eK", e); sendLog(); - clearLog(); return; } @@ -192,29 +201,28 @@ class ZeroExport { CfgGroup->eSum += e; int16_t yI = Ki * Ta * CfgGroup->eSum; if (Ta == 0) { - mLog["Error"] = "Ta = 0"; + _log.addProperty("Error", "Ta = 0"); sendLog(); - clearLog(); return; } int16_t yD = Kd * (e - CfgGroup->eOld) / Ta; if (mCfg->debug) { - mLog["Kp"] = Kp; - mLog["Ki"] = Ki; - mLog["Kd"] = Kd; - mLog["Ta"] = Ta; - mLog["yP"] = yP; - mLog["yI"] = yI; - mLog["eSum"] = CfgGroup->eSum; - mLog["yD"] = yD; - mLog["eOld"] = CfgGroup->eOld; + _log.addProperty("Kp", Kp); + _log.addProperty("Ki", Ki); + _log.addProperty("Kd", Kd); + _log.addProperty("Ta", Ta); + _log.addProperty("yP", yP); + _log.addProperty("yI", yI); + _log.addProperty("eSum", CfgGroup->eSum); + _log.addProperty("yD", yD); + _log.addProperty("eOld", CfgGroup->eOld); } CfgGroup->eOld = e; int16_t y = yP + yI + yD; - mLog["y"] = y; + _log.addProperty("y", y); // Regelbegrenzung // TODO: Hier könnte man den maximalen Sprung begrenzen @@ -230,7 +238,7 @@ class ZeroExport { if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = 1; if (CfgGroupInv->actionTimer > 10) { CfgGroupInv->action = zeroExportAction_t::doTurnOn; - mLog["do"] = "doTurnOn"; + _log.addProperty("do", "doTurnOn"); } } if ((CfgGroupInv->turnOff) && (CfgGroupInv->limitNew <= 0) && (CfgGroupInv->power > 0)) { @@ -238,26 +246,28 @@ class ZeroExport { if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = -1; if (CfgGroupInv->actionTimer < 30) { CfgGroupInv->action = zeroExportAction_t::doTurnOff; - mLog["do"] = "doTurnOff"; + _log.addProperty("do", "doTurnOff"); } } if (((CfgGroup->battSwitch == false) || (mCfg->sleep == true) || (CfgGroup->sleep == true)) && (CfgGroupInv->power > 0)) { CfgGroupInv->action = zeroExportAction_t::doTurnOff; - mLog["do"] = "sleep"; + _log.addProperty("do", "sleep"); } } - mLog["doT"] = CfgGroupInv->action; + _log.addProperty("doT", CfgGroupInv->action); if (CfgGroupInv->action == zeroExportAction_t::doNone) { - mLog["l"] = CfgGroupInv->limit; - mLog["ln"] = CfgGroupInv->limitNew; + _log.addProperty("l", CfgGroupInv->limit); + _log.addProperty("ln", CfgGroupInv->limitNew); // groupMax uint16_t otherIvLimit = groupLimit - CfgGroupInv->limit; if ((otherIvLimit + CfgGroupInv->limitNew) > CfgGroup->powerMax) { CfgGroupInv->limitNew = CfgGroup->powerMax - otherIvLimit; } - if (mCfg->debug) mLog["gPM"] = CfgGroup->powerMax; + if (mCfg->debug) { + _log.addProperty("gPM", CfgGroup->powerMax); + } // PowerMax uint16_t powerMax = 100; @@ -291,13 +301,13 @@ class ZeroExport { // CfgGroupInv->actionTimer = 0; // TODO: Timer stoppen wenn Limit gesetzt wird. - mLog["lN"] = CfgGroupInv->limitNew; + _log.addProperty("lN", CfgGroupInv->limitNew); CfgGroupInv->limit = CfgGroupInv->limitNew; } // doAction - mLog["a"] = CfgGroupInv->action; + _log.addProperty("a", CfgGroupInv->action); switch (CfgGroupInv->action) { case zeroExportAction_t::doRestart: @@ -350,9 +360,6 @@ class ZeroExport { // mqttPublish(String("zero/state/groups/" + String(group) + "/inverter/" + String(inv)).c_str(), mDocLog.as().c_str()); // } /// BUG: 003 Ende - - clearLog(); - return; } @@ -422,17 +429,22 @@ class ZeroExport { if (!mCfg->groups[group].inverters[inv].enabled) continue; if (iv->id == (uint8_t)mCfg->groups[group].inverters[inv].id) { - mLog["g"] = group; - mLog["i"] = inv; + _log.addProperty("g", group); + _log.addProperty("i", inv); + mCfg->groups[group].inverters[inv].waitAck = 0; - mLog["wA"] = mCfg->groups[group].inverters[inv].waitAck; + + _log.addProperty("wA", mCfg->groups[group].inverters[inv].waitAck); + + // Wenn ein neuer LimitWert da ist. Soll es in group schreiben. if (iv->actPowerLimit != 0xffff) { - mLog["l"] = mCfg->groups[group].inverters[inv].limit; + _log.addProperty("l", mCfg->groups[group].inverters[inv].limit); + mCfg->groups[group].inverters[inv].limit = iv->actPowerLimit; - mLog["lF"] = mCfg->groups[group].inverters[inv].limit; + + _log.addProperty("lF", mCfg->groups[group].inverters[inv].limit); } sendLog(); - clearLog(); } } } @@ -453,12 +465,13 @@ class ZeroExport { if (!mCfg->groups[group].inverters[inv].enabled) continue; if (iv->id == mCfg->groups[group].inverters[inv].id) { - mLog["g"] = group; - mLog["i"] = inv; + _log.addProperty("g", group); + _log.addProperty("i", inv); + mCfg->groups[group].inverters[inv].waitAck = 0; - mLog["wA"] = mCfg->groups[group].inverters[inv].waitAck; + + _log.addProperty("wA", mCfg->groups[group].inverters[inv].waitAck); sendLog(); - clearLog(); } } } @@ -479,10 +492,12 @@ class ZeroExport { if (!mCfg->groups[group].inverters[inv].enabled) continue; if (iv->id == mCfg->groups[group].inverters[inv].id) { - mLog["g"] = group; - mLog["i"] = inv; + _log.addProperty("g", group); + _log.addProperty("i", inv); + mCfg->groups[group].inverters[inv].waitAck = 0; - mLog["wA"] = mCfg->groups[group].inverters[inv].waitAck; + + _log.addProperty("wA", mCfg->groups[group].inverters[inv].waitAck); mCfg->groups[group].inverters[inv].limit = mCfg->groups[group].inverters[inv].powerMin; iv->powerLimit[0] = static_cast(mCfg->groups[group].inverters[inv].limit * 10.0); @@ -495,7 +510,6 @@ class ZeroExport { mCfg->groups[group].inverters[inv].actionTimestamp = millis(); } sendLog(); - clearLog(); } } } @@ -518,8 +532,8 @@ class ZeroExport { if (!CfgGroupInv->enabled) continue; if (CfgGroupInv->id != iv->id) continue; - mLog["g"] = group; - mLog["i"] = inv; + _log.addProperty("g", group); + _log.addProperty("i", inv); // TODO: Ist nach eventAckSetLimit verschoben // if (iv->actPowerLimit != 0xffff) { @@ -531,17 +545,19 @@ class ZeroExport { // TODO: Es dauert bis getMaxPower übertragen wird. if (iv->getMaxPower() > 0) { CfgGroupInv->MaxPower = iv->getMaxPower(); - mLog["pM"] = CfgGroupInv->MaxPower; + + _log.addProperty("pM", CfgGroupInv->MaxPower); } record_t<> *rec; rec = iv->getRecordStruct(RealTimeRunData_Debug); if (iv->getLastTs(rec) > (millis() - 15000)) { CfgGroupInv->power = iv->getChannelFieldValue(CH0, FLD_PAC, rec); - mLog["p"] = CfgGroupInv->power; + + _log.addProperty("pM", CfgGroupInv->MaxPower); CfgGroupInv->dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec); - mLog["bU"] = ah::round1(CfgGroupInv->dcVoltage); + _log.addProperty("bU", ah::round1(CfgGroupInv->dcVoltage)); // Batterieüberwachung - Überwachung über die DC-Spannung am PV-Eingang 1 des Inverters if (CfgGroup->battCfg == zeroExportBatteryCfg::invUdc) { @@ -561,16 +577,16 @@ class ZeroExport { uint16_t powerPercent = 100 / CfgGroupInv->MaxPower * CfgGroupInv->power; uint16_t delta = abs(limitPercent - powerPercent); if ((delta > 10) && (CfgGroupInv->power > 0)) { - mLog["delta"] = delta; + _log.addProperty("delta", delta); unsigned long delay = iv->getLastTs(rec) - CfgGroupInv->actionTimestamp; - mLog["delay"] = delay; + _log.addProperty("delay", delay); if (delay > 30000) { CfgGroupInv->action = zeroExportAction_t::doActivePowerContr; - mLog["do"] = "doActivePowerContr"; + _log.addProperty("do", "doActivePowerContr"); } if (delay > 60000) { CfgGroupInv->action = zeroExportAction_t::doRestart; - mLog["do"] = "doRestart"; + _log.addProperty("do", "doRestart"); } } } @@ -583,8 +599,6 @@ class ZeroExport { putQueue(Entry); sendLog(); - clearLog(); - return; } } @@ -634,40 +648,59 @@ class ZeroExport { if (strcmp(mCfg->groups[group].battTopic, String(topic).c_str())) { mCfg->groups[group].battValue = (bool)obj["val"]; - mLog["k"] = mCfg->groups[group].battTopic; - mLog["v"] = mCfg->groups[group].battValue; + + + _log.addProperty("k", mCfg->groups[group].battTopic); + _log.addProperty("v", mCfg->groups[group].battValue); } } // "topic":"ctrl/zero" if (topic.indexOf("ctrl/zero") == -1) return; - if (mCfg->debug) mLog["d"] = obj; + + _log.addProperty("d", obj); if (obj["path"] == "ctrl" && obj["cmd"] == "zero") { int8_t topicGroup = getGroupFromTopic(topic.c_str()); int8_t topicInverter = getInverterFromTopic(topic.c_str()); - if (topicGroup != -1) mLog["g"] = topicGroup; - if (topicInverter == -1) mLog["i"] = topicInverter; + if (topicGroup != -1) { + _log.addProperty("g", topicGroup); + } + if (topicInverter == -1) { + _log.addProperty("i", topicInverter); + } - mLog["k"] = topic; + _log.addProperty("k", topic); // "topic":"ctrl/zero/enabled" - if (topic.indexOf("ctrl/zero/enabled") != -1) mCfg->enabled = mLog["v"] = (bool)obj["val"]; + if (topic.indexOf("ctrl/zero/enabled") != -1) { + _log.addProperty("v", (bool)obj["val"]); + mCfg->enabled = (bool)obj["val"]; + } // "topic":"ctrl/zero/sleep" - else if (topic.indexOf("ctrl/zero/sleep") != -1) mCfg->sleep = mLog["v"] = (bool)obj["val"]; + else if (topic.indexOf("ctrl/zero/sleep") != -1) { + _log.addProperty("v", (bool)obj["val"]); + mCfg->sleep = (bool)obj["val"]; + } else if ((topicGroup >= 0) && (topicGroup < ZEROEXPORT_MAX_GROUPS)) { String stopicGroup = String(topicGroup); // "topic":"ctrl/zero/groups/+/enabled" - if (topic.endsWith("/enabled")) mCfg->groups[topicGroup].enabled = mLog["v"] = (bool)obj["val"]; + if (topic.endsWith("/enabled")) { + _log.addProperty("v", (bool)obj["val"]); + mCfg->groups[topicGroup].enabled = (bool)obj["val"]; + } // "topic":"ctrl/zero/groups/+/sleep" - else if (topic.endsWith("/sleep")) mCfg->groups[topicGroup].sleep = mLog["v"] = (bool)obj["val"]; + else if (topic.endsWith("/sleep")) { + _log.addProperty("v", (bool)obj["val"]); + mCfg->groups[topicGroup].sleep = (bool)obj["val"]; + } // Auf Eis gelegt, dafür 2 Gruppen mehr // 0.8.103008.2 @@ -692,42 +725,64 @@ class ZeroExport { // } // "topic":"ctrl/zero/groups/+/battery/switch" - else if (topic.endsWith("/battery/switch")) mCfg->groups[topicGroup].battSwitch = mLog["v"] = (bool)obj["val"]; + else if (topic.endsWith("/battery/switch")) { + _log.addProperty("v", (bool)obj["val"]); + mCfg->groups[topicGroup].battSwitch = (bool)obj["val"]; + } 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"]; + if (topic.endsWith("/setPoint")) { + _log.addProperty("v", (int16_t)obj["val"]); + mCfg->groups[topicGroup].setPoint = (int16_t)obj["val"]; + } // "topic":"ctrl/zero/groups/+/advanced/powerTolerance" - else if (topic.endsWith("/powerTolerance")) mCfg->groups[topicGroup].powerTolerance = mLog["v"] = (uint8_t)obj["val"]; + else if (topic.endsWith("/powerTolerance")) { + _log.addProperty("v", (uint8_t)obj["val"]); + mCfg->groups[topicGroup].powerTolerance = (uint8_t)obj["val"]; + } // "topic":"ctrl/zero/groups/+/advanced/powerMax" - else if (topic.endsWith("/powerMax")) mCfg->groups[topicGroup].powerMax = mLog["v"] = (uint16_t)obj["val"]; + else if (topic.endsWith("/powerMax")) { + _log.addProperty("v", (uint16_t)obj["val"]); + mCfg->groups[topicGroup].powerMax = (uint16_t)obj["val"]; + } } 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"]; + if (topic.endsWith("/enabled")) { + _log.addProperty("v", (bool)obj["val"]); + mCfg->groups[topicGroup].inverters[topicInverter].enabled = (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"]; - + else if (topic.endsWith("/powerMin")) { + _log.addProperty("v", (uint16_t)obj["val"]); + mCfg->groups[topicGroup].inverters[topicInverter].powerMin = (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 if (topic.endsWith("/powerMax")) { + _log.addProperty("v", (uint16_t)obj["val"]); + mCfg->groups[topicGroup].inverters[topicInverter].powerMax = (uint16_t)obj["val"]; + } + else + { + _log.addProperty("k", "error"); + } } } else { - mLog["k"] = "error"; + _log.addProperty("k", "error"); } } } sendLog(); - clearLog(); return; } @@ -770,7 +825,8 @@ class ZeroExport { while (*pGroupSection != '/' && digitsCopied < 2) strGroup[digitsCopied++] = *pGroupSection++; strGroup[digitsCopied] = '\0'; int8_t group = atoi(strGroup); - mLog["getGroupFromTopic"] = group; + + _log.addProperty("getGroupFromTopic", "group"); return group; } @@ -819,7 +875,7 @@ class ZeroExport { void sendLog(void) { // Log over Webserial if (mCfg->log_over_webserial) { - DPRINTLN(DBG_INFO, String("ze: ") + mDocLog.as()); + DPRINTLN(DBG_INFO, String("ze: ") + _log.toString()); } // Log over MQTT @@ -836,12 +892,15 @@ class ZeroExport { * Löscht den LogSpeicher */ void clearLog(void) { - mDocLog.clear(); + _log.clear(); } // private member variables bool mIsInitialized = false; + // Maximale Größe des JSON-Dokuments + static const size_t max_size = 5000; + IApp *mApp = nullptr; uint32_t *mTimestamp = nullptr; zeroExport_t *mCfg = nullptr; @@ -855,15 +914,12 @@ class ZeroExport { unsigned long mLastRun = 0; - StaticJsonDocument<5000> mDocLog; - JsonObject mLog = mDocLog.to(); - powermeter mPowermeter; PubMqttType *mMqtt = nullptr; bool mIsSubscribed = false; - StaticJsonDocument<512> mqttDoc; // DynamicJsonDocument mqttDoc(512); - JsonObject mqttObj = mqttDoc.to(); + + DynamicJsonHandler _log; }; #endif /*__ZEROEXPORT__*/ From c36ccad627ec25571c9c12d116d89e9589b2b687 Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Fri, 31 May 2024 19:14:27 +0200 Subject: [PATCH 2/6] Update powermeter.h --- src/plugins/zeroExport/powermeter.h | 89 +++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/src/plugins/zeroExport/powermeter.h b/src/plugins/zeroExport/powermeter.h index f8b634d2..4cf6f5d9 100644 --- a/src/plugins/zeroExport/powermeter.h +++ b/src/plugins/zeroExport/powermeter.h @@ -19,7 +19,7 @@ #include #include "plugins/zeroExport/lib/sml.h" - +#include "utils/DynamicJsonHandler.h" typedef struct { const unsigned char OBIS[6]; void (*Fn)(double &); @@ -46,7 +46,7 @@ class powermeter { * @param *log * @returns void */ - bool setup(IApp *app, zeroExport_t *cfg, PubMqttType *mqtt, JsonObject *log) { + bool setup(IApp *app, zeroExport_t *cfg, PubMqttType *mqtt, DynamicJsonHandler *log) { mApp = app; mCfg = cfg; mMqtt = mqtt; @@ -84,7 +84,7 @@ class powermeter { switch (mCfg->groups[group].pm_type) { #if defined(ZEROEXPORT_POWERMETER_SHELLY) case zeroExportPowermeterType_t::Shelly: - result = getPowermeterWattsShelly(*mLog, group, &power); + result = getPowermeterWattsShelly(group, &power); break; #endif #if defined(ZEROEXPORT_POWERMETER_TASMOTA) @@ -105,12 +105,12 @@ class powermeter { */ case zeroExportPowermeterType_t::Tibber: if (mCfg->groups[group].pm_refresh < 3) mCfg->groups[group].pm_refresh = 3; - result = getPowermeterWattsTibber(*mLog, group, &power); + result = getPowermeterWattsTibber(group, &power); break; #endif #if defined(ZEROEXPORT_POWERMETER_SHRDZM) case zeroExportPowermeterType_t::Shrdzm: - result = getPowermeterWattsShrdzm(*mLog, group, &power); + result = getPowermeterWattsShrdzm(group, &power); break; #endif } @@ -118,7 +118,7 @@ class powermeter { if (result) { bufferWrite(power, group); mCfg->groups[group].power = power; - + // MQTT - Powermeter /// BUG: 002 Anfang - Muss dieser Teil raus? Führt er zu abstürzen wie BUG 001? if (mMqtt->isConnected()) { @@ -239,7 +239,7 @@ class powermeter { bufferWrite(power, group); mCfg->groups[group].power = power; // TODO: join two sites together (PM & MQTT) - + // MQTT - Powermeter /// BUG: 001 Anfang - Dieser Teil ist deaktiviert weil er zu abstürzen der DTU führt // if (mCfg->debug) { @@ -280,7 +280,7 @@ class powermeter { zeroExport_t *mCfg; PubMqttType *mMqtt = nullptr; - JsonObject *mLog; + DynamicJsonHandler* mLog; IApp *mApp = nullptr; unsigned long mPreviousTsp = millis(); @@ -294,7 +294,7 @@ class powermeter { /** setHeader * */ - void setHeader(HTTPClient *h) { + void setHeader(HTTPClient *h, String auth = "", u8_t realm = NULL) { h->setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); /// h->setUserAgent("Ahoy-Agent"); /// // TODO: Ahoy-0.8.850024-zero @@ -303,6 +303,43 @@ class powermeter { h->setTimeout(1000); h->addHeader("Content-Type", "application/json"); h->addHeader("Accept", "application/json"); + + /* + Shelly PM Mini Gen3 + Shelly Plus 1PM + Shelly Plus 2PM + Shelly Pro 3EM - 120A + Shelly Pro 4PM + Shelly Pro Dual Cover / Shutter PM + Shelly Pro 1PM + Shelly Pro 2PM + Shelly Pro EM - 50 + Shelly Qubino Wave 1PM Mini + Shelly Qubino Wave PM Mini + Shelly Qubino Wave Shutter + Shelly Qubino Wave 1PM + Shelly Qubino Wave 2PM + Shelly Qubino Wave Pro 1PM + Shelly Qubino Wave Pro 2PM + Shelly 3EM + Shelly EM + 120A Clamp + + */ + + + /*if (auth != NULL && realm) http.addHeader("WWW-Authenticate", "Digest qop=\"auth\", realm=\"" + shellypro4pm-f008d1d8b8b8 + "\", nonce=\"60dc59c6\", algorithm=SHA-256"); + else if (auth != NULL) http.addHeader("Authorization", "Basic " + auth);*/ + /* + All Required: + realm: string, device_id of the Shelly device. + username: string, must be set to admin. + nonce: number, random or pseudo-random number to prevent replay attacks, taken from the error message. + cnonce: number, client nonce, random number generated by the client. + response: string, encoding of the string + ":" + + ":" + + ":" + + ":" + "auth" + ":" + in SHA256. + ha1: string, :: encoded in SHA256 + ha2: string, "dummy_method:dummy_uri" encoded in SHA256 + algorithm: string, SHA-256. + */ } #if defined(ZEROEXPORT_POWERMETER_SHELLY) @@ -312,13 +349,13 @@ class powermeter { * @param group * @returns true/false */ - bool getPowermeterWattsShelly(JsonObject logObj, uint8_t group, float *power) { - logObj["mod"] = "getPowermeterWattsShelly"; + bool getPowermeterWattsShelly(uint8_t group, float *power) { + mLog->addProperty("mod", "getPowermeterWattsShelly"); setHeader(&http); String url = String("http://") + String(mCfg->groups[group].pm_src) + String("/") + String(mCfg->groups[group].pm_jsonPath); - logObj["HTTP_URL"] = url; + mLog->addProperty("HTTP_URL", url); http.begin(url); @@ -327,7 +364,7 @@ class powermeter { DynamicJsonDocument doc(2048); DeserializationError error = deserializeJson(doc, http.getString()); if (error) { - logObj["err"] = "deserializeJson: " + String(error.c_str()); + mLog->addProperty("err", "deserializeJson: " + String(error.c_str())); return false; } else { switch (mCfg->groups[group].pm_target) { @@ -395,7 +432,7 @@ class powermeter { * @param group * @returns true/false */ - bool getPowermeterWattsTasmota(JsonObject logObj, uint8_t group, float *power) { + bool getPowermeterWattsTasmota(DynamicJsonHandler logObj, uint8_t group, float *power) { logObj["mod"] = "getPowermeterWattsTasmota"; /* // TODO: nicht komplett @@ -467,7 +504,7 @@ class powermeter { * @param group * @returns true/false */ - bool getPowermeterWattsHichi(JsonObject logObj, uint8_t group, float *power) { + bool getPowermeterWattsHichi(DynamicJsonHandler logObj, uint8_t group, float *power) { logObj["mod"] = "getPowermeterWattsHichi"; // Hier neuer Code - Anfang @@ -518,17 +555,20 @@ class powermeter { {{0x01, 0x00, 0x01, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterImport}, {{0x01, 0x00, 0x02, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterExport}}; - bool getPowermeterWattsTibber(JsonObject logObj, uint8_t group, float *power) { + /* + Daniel92: https://tibber.com/de/api/lookup/price-overview?postalCode= + Hab ich mal ausgelesen... hintendran die PLZ eingeben + energy/todayHours//priceIncludingVat + */ + bool getPowermeterWattsTibber(uint8_t group, float *power) { bool result = false; - - logObj["mod"] = "getPowermeterWattsTibber"; + mLog->addProperty("mod", "getPowermeterWattsTibber"); 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); + setHeader(&http, auth); http.begin(url); - http.addHeader("Authorization", "Basic " + auth); if (http.GET() == HTTP_CODE_OK && http.getSize() > 0) { String myString = http.getString(); @@ -571,8 +611,8 @@ class powermeter { * @TODO: Username & Passwort wird mittels base64 verschlüsselt. Dies wird für die Authentizierung benötigt. Wichtig diese im WebUI unkenntlich zu machen und base64 im eeprom zu speichern, statt klartext. * @TODO: Abfrage Interval einbauen. Info: Datei-Size kann auch mal 0-bytes sein? */ - bool getPowermeterWattsShrdzm(JsonObject logObj, uint8_t group, float *power) { - logObj["mod"] = "getPowermeterWattsShrdzm"; + bool getPowermeterWattsShrdzm(uint8_t group, float *power) { + mLog->addProperty("mod", "getPowermeterWattsShrdzm"); setHeader(&http); @@ -587,7 +627,7 @@ class powermeter { DynamicJsonDocument doc(512); DeserializationError error = deserializeJson(doc, http.getString()); if (error) { - logObj["err"] = "deserializeJson: " + String(error.c_str()); + mLog->addProperty("err", "deserializeJson: " + String(error.c_str())); return false; } else { if (doc.containsKey(F("16.7.0"))) { @@ -606,8 +646,7 @@ class powermeter { */ void bufferWrite(float raw, short group) { mPowermeterBuffer[group][mPowermeterBufferPos[group]] = raw; - mPowermeterBufferPos[group]++; - if (mPowermeterBufferPos[group] >= 5) mPowermeterBufferPos[group] = 0; + mPowermeterBufferPos[group] = (mPowermeterBufferPos[group] + 1) % 5; } }; From 60aee22a48d22209b1e398e8bc4f8e8412699579 Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Fri, 31 May 2024 19:15:37 +0200 Subject: [PATCH 3/6] The new class for DynamicJsonDocument --- src/utils/DynamicJsonHandler.cpp | 39 ++++++++++++++++++++++++++++ src/utils/DynamicJsonHandler.h | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/utils/DynamicJsonHandler.cpp create mode 100644 src/utils/DynamicJsonHandler.h diff --git a/src/utils/DynamicJsonHandler.cpp b/src/utils/DynamicJsonHandler.cpp new file mode 100644 index 00000000..8b7c4fab --- /dev/null +++ b/src/utils/DynamicJsonHandler.cpp @@ -0,0 +1,39 @@ +#include "DynamicJsonHandler.h" + +DynamicJsonHandler::DynamicJsonHandler() : doc(min_size) { +} + +DynamicJsonHandler::~DynamicJsonHandler() { + delete &doc; +} + +String DynamicJsonHandler::toString() { + String jsonString; + serializeJson(doc, jsonString); + doc.clear(); // TODO: Entfernen wegen mqtt + webserial? + return jsonString; +} + +void DynamicJsonHandler::clear() { + doc.clear(); +} + +size_t DynamicJsonHandler::size() const { + return doc.memoryUsage(); +} + +void DynamicJsonHandler::resizeDocument(size_t requiredSize) { + // TODO: multiplikator zwei muss ersetzt werden? Kann noch minimal werden. + size_t newCapacity = min(max(requiredSize * 2, min_size), max_size); + DynamicJsonDocument newDoc(newCapacity); + newDoc.set(doc); // Bestehende Daten kopieren + doc = std::move(newDoc); +} + +size_t DynamicJsonHandler::min(size_t a, size_t b) { + return (a < b) ? a : b; +} + +size_t DynamicJsonHandler::max(size_t a, size_t b) { + return (a > b) ? a : b; +} diff --git a/src/utils/DynamicJsonHandler.h b/src/utils/DynamicJsonHandler.h new file mode 100644 index 00000000..4c7a7476 --- /dev/null +++ b/src/utils/DynamicJsonHandler.h @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// 2022 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __DYNAMICJSONHANDLER_H__ +#define __DYNAMICJSONHANDLER_H__ + +#include +#include +#include + +class DynamicJsonHandler { +public: + DynamicJsonHandler(); + ~DynamicJsonHandler(); + + template + void addProperty(const std::string& key, const T& value); + + String toString(); + void clear(); + size_t size() const; + +private: + DynamicJsonDocument doc; + static const size_t min_size = 256; + static const size_t max_size = 5000; // Max RAM : 2 = da es für resizeDocument eng werden könnte? + + void resizeDocument(size_t requiredSize); + size_t min(size_t a, size_t b); + size_t max(size_t a, size_t b); +}; + +template +void DynamicJsonHandler::addProperty(const std::string& key, const T& value) { + size_t additionalSize = JSON_OBJECT_SIZE(1) + key.length() + sizeof(value); + if (doc.memoryUsage() + additionalSize > doc.capacity()) { + resizeDocument(doc.memoryUsage() + additionalSize); + } + doc[key] = value; +} + +#endif /*__DYNAMICJSONHANDLER_H__*/ From 1201bda0863d5a1a90833d5c3ad0792f24be4ede Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Fri, 31 May 2024 20:27:28 +0200 Subject: [PATCH 4/6] remove doc.clear(); from toString() doc.clear(); // TODO: Entfernen wegen mqtt + webserial? --- src/utils/DynamicJsonHandler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/DynamicJsonHandler.cpp b/src/utils/DynamicJsonHandler.cpp index 8b7c4fab..7ec5a059 100644 --- a/src/utils/DynamicJsonHandler.cpp +++ b/src/utils/DynamicJsonHandler.cpp @@ -10,7 +10,6 @@ DynamicJsonHandler::~DynamicJsonHandler() { String DynamicJsonHandler::toString() { String jsonString; serializeJson(doc, jsonString); - doc.clear(); // TODO: Entfernen wegen mqtt + webserial? return jsonString; } From 7c7f5b507c9382f05faca9b961f974c2c3ec32d0 Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Fri, 31 May 2024 20:28:05 +0200 Subject: [PATCH 5/6] insert clearlog() needed insert again, because mqtt and other stuff --- src/plugins/zeroExport/zeroExport.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/plugins/zeroExport/zeroExport.h b/src/plugins/zeroExport/zeroExport.h index 4bd400b5..572c07e9 100644 --- a/src/plugins/zeroExport/zeroExport.h +++ b/src/plugins/zeroExport/zeroExport.h @@ -101,6 +101,7 @@ class ZeroExport { _log.addProperty("nA", "!isAvailable"); sendLog(); } + clearLog(); return; } @@ -110,6 +111,7 @@ class ZeroExport { _log.addProperty("wA", CfgGroupInv->waitAck); sendLog(); } + clearLog(); return; } @@ -188,6 +190,7 @@ class ZeroExport { e = 0; _log.addProperty("eK", e); sendLog(); + clearLog(); return; } @@ -203,6 +206,7 @@ class ZeroExport { if (Ta == 0) { _log.addProperty("Error", "Ta = 0"); sendLog(); + clearLog(); return; } int16_t yD = Kd * (e - CfgGroup->eOld) / Ta; @@ -360,6 +364,9 @@ class ZeroExport { // mqttPublish(String("zero/state/groups/" + String(group) + "/inverter/" + String(inv)).c_str(), mDocLog.as().c_str()); // } /// BUG: 003 Ende + + clearLog(); + return; } @@ -445,6 +452,7 @@ class ZeroExport { _log.addProperty("lF", mCfg->groups[group].inverters[inv].limit); } sendLog(); + clearLog(); } } } @@ -472,6 +480,7 @@ class ZeroExport { _log.addProperty("wA", mCfg->groups[group].inverters[inv].waitAck); sendLog(); + clearLog(); } } } @@ -510,6 +519,7 @@ class ZeroExport { mCfg->groups[group].inverters[inv].actionTimestamp = millis(); } sendLog(); + clearLog(); } } } @@ -599,6 +609,7 @@ class ZeroExport { putQueue(Entry); sendLog(); + clearLog(); return; } } @@ -783,6 +794,7 @@ class ZeroExport { } sendLog(); + clearLog(); return; } From 8ef77eb21cf352fd881bbe9e727d75b41c21228a Mon Sep 17 00:00:00 2001 From: Patrick Amrhein Date: Fri, 31 May 2024 20:49:33 +0200 Subject: [PATCH 6/6] 0.8.1030019 --- src/defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defines.h b/src/defines.h index ffdbadf2..308ff3f2 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 1030018 +#define VERSION_PATCH 1030019 //------------------------------------- typedef struct { uint8_t ch;