From 06b34b16c48e5fa2886ecbf741f34a2ab4f9db45 Mon Sep 17 00:00:00 2001 From: Patrick Amrhein Date: Wed, 1 May 2024 09:21:36 +0200 Subject: [PATCH] 0.8.1030008 --- src/config/settings.h | 3 + src/defines.h | 2 +- src/plugins/zeroExport/powermeter.h | 51 +++++++++++++--- src/plugins/zeroExport/zeroExport.h | 91 ++++++++++++++++++++++------- 4 files changed, 117 insertions(+), 30 deletions(-) diff --git a/src/config/settings.h b/src/config/settings.h index 23a53560..306f1d43 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -265,6 +265,8 @@ typedef struct { // zeroExportAction_t action; + int8_t actionTimer; + unsigned long actionTimestamp; uint16_t power; uint16_t MaxPower; int32_t limit; @@ -682,6 +684,7 @@ class settings { // mCfg.plugin.zeroExport.groups[group].inverters[inv].waitAck = 0; mCfg.plugin.zeroExport.groups[group].inverters[inv].action = zeroExportAction_t::doNone; + mCfg.plugin.zeroExport.groups[group].inverters[inv].actionTimer = 0;; mCfg.plugin.zeroExport.groups[group].inverters[inv].dcVoltage = 0; mCfg.plugin.zeroExport.groups[group].inverters[inv].limit = 0; mCfg.plugin.zeroExport.groups[group].inverters[inv].limitNew = 0; diff --git a/src/defines.h b/src/defines.h index 9c3cdd0a..088e77e6 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 1030007 +#define VERSION_PATCH 1030008 //------------------------------------- typedef struct { uint8_t ch; diff --git a/src/plugins/zeroExport/powermeter.h b/src/plugins/zeroExport/powermeter.h index 9ea42f09..7b7daacb 100644 --- a/src/plugins/zeroExport/powermeter.h +++ b/src/plugins/zeroExport/powermeter.h @@ -109,6 +109,8 @@ class powermeter { #endif } + if ((power.P == 0) and (power.P1 == 0) && (power.P2 == 0) && (power.P3 == 0)) return; + bufferWrite(power, group); // MQTT - Powermeter @@ -153,6 +155,19 @@ class powermeter { * */ void onMqttConnect(void) { + +#if defined(ZEROEXPORT_POWERMETER_MQTT) + + for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { + if (mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) { +// if (String(mCfg->groups[group].pm_jsonPath) == "") return; + + mMqtt->subscribe(String(mCfg->groups[group].pm_jsonPath).c_str(), QOS_2); + } + } + +#endif /*defined(ZEROEXPORT_POWERMETER_MQTT)*/ + } /** @@ -163,17 +178,39 @@ class powermeter { #if defined(ZEROEXPORT_POWERMETER_MQTT) // topic for powermeter? - for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { - if (mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) { - // mLog["mqttDevice"] = "topicInverter"; - if (!topic.equals(mCfg->groups[group].pm_jsonPath)) return; - mCfg->groups[group].pm_P = (int32_t)obj["val"]; - } - } +// for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { +// if (mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) { +// // mLog["mqttDevice"] = "topicInverter"; +// if (!topic.equals(mCfg->groups[group].pm_jsonPath)) return; +// mCfg->groups[group].pm_P = (int32_t)obj["val"]; +// } +// } #endif /*defined(ZEROEXPORT_POWERMETER_MQTT)*/ } private: + /** mqttSubscribe + * when a MQTT Msg is needed to subscribe, then a publish is leading + * @param gr + * @param payload + * @returns void + */ + void mqttSubscribe(String gr, String payload) { +// mqttPublish(gr, payload); + mMqtt->subscribe(gr.c_str(), QOS_2); + } + + /** mqttPublish + * when a MQTT Msg is needed to Publish, but not to subscribe. + * @param gr + * @param payload + * @param retain + * @returns void + */ + void mqttPublish(String gr, String payload, bool retain = false) { + mMqtt->publish(gr.c_str(), payload.c_str(), retain); + } + HTTPClient http; zeroExport_t *mCfg; diff --git a/src/plugins/zeroExport/zeroExport.h b/src/plugins/zeroExport/zeroExport.h index 6c81f643..7007d212 100644 --- a/src/plugins/zeroExport/zeroExport.h +++ b/src/plugins/zeroExport/zeroExport.h @@ -239,35 +239,35 @@ class ZeroExport { // Regelbegrenzung // TODO: Hier könnte man den maximalen Sprung begrenzen - // Keine Regelung wenn Maximalleistung des Inverters unbekannt ist - if (CfgGroupInv->MaxPower == 0) { - y = 0; - mLog["yK"] = y; - } - // Stellgröße y in W CfgGroupInv->limitNew += y; // Check if (CfgGroupInv->action == zeroExportAction_t::doNone) { -// if ((CfgGroup->battSwitch == true) && (CfgGroupInv->limitNew > CfgGroupInv->powerMin) && (CfgGroupInv->power == 0) && (mCfg->sleep != true) && (CfgGroup->sleep != true)) { -// TODO: Schlägt fehl, weil wenn MaxPower = 0 wird y auf 0 gesetzt und damit ist limitNew = powerMin - if ((CfgGroup->battSwitch == true) && (CfgGroupInv->power == 0) && (mCfg->sleep != true) && (CfgGroup->sleep != true)) { - CfgGroupInv->action = zeroExportAction_t::doTurnOn; - mLog["do"] = "doTurnOn"; + if ((CfgGroup->battSwitch == true) && (CfgGroupInv->limitNew > CfgGroupInv->powerMin) && (CfgGroupInv->power == 0) && (mCfg->sleep != true) && (CfgGroup->sleep != true)) { + if (CfgGroupInv->actionTimer < 0) CfgGroupInv->actionTimer = 0; + if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = 1; + if (CfgGroupInv->actionTimer > 10) { + CfgGroupInv->action = zeroExportAction_t::doTurnOn; + mLog["do"] = "doTurnOn"; + } } - - if (((CfgGroup->battSwitch == false) || (CfgGroupInv->limitNew < 0)) && (CfgGroupInv->power > 0)) { - CfgGroupInv->action = zeroExportAction_t::doTurnOff; - mLog["do"] = "doTurnOff"; +// TODO: hier kommt eine CheckBox je Gruppe rein, die es verhindert, dass Inv ausgeschaltet werden. + if ((CfgGroupInv->limitNew <= 0) && (CfgGroupInv->power > 0)) { + if (CfgGroupInv->actionTimer > 0) CfgGroupInv->actionTimer = 0; + if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = -1; + if (CfgGroupInv->actionTimer < 30) { + CfgGroupInv->action = zeroExportAction_t::doTurnOff; + mLog["do"] = "doTurnOff"; + } } - - if (((mCfg->sleep == true) || (CfgGroup->sleep == true)) && (CfgGroupInv->power > 0)) { + if (((CfgGroup->battSwitch == false) || (mCfg->sleep == true) || (CfgGroup->sleep == true)) && (CfgGroupInv->power > 0)) { CfgGroupInv->action = zeroExportAction_t::doTurnOff; mLog["do"] = "sleep"; } } + mLog["doT"] = CfgGroupInv->action; if (CfgGroupInv->action == zeroExportAction_t::doNone) { mLog["l"] = CfgGroupInv->limit; @@ -302,6 +302,16 @@ class ZeroExport { if (CfgGroupInv->limit != CfgGroupInv->limitNew) CfgGroupInv->action = zeroExportAction_t::doActivePowerContr; + if ((CfgGroupInv->limit == powerMin) && (CfgGroupInv->power == 0)) { + CfgGroupInv->action = zeroExportAction_t::doNone; + if (!mCfg->debug) { + clearLog(); + return; + } + } + +// CfgGroupInv->actionTimer = 0; +// TODO: Timer stoppen wenn Limit gesetzt wird. mLog["lN"] = CfgGroupInv->limitNew; CfgGroupInv->limit = CfgGroupInv->limitNew; @@ -316,6 +326,8 @@ class ZeroExport { mApp->triggerTickSend(iv->id); CfgGroupInv->waitAck = 120; CfgGroupInv->action = zeroExportAction_t::doNone; + CfgGroupInv->actionTimer = 0; + CfgGroupInv->actionTimestamp = Tsp; } break; case zeroExportAction_t::doTurnOn: @@ -323,6 +335,8 @@ class ZeroExport { mApp->triggerTickSend(iv->id); CfgGroupInv->waitAck = 120; CfgGroupInv->action = zeroExportAction_t::doNone; + CfgGroupInv->actionTimer = 0; + CfgGroupInv->actionTimestamp = Tsp; } break; case zeroExportAction_t::doTurnOff: @@ -330,20 +344,19 @@ class ZeroExport { mApp->triggerTickSend(iv->id); CfgGroupInv->waitAck = 120; CfgGroupInv->action = zeroExportAction_t::doNone; + CfgGroupInv->actionTimer = 0; + CfgGroupInv->actionTimestamp = Tsp; } break; case zeroExportAction_t::doActivePowerContr: - if ((CfgGroupInv->limit <= CfgGroupInv->powerMin) && (CfgGroupInv->power == 0)) { - clearLog(); - return; - } - iv->powerLimit[0] = static_cast(CfgGroupInv->limit * 10.0); iv->powerLimit[1] = AbsolutNonPersistent; if (iv->setDevControlRequest(ActivePowerContr)) { mApp->triggerTickSend(iv->id); CfgGroupInv->waitAck = 60; CfgGroupInv->action = zeroExportAction_t::doNone; + CfgGroupInv->actionTimer = 0; + CfgGroupInv->actionTimestamp = Tsp; } break; default: @@ -382,6 +395,9 @@ class ZeroExport { if (mCfg->groups[group].inverters[inv].waitAck > 0) { mCfg->groups[group].inverters[inv].waitAck--; } + + if (mCfg->groups[group].inverters[inv].actionTimer > 0) mCfg->groups[group].inverters[inv].actionTimer++; + if (mCfg->groups[group].inverters[inv].actionTimer < 0) mCfg->groups[group].inverters[inv].actionTimer--; } } } @@ -537,6 +553,28 @@ class ZeroExport { CfgGroupInv->dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec); mLog["bU"] = ah::round1(CfgGroupInv->dcVoltage); + +// Fallschirm 2: Für nicht übernommene Limits bzw. nicht regelnde Inverter +// Bisher ist nicht geklärt ob der Inverter das Limit bestätigt hat +// Erstmalig aufgetreten bei @knickohr am 28.04.2024 ... l=300 pM=300, p=9 +if (CfgGroupInv->MaxPower > 0) { +uint16_t limitPercent = 100 / CfgGroupInv->MaxPower * CfgGroupInv->limit; +uint16_t powerPercent = 100 / CfgGroupInv->MaxPower * CfgGroupInv->power; +uint16_t delta = abs(limitPercent - powerPercent); +if ((delta > 10) && (CfgGroupInv->power > 0)) { + mLog["delta"] = delta; + unsigned long delay = iv->getLastTs(rec) - CfgGroupInv->actionTimestamp; + mLog["delay"] = delay; + if (delay > 30000) { + CfgGroupInv->action = zeroExportAction_t::doActivePowerContr; + mLog["do"] = "doActivePowerContr"; + } + if (delay > 60000) { + CfgGroupInv->action = zeroExportAction_t::doRestart; + mLog["do"] = "doRestart"; + } +} +} } zeroExportQueue_t Entry; @@ -560,6 +598,12 @@ class ZeroExport { */ void onMqttConnect(void) { mPowermeter.onMqttConnect(); + + for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { + // if (String(mCfg->groups[group].battSoC) == "") return; + + mMqtt->subscribe(String(mCfg->groups[group].battSoC).c_str(), QOS_2); + } } /** onMqttMessage @@ -570,6 +614,9 @@ class ZeroExport { void onMqttMessage(JsonObject obj) { if (!mIsInitialized) return; + if (mCfg->debug) mLog["d"] = obj; + sendLog(); + clearLog(); mPowermeter.onMqttMessage(obj); String topic = String(obj["topic"]);