diff --git a/src/app.cpp b/src/app.cpp index ae78b0cf..7334e218 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -74,7 +74,7 @@ void app::setup() { #if defined(PLUGIN_ZEROEXPORT) || defined(ENABLE_MQTT) mCommunication.addPowerLimitAckListener([this] (Inverter<> *iv) { #if defined(PLUGIN_ZEROEXPORT) - mZeroExport.resetWaitLimitAck(iv); + mZeroExport.eventAckSetLimit(iv); #endif /*PLUGIN_ZEROEXPORT*/ #if defined(ENABLE_MQTT) mMqtt.setPowerLimitAck(iv); @@ -83,17 +83,17 @@ void app::setup() { #endif /*defined(PLUGIN_ZEROEXPORT) || defined(ENABLE_MQTT)*/ #if defined(PLUGIN_ZEROEXPORT) mCommunication.addPowerPowerAckListener([this] (Inverter<> *iv) { - mZeroExport.resetWaitPowerAck(iv); + mZeroExport.eventAckSetPower(iv); }); #endif /*PLUGIN_ZEROEXPORT*/ #if defined(PLUGIN_ZEROEXPORT) mCommunication.addPowerRebootAckListener([this] (Inverter<> *iv) { - mZeroExport.resetWaitRebootAck(iv); + mZeroExport.eventAckSetReboot(iv); }); #endif /*PLUGIN_ZEROEXPORT*/ #if defined(PLUGIN_ZEROEXPORT) mCommunication.addNewDataListener([this] (Inverter<> *iv) { - mZeroExport.newDataAvailable(iv); + mZeroExport.eventNewDataAvailable(iv); }); #endif /*PLUGIN_ZEROEXPORT*/ diff --git a/src/config/settings.h b/src/config/settings.h index d9fcb880..7b3eac3d 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -233,7 +233,6 @@ enum class zeroExportState : uint8_t { SETREBOOT, SETPOWER, SETLIMIT, - PUBLISH, EMERGENCY, FINISH, ERROR @@ -270,16 +269,16 @@ typedef struct { int32_t power; int32_t limit; int32_t limitNew; - uint8_t waitLimitAck; - uint8_t waitPowerAck; - uint8_t waitRebootAck; + uint8_t waitAckSetLimit; + uint8_t waitAckSetPower; + uint8_t waitAckSetReboot; unsigned long limitTsp; - float dcVoltage; bool state; // int8_t doReboot; int8_t doPower; int8_t doLimit; + float dcVoltage; } zeroExportGroupInverter_t; typedef struct { @@ -711,12 +710,13 @@ class settings { mCfg.plugin.zeroExport.groups[group].inverters[inv].powerMin = 10; mCfg.plugin.zeroExport.groups[group].inverters[inv].powerMax = 600; // - mCfg.plugin.zeroExport.groups[group].inverters[inv].waitLimitAck = false; - mCfg.plugin.zeroExport.groups[group].inverters[inv].waitPowerAck = false; - mCfg.plugin.zeroExport.groups[group].inverters[inv].waitRebootAck = false; + mCfg.plugin.zeroExport.groups[group].inverters[inv].waitAckSetLimit = false; + mCfg.plugin.zeroExport.groups[group].inverters[inv].waitAckSetPower = false; + mCfg.plugin.zeroExport.groups[group].inverters[inv].waitAckSetReboot = false; mCfg.plugin.zeroExport.groups[group].inverters[inv].doReboot = -1; mCfg.plugin.zeroExport.groups[group].inverters[inv].doPower = -1; mCfg.plugin.zeroExport.groups[group].inverters[inv].doLimit = -1; + mCfg.plugin.zeroExport.groups[group].inverters[inv].dcVoltage = 0; } // Battery mCfg.plugin.zeroExport.groups[group].battEnabled = false; @@ -734,7 +734,7 @@ class settings { mCfg.plugin.zeroExport.groups[group].state = zeroExportState::INIT; mCfg.plugin.zeroExport.groups[group].lastRun = 0; mCfg.plugin.zeroExport.groups[group].lastRefresh = 0; - mCfg.plugin.zeroExport.groups[group].wait = 0; + mCfg.plugin.zeroExport.groups[group].wait = 60000; mCfg.plugin.zeroExport.groups[group].pm_P = 0; mCfg.plugin.zeroExport.groups[group].pm_P1 = 0; mCfg.plugin.zeroExport.groups[group].pm_P2 = 0; diff --git a/src/plugins/zeroExport/powermeter.txt b/src/plugins/zeroExport/powermeter.txt index ba066067..fb808e33 100644 --- a/src/plugins/zeroExport/powermeter.txt +++ b/src/plugins/zeroExport/powermeter.txt @@ -26,6 +26,23 @@ Abfrage: Ergebnis: {"ble":{},"cloud":{"connected":true},"em:0":{"id":0,"a_current":1.269,"a_voltage":228.5,"a_act_power":239.8,"a_aprt_power":289.7,"a_pf":0.86,"a_freq":50.0,"b_current":0.348,"b_voltage":227.5,"b_act_power":24.7,"b_aprt_power":79.0,"b_pf":0.58,"b_freq":50.0,"c_current":0.378,"c_voltage":228.5,"c_act_power":42.3,"c_aprt_power":86.3,"c_pf":0.66,"c_freq":50.0,"n_current":null,"total_current":1.995,"total_act_power":306.811,"total_aprt_power":455.018, "user_calibrated_phase":[]},"emdata:0":{"id":0,"a_total_act_energy":648103.86,"a_total_act_ret_energy":0.00,"b_total_act_energy":142793.47,"b_total_act_ret_energy":171396.02,"c_total_act_energy":493778.01,"c_total_act_ret_energy":0.00,"total_act":1284675.34, "total_act_ret":171396.02},"eth":{"ip":null},"modbus":{},"mqtt":{"connected":false},"script:1":{"id":1,"running":true,"mem_used":1302,"mem_peak":3094,"mem_free":23898},"sys":{"mac":"3CE90E6EBE5C","restart_required":false,"time":"18:09","unixtime":1712074162,"uptime":3180551,"ram_size":240004,"ram_free":96584,"fs_size":524288,"fs_free":176128,"cfg_rev":23,"kvs_rev":9104,"schedule_rev":0,"webhook_rev":0,"available_updates":{},"reset_reason":3},"temperature:0":{"id": 0,"tC":46.2, "tF":115.1},"wifi":{"sta_ip":"192.168.0.69","status":"got ip","ssid":"Riker","rssi":-70},"ws":{"connected":false}} +Shelly PM Mini Gen3 +------------------- + +Stand: 04.04.2024 + +Abfrage: +rpc/PM1.GetStatus?id=0 + +Ergebnis: +{"id":0, "voltage":226.0, "current":0.384, "apower":-55.0 ,"freq":50.0,"aenergy":{"total":11755.618,"by_minute":[1063.082,1700.931,1275.698],"minute_ts":1712248200},"ret_aenergy":{"total":10973.555,"by_minute":[1063.082,1700.931,1275.698],"minute_ts":1712248200}} + +Abfrage: +rpc/Shelly.GetStatus + +Ergebnis: +{"ble":{},"cloud":{"connected":true},"mqtt":{"connected":false},"pm1:0":{"id":0, "voltage":228.5, "current":0.451, "apower":-67.1 ,"freq":50.1,"aenergy":{"total":11754.555,"by_minute":[1700.931,1275.698,1913.547],"minute_ts":1712248140},"ret_aenergy":{"total":10972.492,"by_minute":[1700.931,1275.698,1913.547],"minute_ts":1712248140}},"sys":{"mac":"ECDA3BC63CC8","restart_required":false,"time":"18:29","unixtime":1712248162,"uptime":13723,"ram_size":260764,"ram_free":146460,"fs_size":1048576,"fs_free":729088,"cfg_rev":11,"kvs_rev":2,"schedule_rev":0,"webhook_rev":0,"available_updates":{},"reset_reason":1},"wifi":{"sta_ip":"192.168.0.57","status":"got ip","ssid":"Riker","rssi":-30},"ws":{"connected":false}} + --------------------------------------------------------------------------- Tasmota diff --git a/src/plugins/zeroExport/zeroExport.h b/src/plugins/zeroExport/zeroExport.h index 30e2885e..9f0f8ca9 100644 --- a/src/plugins/zeroExport/zeroExport.h +++ b/src/plugins/zeroExport/zeroExport.h @@ -40,6 +40,12 @@ class ZeroExport { /** setup * Initialisierung + * @param *cfg + * @param *sys + * @param *config + * @param *api + * @param *mqtt + * @returns void */ void setup(zeroExport_t *cfg, HMSYSTEM *sys, settings_t *config, RestApiType *api, PubMqttType *mqtt) { mCfg = cfg; @@ -48,16 +54,13 @@ class ZeroExport { mApi = api; mMqtt = mqtt; - mIsSubscribed = false; mIsInitialized = mPowermeter.setup(mCfg, &mLog); - } /** loop * Arbeitsschleife - * @param - * @returns - * @todo publish + * @param void + * @returns void * @todo emergency */ void loop(void) { @@ -69,39 +72,49 @@ class ZeroExport { unsigned long Tsp = millis(); mPowermeter.loop(&Tsp, &DoLog); - // if (DoLog) sendLog(); + if (DoLog) sendLog(); clearLog(); + DoLog = false; for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; + // enabled if (!cfgGroup->enabled) continue; // wait if (Tsp <= (cfgGroup->lastRun + cfgGroup->wait)) continue; cfgGroup->wait = 0; + // log mLog["g"] = group; mLog["s"] = (uint8_t)cfgGroup->state; + // Statemachine switch (cfgGroup->state) { case zeroExportState::INIT: if (groupInit(group, &Tsp, &DoLog)) { cfgGroup->state = zeroExportState::WAITREFRESH; - cfgGroup->wait = 60000; + cfgGroup->wait = 1000; } else { cfgGroup->state = zeroExportState::INIT; cfgGroup->wait = 60000; #if defined(ZEROEXPORT_DEV_POWERMETER) cfgGroup->state = zeroExportState::WAITREFRESH; - cfgGroup->wait = 10000; + cfgGroup->wait = 1000; #endif } break; case zeroExportState::WAITREFRESH: if (groupWaitRefresh(group, &Tsp, &DoLog)) { cfgGroup->state = zeroExportState::GETINVERTERDATA; + if (mCfg->sleep) { + cfgGroup->state = zeroExportState::SETPOWER; + for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { + cfgGroup->inverters[inv].limitNew = -99; + } + } #if defined(ZEROEXPORT_DEV_POWERMETER) cfgGroup->state = zeroExportState::GETPOWERMETER; #endif @@ -171,16 +184,12 @@ class ZeroExport { break; case zeroExportState::SETLIMIT: if (groupSetLimit(group, &Tsp, &DoLog)) { - cfgGroup->state = zeroExportState::PUBLISH; + cfgGroup->state = zeroExportState::WAITREFRESH; } else { cfgGroup->wait = 1000; - } - break; - case zeroExportState::PUBLISH: - if (groupPublish(group, &Tsp, &DoLog)) { - cfgGroup->state = zeroExportState::WAITREFRESH; - //} else { - // TODO: fehlt + if (mCfg->sleep) { + cfgGroup->wait = 60000; + } } break; case zeroExportState::EMERGENCY: @@ -219,24 +228,26 @@ class ZeroExport { * Time pulse every second * @param void * @returns void + * @todo Eventuell ein waitAck für alle 3 Set-Befehle + * @todo Eventuell ein waitAck für alle Inverter einer Gruppe */ void tickSecond() { if ((!mIsInitialized) || (!mCfg->enabled)) return; - // Wait for ACK + // Reduce WaitAck every second for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { - // Limit - if (mCfg->groups[group].inverters[inv].waitLimitAck > 0) { - mCfg->groups[group].inverters[inv].waitLimitAck--; + // WaitAckSetLimit + if (mCfg->groups[group].inverters[inv].waitAckSetLimit > 0) { + mCfg->groups[group].inverters[inv].waitAckSetLimit--; } - // Power - if (mCfg->groups[group].inverters[inv].waitPowerAck > 0) { - mCfg->groups[group].inverters[inv].waitPowerAck--; + // WaitAckSetPower + if (mCfg->groups[group].inverters[inv].waitAckSetPower > 0) { + mCfg->groups[group].inverters[inv].waitAckSetPower--; } - // Reboot - if (mCfg->groups[group].inverters[inv].waitRebootAck > 0) { - mCfg->groups[group].inverters[inv].waitRebootAck--; + // WaitAckSetReboot + if (mCfg->groups[group].inverters[inv].waitAckSetReboot > 0) { + mCfg->groups[group].inverters[inv].waitAckSetReboot--; } } } @@ -246,24 +257,26 @@ class ZeroExport { * Time pulse Midnicht * @param void * @returns void + * @todo Reboot der Inverter um Mitternacht in Ahoy selbst verschieben mit separater Config-Checkbox + * @todo Ahoy Config-Checkbox Reboot Inverter at Midnight beim groupInit() automatisch setzen. */ void tickMidnight(void) { - if ((!mIsInitialized) || (!mCfg->enabled)) return; + if (!mIsInitialized) return; // Select all Inverter to reboot for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { - // mCfg->groups[group].inverters[inv].doReboot = 1; + mCfg->groups[group].inverters[inv].doReboot = 1; } } } - /** resetWaitLimitAck + /** eventAckSetLimit * Reset waiting time limit * @param iv * @returns void */ - void resetWaitLimitAck(Inverter<> *iv) { + void eventAckSetLimit(Inverter<> *iv) { if ((!mIsInitialized) || (!mCfg->enabled)) return; for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { @@ -271,7 +284,8 @@ class ZeroExport { unsigned long bTsp = millis(); mLog["g"] = group; - mLog["t"] = "resetWaitLimitAck"; + mLog["s"] = (100 + (uint8_t)zeroExportState::SETLIMIT); + if (mCfg->debug) mLog["t"] = "eventAckSetLimit"; JsonArray logArr = mLog.createNestedArray("ix"); @@ -281,8 +295,8 @@ class ZeroExport { logObj["i"] = inv; logObj["id"] = iv->id; - mCfg->groups[group].inverters[inv].waitLimitAck = 0; - logObj["wL"] = mCfg->groups[group].inverters[inv].waitLimitAck; + mCfg->groups[group].inverters[inv].waitAckSetLimit = 0; + logObj["wL"] = mCfg->groups[group].inverters[inv].waitAckSetLimit; DoLog = true; } @@ -301,12 +315,12 @@ class ZeroExport { } } - /** resetPowerAck + /** eventAckSetPower * Reset waiting time power * @param iv * @returns void */ - void resetWaitPowerAck(Inverter<> *iv) { + void eventAckSetPower(Inverter<> *iv) { if ((!mIsInitialized) || (!mCfg->enabled)) return; for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { @@ -314,7 +328,8 @@ class ZeroExport { unsigned long bTsp = millis(); mLog["g"] = group; - mLog["t"] = "resetWaitPowerAck"; + mLog["s"] = (100 + (uint8_t)zeroExportState::SETPOWER); + if (mCfg->debug) mLog["t"] = "eventAckSetPower"; JsonArray logArr = mLog.createNestedArray("ix"); @@ -324,8 +339,8 @@ class ZeroExport { logObj["i"] = inv; logObj["id"] = iv->id; - mCfg->groups[group].inverters[inv].waitPowerAck = 30; - logObj["wP"] = mCfg->groups[group].inverters[inv].waitPowerAck; + mCfg->groups[group].inverters[inv].waitAckSetPower = 30; + logObj["wP"] = mCfg->groups[group].inverters[inv].waitAckSetPower; DoLog = true; } @@ -344,12 +359,12 @@ class ZeroExport { } } - /** resetWaitRebootAck + /** eventAckSetReboot * Reset waiting time reboot * @param iv * @returns void */ - void resetWaitRebootAck(Inverter<> *iv) { + void eventAckSetReboot(Inverter<> *iv) { if ((!mIsInitialized) || (!mCfg->enabled)) return; for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { @@ -357,7 +372,8 @@ class ZeroExport { unsigned long bTsp = millis(); mLog["g"] = group; - mLog["t"] = "resetWaitRebootAck"; + mLog["s"] = (100 + (uint8_t)zeroExportState::SETREBOOT); + if (mCfg->debug) mLog["t"] = "eventAckSetReboot"; JsonArray logArr = mLog.createNestedArray("ix"); @@ -367,8 +383,8 @@ class ZeroExport { logObj["i"] = inv; logObj["id"] = iv->id; - mCfg->groups[group].inverters[inv].waitRebootAck = 30; - logObj["wR"] = mCfg->groups[group].inverters[inv].waitRebootAck; + mCfg->groups[group].inverters[inv].waitAckSetReboot = 30; + logObj["wR"] = mCfg->groups[group].inverters[inv].waitAckSetReboot; DoLog = true; } @@ -387,12 +403,12 @@ class ZeroExport { } } - /** newDataAvailable + /** eventNewDataAvailable * * @param iv * @returns void */ - void newDataAvailable(Inverter<> *iv) { + void eventNewDataAvailable(Inverter<> *iv) { if ((!mIsInitialized) || (!mCfg->enabled)) return; if (!iv->isAvailable()) return; @@ -409,14 +425,10 @@ class ZeroExport { // Keine Datenübernahme wenn nicht enabled if (!mCfg->groups[group].inverters[inv].enabled) continue; - // Keine Datenübernahme wenn setReboot läuft - if (mCfg->groups[group].inverters[inv].waitRebootAck > 0) continue; - - // Keine Datenübernahme wenn setPower läuft - if (mCfg->groups[group].inverters[inv].waitPowerAck > 0) continue; - - // Keine Datenübernahme wenn setLimit läuft - if (mCfg->groups[group].inverters[inv].waitLimitAck > 0) continue; + // Keine Datenübernahme wenn setReboot, setPower, setLimit läuft + if (mCfg->groups[group].inverters[inv].waitAckSetReboot > 0) continue; + if (mCfg->groups[group].inverters[inv].waitAckSetPower > 0) continue; + if (mCfg->groups[group].inverters[inv].waitAckSetLimit > 0) continue; // Calculate int32_t ivLp = iv->actPowerLimit; @@ -455,6 +467,8 @@ class ZeroExport { /** onMqttMessage * Subscribe section + * @param + * @returns void */ void onMqttMessage(JsonObject obj) { if (!mIsInitialized) return; @@ -532,7 +546,7 @@ class ZeroExport { } } - mLog["Msg"] = obj; + if (mCfg->debug) mLog["Msg"] = obj; sendLog(); clearLog(); return; @@ -590,43 +604,42 @@ class ZeroExport { * @todo getInverterById statt getInverterByPos, dann würde die Variable *iv und die Schleife nicht gebraucht. */ bool groupInit(uint8_t group, unsigned long *tsp, bool *doLog) { - uint8_t result = false; - - if (mCfg->debug) mLog["t"] = "groupInit"; + zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; + bool result = false; mCfg->groups[group].lastRun = *tsp; + if (mCfg->debug) { + mLog["t"] = "groupInit"; + } + *doLog = true; - // Init ivPointer + // Clear Inverter-Pointer for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { mIv[group][inv] = nullptr; } - // Search/Set ivPointer + // Search/Get Inverter-Pointer JsonArray logArr = mLog.createNestedArray("ix"); for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { JsonObject logObj = logArr.createNestedObject(); logObj["i"] = inv; - mIv[group][inv] = nullptr; - - // Inverter not enabled or not selected -> ignore + // Inverter-Config not enabled or not selected -> ignore if (NotEnabledOrNotSelected(group, inv)) continue; - // Load Config + // Load Inverter-Config Inverter<> *iv; for (uint8_t i = 0; i < mSys->getNumInverters(); i++) { iv = mSys->getInverterByPos(i); - // Inverter not configured -> ignore + // Inverter not configured/matching -> ignore if (iv == NULL) continue; - - // Inverter not matching -> ignore if (iv->id != (uint8_t)mCfg->groups[group].inverters[inv].id) continue; - // Save Inverter + // Save Inverter-Pointer logObj["pos"] = i; logObj["id"] = iv->id; mIv[group][inv] = mSys->getInverterByPos(i); @@ -635,13 +648,14 @@ class ZeroExport { } } - // Init Acks + // Init waitAcks for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { - mCfg->groups[group].inverters[inv].waitLimitAck = 0; - mCfg->groups[group].inverters[inv].waitPowerAck = 0; - mCfg->groups[group].inverters[inv].waitRebootAck = 0; + mCfg->groups[group].inverters[inv].waitAckSetLimit = 0; + mCfg->groups[group].inverters[inv].waitAckSetPower = 0; + mCfg->groups[group].inverters[inv].waitAckSetReboot = 0; } + // Init lastRefresh for waitRefresh mCfg->groups[group].lastRefresh = *tsp; return result; @@ -653,14 +667,17 @@ class ZeroExport { * @returns true/false */ bool groupWaitRefresh(uint8_t group, unsigned long *tsp, bool *doLog) { - if (mCfg->debug) mLog["t"] = "groupWaitRefresh"; + zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; + + mCfg->groups[group].lastRun = *tsp; // Wait Refreshtime if (*tsp <= (mCfg->groups[group].lastRefresh + (mCfg->groups[group].refresh * 1000UL))) return false; - mCfg->groups[group].lastRun = *tsp; - - *doLog = true; + if (mCfg->debug) { + mLog["t"] = "groupWaitRefresh"; + *doLog = true; + } return true; } @@ -671,34 +688,49 @@ class ZeroExport { * @returns true/false */ bool groupGetInverterData(uint8_t group, unsigned long *tsp, bool *doLog) { - if (mCfg->debug) mLog["t"] = "groupGetInverterData"; + zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; - mCfg->groups[group].lastRun = *tsp; + cfgGroup->lastRun = *tsp; - mCfg->groups[group].power = 0; + if (mCfg->debug) { + mLog["t"] = "groupGetInverterData"; + *doLog = true; + } -// *doLog = true; + // Init data + cfgGroup->power = 0; // Get Data JsonArray logArr = mLog.createNestedArray("ix"); -/// bool wait = false; + int32_t power = 0; + for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { + zeroExportGroupInverter_t *cfgGroupInv = &cfgGroup->inverters[inv]; + JsonObject logObj = logArr.createNestedObject(); logObj["i"] = inv; // Inverter not enabled or not selected -> ignore if (NotEnabledOrNotSelected(group, inv)) continue; -// if (!mIv[group][inv]->isAvailable()) continue; + if (!mIv[group][inv]->isAvailable()) continue; - // Get Pac record_t<> *rec; rec = mIv[group][inv]->getRecordStruct(RealTimeRunData_Debug); - mCfg->groups[group].power += mIv[group][inv]->getChannelFieldValue(CH0, FLD_PAC, rec); - // TODO: Save Hole Power für die Webanzeige + // Get Pac + cfgGroupInv->power = mIv[group][inv]->getChannelFieldValue(CH0, FLD_PAC, rec); + logObj["P"] = cfgGroupInv->power; + power += cfgGroupInv->power; + + // Get dcVoltage + cfgGroupInv->dcVoltage = mIv[group][inv]->getChannelFieldValue(CH1, FLD_UDC, rec); + logObj["U"] = cfgGroupInv->dcVoltage; } + cfgGroup->power = power; + mLog["P"] = cfgGroup->power; + return true; } @@ -706,134 +738,73 @@ class ZeroExport { * Batterieschutzfunktion * @param group * @returns true/false + * @todo Inverter mit permanentem Limit versehen + * @todo BMS auslesen hinzufügen */ bool groupBatteryprotection(uint8_t group, unsigned long *tsp, bool *doLog) { - if (mCfg->debug) mLog["t"] = "groupBatteryprotection"; + zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; - mCfg->groups[group].lastRun = *tsp; + cfgGroup->lastRun = *tsp; - *doLog = true; + if (mCfg->debug) { + mLog["t"] = "groupBatteryprotection"; + *doLog = true; + } // Protection - if (mCfg->groups[group].battEnabled) { + if (cfgGroup->battEnabled) { mLog["en"] = true; // Config - parameter check - if (mCfg->groups[group].battVoltageOn <= mCfg->groups[group].battVoltageOff) { - mCfg->groups[group].battSwitch = false; - mLog["err"] = "Config - battVoltageOn(" + (String)mCfg->groups[group].battVoltageOn + ") <= battVoltageOff(" + (String)mCfg->groups[group].battVoltageOff + ")"; + if (cfgGroup->battVoltageOn <= cfgGroup->battVoltageOff) { + cfgGroup->battSwitch = false; + mLog["err"] = "Config - battVoltageOn(" + (String)cfgGroup->battVoltageOn + ") <= battVoltageOff(" + (String)cfgGroup->battVoltageOff + ")"; + *doLog = true; return false; } // Config - parameter check - if (mCfg->groups[group].battVoltageOn <= (mCfg->groups[group].battVoltageOff + 1)) { - mCfg->groups[group].battSwitch = false; - mLog["err"] = "Config - battVoltageOn(" + (String)mCfg->groups[group].battVoltageOn + ") <= battVoltageOff(" + (String)mCfg->groups[group].battVoltageOff + " + 1V)"; + if (cfgGroup->battVoltageOn <= (cfgGroup->battVoltageOff + 1)) { + cfgGroup->battSwitch = false; + mLog["err"] = "Config - battVoltageOn(" + (String)cfgGroup->battVoltageOn + ") <= battVoltageOff(" + (String)cfgGroup->battVoltageOff + " + 1V)"; + *doLog = true; return false; } // Config - parameter check - if (mCfg->groups[group].battVoltageOn <= 22) { - mCfg->groups[group].battSwitch = false; - mLog["err"] = "Config - battVoltageOn(" + (String)mCfg->groups[group].battVoltageOn + ") <= 22V)"; + if (cfgGroup->battVoltageOn <= 22) { + cfgGroup->battSwitch = false; + mLog["err"] = "Config - battVoltageOn(" + (String)cfgGroup->battVoltageOn + ") <= 22V)"; + *doLog = true; return false; } - int8_t id = 0; - float U = 0; - + bool switchOn = true; + bool switchOff = false; for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { - zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv]; + // Inverter not enabled or not selected -> ignore + if (NotEnabledOrNotSelected(group, inv)) continue; - // Ignore disabled Inverter - if (!cfgGroupInv->enabled) continue; - - if (cfgGroupInv->id < 0) continue; - - if (!mIv[group][inv]->isAvailable()) { - if (U > 0) continue; - U = 0; - id = cfgGroupInv->id; - continue; - } - - // Get U - record_t<> *rec; - rec = mIv[group][inv]->getRecordStruct(RealTimeRunData_Debug); - float tmp = mIv[group][inv]->getChannelFieldValue(CH1, FLD_UDC, rec); - if (U == 0) { - U = tmp; - id = cfgGroupInv->id; - } - if (U > tmp) { - U = tmp; - id = cfgGroupInv->id; - } + if (cfgGroup->inverters[inv].dcVoltage < cfgGroup->battVoltageOn) switchOn = false; + if (cfgGroup->inverters[inv].dcVoltage < cfgGroup->battVoltageOff) switchOff = true; } - mLog["i"] = id; - mLog["U"] = U; - - // Switch to ON - if (U > mCfg->groups[group].battVoltageOn) { - mCfg->groups[group].battSwitch = true; - mLog["act"] = "On"; - - for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { - // zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv]; - - // Inverter not enabled or not selected -> ignore - if (NotEnabledOrNotSelected(group, inv)) continue; - - // Abbruch weil Inverter nicht verfügbar - if (!mIv[group][inv]->isAvailable()) { - mLog["err"] = "is not Available"; - continue; - } - - // Nothing todo - if (mCfg->groups[group].battSwitch == mIv[group][inv]->isProducing()) { - mLog["err"] = "battSwitch " + String(mCfg->groups[group].battSwitch) + " == isProducing()" + String(mIv[group][inv]->isProducing()); - continue; - } - - mCfg->groups[group].state = zeroExportState::SETPOWER; - } - } - - // Switch to OFF - if (U < mCfg->groups[group].battVoltageOff) { - mCfg->groups[group].battSwitch = false; - mLog["act"] = "Off"; - - for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { - // zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv]; - - // Inverter not enabled or not selected -> ignore - if (NotEnabledOrNotSelected(group, inv)) continue; - - // Abbruch weil Inverter nicht verfügbar - if (!mIv[group][inv]->isAvailable()) { - mLog["err"] = "is not Available"; - continue; - } - - // Nothing todo - if (mCfg->groups[group].battSwitch == mIv[group][inv]->isProducing()) { - mLog["err"] = "battSwitch " + String(mCfg->groups[group].battSwitch) + " == isProducing()" + String(mIv[group][inv]->isProducing()); - continue; - } - - mCfg->groups[group].state = zeroExportState::SETPOWER; + if (switchOff == true) { + cfgGroup->battSwitch = false; + *doLog = true; + } else { + if (switchOn == true) { + cfgGroup->battSwitch = true; + *doLog = true; } } } else { mLog["en"] = false; - mCfg->groups[group].battSwitch = true; + cfgGroup->battSwitch = true; } - mLog["sw"] = mCfg->groups[group].battSwitch; + mLog["sw"] = cfgGroup->battSwitch; return true; } @@ -845,9 +816,11 @@ class ZeroExport { * @todo Eventuell muss am Ende geprüft werden ob die Daten vom Powermeter plausibel sind. */ bool groupGetPowermeter(uint8_t group, unsigned long *tsp, bool *doLog) { - if (mCfg->debug) mLog["t"] = "groupGetPowermeter"; + zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; + mCfg->groups[group].lastRun = *tsp; + if (mCfg->debug) mLog["t"] = "groupGetPowermeter"; *doLog = true; mCfg->groups[group].pm_P = mPowermeter.getDataAVG(group).P; @@ -868,16 +841,13 @@ class ZeroExport { mLog["P2"] = mCfg->groups[group].pm_P2; mLog["P3"] = mCfg->groups[group].pm_P3; - // Powermeter - // if (cfgGroup->publishPower) { - // cfgGroup->publishPower = false; + // MQTT - Powermeter mqttObj["Sum"] = mCfg->groups[group].pm_P; mqttObj["L1"] = mCfg->groups[group].pm_P1; mqttObj["L2"] = mCfg->groups[group].pm_P2; mqttObj["L3"] = mCfg->groups[group].pm_P3; mMqtt->publish("zero/state/powermeter/P", mqttDoc.as().c_str(), false); mqttDoc.clear(); - // } // if (cfgGroup->pm_Publish_W) { // cfgGroup->pm_Publish_W = false; @@ -889,107 +859,69 @@ class ZeroExport { // mMqtt->publish("zero/powermeter/W", doc.as().c_str(), false); // doc.clear(); // } + return true; } /** groupController * PID-Regler * @param group + * @param *tsp + * @param *doLog * @returns true/false */ bool groupController(uint8_t group, unsigned long *tsp, bool *doLog) { zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; - if (mCfg->debug) mLog["t"] = "groupController"; - cfgGroup->lastRun = *tsp; - *doLog = true; - // Führungsgröße w in Watt int32_t w = cfgGroup->setPoint; - mLog["w"] = w; // Regelgröße x in Watt int32_t x = cfgGroup->pm_P; int32_t x1 = cfgGroup->pm_P1; int32_t x2 = cfgGroup->pm_P2; int32_t x3 = cfgGroup->pm_P3; - mLog["x"] = x; - mLog["x1"] = x1; - mLog["x2"] = x2; - mLog["x3"] = x3; // Regelabweichung e in Watt int32_t e = w - x; int32_t e1 = w - x1; int32_t e2 = w - x2; int32_t e3 = w - x3; - mLog["e"] = e; - mLog["e1"] = e1; - mLog["e2"] = e2; - mLog["e3"] = e3; - if ( - (e < cfgGroup->powerTolerance) && (e > -cfgGroup->powerTolerance) && - (e1 < cfgGroup->powerTolerance) && (e1 > -cfgGroup->powerTolerance) && - (e2 < cfgGroup->powerTolerance) && (e2 > -cfgGroup->powerTolerance) && - (e3 < cfgGroup->powerTolerance) && (e3 > -cfgGroup->powerTolerance)) { - mLog["tol"] = cfgGroup->powerTolerance; - return false; - } // Regler float Kp = cfgGroup->Kp; float Ki = cfgGroup->Ki; float Kd = cfgGroup->Kd; unsigned long Ta = *tsp - mCfg->groups[group].lastRefresh; - mLog["Kp"] = Kp; - mLog["Ki"] = Ki; - mLog["Kd"] = Kd; - mLog["Ta"] = Ta; + // - P-Anteil int32_t yP = Kp * e; int32_t yP1 = Kp * e1; int32_t yP2 = Kp * e2; int32_t yP3 = Kp * e3; - mLog["yP"] = yP; - mLog["yP1"] = yP1; - mLog["yP2"] = yP2; - mLog["yP3"] = yP3; + // - I-Anteil cfgGroup->eSum += e; cfgGroup->eSum1 += e1; cfgGroup->eSum2 += e2; cfgGroup->eSum3 += e3; - mLog["esum"] = cfgGroup->eSum; - mLog["esum1"] = cfgGroup->eSum1; - mLog["esum2"] = cfgGroup->eSum2; - mLog["esum3"] = cfgGroup->eSum3; int32_t yI = Ki * Ta * cfgGroup->eSum; int32_t yI1 = Ki * Ta * cfgGroup->eSum1; int32_t yI2 = Ki * Ta * cfgGroup->eSum2; int32_t yI3 = Ki * Ta * cfgGroup->eSum3; - mLog["yI"] = yI; - mLog["yI1"] = yI1; - mLog["yI2"] = yI2; - mLog["yI3"] = yI3; + // - D-Anteil - mLog["ealt"] = cfgGroup->eOld; - mLog["ealt1"] = cfgGroup->eOld1; - mLog["ealt2"] = cfgGroup->eOld2; - mLog["ealt3"] = cfgGroup->eOld3; int32_t yD = Kd * (e - cfgGroup->eOld) / Ta; int32_t yD1 = Kd * (e1 - cfgGroup->eOld1) / Ta; int32_t yD2 = Kd * (e2 - cfgGroup->eOld2) / Ta; int32_t yD3 = Kd * (e3 - cfgGroup->eOld3) / Ta; - mLog["yD"] = yD; - mLog["yD1"] = yD1; - mLog["yD2"] = yD2; - mLog["yD3"] = yD3; cfgGroup->eOld = e; cfgGroup->eOld1 = e1; cfgGroup->eOld2 = e2; cfgGroup->eOld3 = e3; + // - PID-Anteil int32_t y = yP + yI + yD; int32_t y1 = yP1 + yI1 + yD1; @@ -999,14 +931,78 @@ class ZeroExport { // Regelbegrenzung // TODO: Hier könnte man den maximalen Sprung begrenzen + // Stellgröße cfgGroup->y = y; cfgGroup->y1 = y1; cfgGroup->y2 = y2; cfgGroup->y3 = y3; - mLog["y"] = y; - mLog["y1"] = y1; - mLog["y2"] = y2; - mLog["y3"] = y3; + + // Log + if (mCfg->debug) { + mLog["t"] = "groupController"; + *doLog = true; + + mLog["w"] = w; + + mLog["x"] = x; + mLog["x1"] = x1; + mLog["x2"] = x2; + mLog["x3"] = x3; + + mLog["e"] = e; + mLog["e1"] = e1; + mLog["e2"] = e2; + mLog["e3"] = e3; + + mLog["Kp"] = Kp; + mLog["Ki"] = Ki; + mLog["Kd"] = Kd; + mLog["Ta"] = Ta; + + mLog["yP"] = yP; + mLog["yP1"] = yP1; + mLog["yP2"] = yP2; + mLog["yP3"] = yP3; + + mLog["esum"] = cfgGroup->eSum; + mLog["esum1"] = cfgGroup->eSum1; + mLog["esum2"] = cfgGroup->eSum2; + mLog["esum3"] = cfgGroup->eSum3; + + mLog["yI"] = yI; + mLog["yI1"] = yI1; + mLog["yI2"] = yI2; + mLog["yI3"] = yI3; + + mLog["ealt"] = cfgGroup->eOld; + mLog["ealt1"] = cfgGroup->eOld1; + mLog["ealt2"] = cfgGroup->eOld2; + mLog["ealt3"] = cfgGroup->eOld3; + + mLog["yD"] = yD; + mLog["yD1"] = yD1; + mLog["yD2"] = yD2; + mLog["yD3"] = yD3; + + mLog["y"] = y; + mLog["y1"] = y1; + mLog["y2"] = y2; + mLog["y3"] = y3; + } + + // powerTolerance + if ( + (e < cfgGroup->powerTolerance) && + (e > -cfgGroup->powerTolerance) && + (e1 < cfgGroup->powerTolerance) && + (e1 > -cfgGroup->powerTolerance) && + (e2 < cfgGroup->powerTolerance) && + (e2 > -cfgGroup->powerTolerance) && + (e3 < cfgGroup->powerTolerance) && + (e3 > -cfgGroup->powerTolerance)) { + mLog["tol"] = cfgGroup->powerTolerance; + return false; + } return true; } @@ -1014,14 +1010,21 @@ class ZeroExport { /** groupPrognose * * @param group + * @param *tsp + * @param *doLog * @returns true/false + * @todo Vorhersage ob ein gedrosselter Inverter mehr Leistung liefern kann, wenn das Limit erhöht wird. + * @todo Klären in wieweit diese Funktion benötigt wird. */ bool groupPrognose(uint8_t group, unsigned long *tsp, bool *doLog) { - if (mCfg->debug) mLog["t"] = "groupPrognose"; + zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; mCfg->groups[group].lastRun = *tsp; - // *doLog = true; + if (mCfg->debug) { + mLog["t"] = "groupPrognose"; + *doLog = true; + } return true; } @@ -1032,24 +1035,27 @@ class ZeroExport { * @returns true/false */ bool groupAufteilen(uint8_t group, unsigned long *tsp, bool *doLog) { - if (mCfg->debug) mLog["t"] = "groupAufteilen"; + zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; - mCfg->groups[group].lastRun = *tsp; + cfgGroup->lastRun = *tsp; - *doLog = true; + if (mCfg->debug) { + mLog["t"] = "groupAufteilen"; + *doLog = true; + } - int32_t y = mCfg->groups[group].y; - int32_t y1 = mCfg->groups[group].y1; - int32_t y2 = mCfg->groups[group].y2; - int32_t y3 = mCfg->groups[group].y3; + int32_t y = cfgGroup->y; + int32_t y1 = cfgGroup->y1; + int32_t y2 = cfgGroup->y2; + int32_t y3 = cfgGroup->y3; -if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { - int32_t diff = mCfg->groups[group].power - mCfg->groups[group].powerMax; - y = y - diff; - y1 = y1 - (diff * y1 / y); - y1 = y1 - (diff * y2 / y); - y1 = y1 - (diff * y3 / y); -} + if (cfgGroup->power > cfgGroup->powerMax) { + int32_t diff = cfgGroup->power - cfgGroup->powerMax; + y = y - diff; + y1 = y1 - (diff * y1 / y); + y1 = y1 - (diff * y2 / y); + y1 = y1 - (diff * y3 / y); + } // TDOD: nochmal durchdenken ... es muss für Sum und L1-3 sein // uint16_t groupPmax = 0; @@ -1074,15 +1080,14 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { uint16_t ivPmax[7] = {0, 0, 0, 0, 0, 0, 0}; for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { - zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv]; + zeroExportGroupInverter_t *cfgGroupInv = &cfgGroup->inverters[inv]; - if (!cfgGroupInv->enabled) { - continue; - } + // Inverter not enabled or not selected -> ignore + if (NotEnabledOrNotSelected(group, inv)) continue; - record_t<> *rec; - rec = mIv[group][inv]->getRecordStruct(RealTimeRunData_Debug); - cfgGroupInv->power = mIv[group][inv]->getChannelFieldValue(CH0, FLD_PAC, rec); +/// record_t<> *rec; +/// rec = mIv[group][inv]->getRecordStruct(RealTimeRunData_Debug); +/// cfgGroupInv->power = mIv[group][inv]->getChannelFieldValue(CH0, FLD_PAC, rec); if ((cfgGroupInv->power < ivPmin[cfgGroupInv->target]) && (cfgGroupInv->limit < cfgGroupInv->powerMax) && (cfgGroupInv->limit < mIv[group][inv]->getMaxPower())) { grpTarget[cfgGroupInv->target] = true; @@ -1178,7 +1183,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { } /** groupSetReboot - * + * Sets the calculated Reboot to the Inverter and waits for ACK. * @param group * @param tsp * @param doLog @@ -1188,10 +1193,10 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; bool result = true; - if (mCfg->debug) mLog["t"] = "groupSetReboot"; - cfgGroup->lastRun = *tsp; + if (mCfg->debug) mLog["t"] = "groupSetReboot"; + JsonArray logArr = mLog.createNestedArray("ix"); for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { JsonObject logObj = logArr.createNestedObject(); @@ -1208,18 +1213,20 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { continue; } - logObj["dR"] = cfgGroupInv->doReboot; - logObj["wR"] = cfgGroupInv->waitRebootAck; + if (mCfg->debug) { + logObj["dR"] = cfgGroupInv->doReboot; + logObj["wR"] = cfgGroupInv->waitAckSetReboot; + } // Wait - if (cfgGroupInv->waitRebootAck > 0) { + if (cfgGroupInv->waitAckSetReboot > 0) { result = false; if (mCfg->debug) *doLog = true; continue; } // Reset - if ((cfgGroupInv->doReboot == 2) && (cfgGroupInv->waitRebootAck == 0)) { + if ((cfgGroupInv->doReboot == 2) && (cfgGroupInv->waitAckSetReboot == 0)) { cfgGroupInv->doReboot = -1; if (mCfg->debug) { logObj["act"] = "done"; @@ -1231,7 +1238,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { // Calculate if (cfgGroupInv->doReboot == 1) { cfgGroupInv->doReboot = 2; - cfgGroupInv->waitRebootAck = 120; + cfgGroupInv->waitAckSetReboot = 120; } // Inverter nothing to do -> ignore @@ -1246,13 +1253,14 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { result = false; *doLog = true; - // send Command + // send Command over RestAPI DynamicJsonDocument doc(512); JsonObject obj = doc.to(); obj["id"] = cfgGroupInv->id; obj["path"] = "ctrl"; obj["cmd"] = "restart"; mApi->ctrlRequest(obj); + if (mCfg->debug) logObj["d"] = obj; } @@ -1260,7 +1268,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { } /** groupSetPower - * + * Sets the calculated Power to the Inverter and waits for ACK. * @param group * @param tsp * @param doLog @@ -1270,10 +1278,10 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; bool result = true; - if (mCfg->debug) mLog["t"] = "groupSetPower"; - cfgGroup->lastRun = *tsp; + if (mCfg->debug) mLog["t"] = "groupSetPower"; + JsonArray logArr = mLog.createNestedArray("ix"); for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { JsonObject logObj = logArr.createNestedObject(); @@ -1290,18 +1298,20 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { continue; } - logObj["dP"] = cfgGroupInv->doPower; - logObj["wP"] = cfgGroupInv->waitPowerAck; + if (mCfg->debug) { + logObj["dP"] = cfgGroupInv->doPower; + logObj["wP"] = cfgGroupInv->waitAckSetPower; + } // Wait - if (cfgGroupInv->waitPowerAck > 0) { + if (cfgGroupInv->waitAckSetPower > 0) { result = false; if (mCfg->debug) *doLog = true; continue; } // Reset - if ((cfgGroupInv->doPower != -1) && (cfgGroupInv->waitPowerAck == 0)) { + if ((cfgGroupInv->doPower != -1) && (cfgGroupInv->waitAckSetPower == 0)) { cfgGroupInv->doPower = -1; if (mCfg->debug) { logObj["act"] = "done"; @@ -1320,7 +1330,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { (mIv[group][inv]->isProducing() == false)) { // On cfgGroupInv->doPower = 1; - cfgGroupInv->waitPowerAck = 120; + cfgGroupInv->waitAckSetPower = 120; logObj["act"] = "on"; } if ( @@ -1330,7 +1340,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { (mIv[group][inv]->isProducing() == true)) { // Off cfgGroupInv->doPower = 0; - cfgGroupInv->waitPowerAck = 120; + cfgGroupInv->waitAckSetPower = 120; logObj["act"] = "off"; } @@ -1346,7 +1356,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { result = false; *doLog = true; - // send Command + // send Command over RestAPI DynamicJsonDocument doc(512); JsonObject obj = doc.to(); obj["val"] = cfgGroupInv->doPower; @@ -1354,6 +1364,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { obj["path"] = "ctrl"; obj["cmd"] = "power"; mApi->ctrlRequest(obj); + if (mCfg->debug) logObj["d"] = obj; } @@ -1371,10 +1382,10 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; bool result = true; - if (mCfg->debug) mLog["t"] = "groupSetLimit"; - cfgGroup->lastRun = *tsp; + if (mCfg->debug) mLog["t"] = "groupSetLimit"; + JsonArray logArr = mLog.createNestedArray("ix"); for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) { JsonObject logObj = logArr.createNestedObject(); @@ -1391,19 +1402,21 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { continue; } - logObj["dL"] = cfgGroupInv->doLimit; - logObj["wL"] = cfgGroupInv->waitLimitAck; - logObj["L"] = cfgGroupInv->limit; + if (mCfg->debug) { + logObj["dL"] = cfgGroupInv->doLimit; + logObj["wL"] = cfgGroupInv->waitAckSetLimit; + logObj["L"] = cfgGroupInv->limit; + } // Wait - if (cfgGroupInv->waitLimitAck > 0) { + if (cfgGroupInv->waitAckSetLimit > 0) { result = false; if (mCfg->debug) *doLog = true; continue; } // Reset - if ((cfgGroupInv->doLimit != -1) && (cfgGroupInv->waitLimitAck == 0)) { + if ((cfgGroupInv->doLimit != -1) && (cfgGroupInv->waitAckSetLimit == 0)) { cfgGroupInv->doLimit = -1; if (mCfg->debug) { logObj["act"] = "done"; @@ -1431,11 +1444,6 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { cfgGroupInv->limitNew = power2proz; } - /// // Restriction Power + 10% < Limit - /// if ((cfgGroupInv->power + (power100proz * 10 / 100)) < cfgGroupInv->limit) { - /// cfgGroupInv->limitNew += (power100proz * 10 / 100); - /// } - // Restriction LimitNew > Pmax if (cfgGroupInv->limitNew > cfgGroupInv->powerMax) { cfgGroupInv->limitNew = cfgGroupInv->powerMax; @@ -1465,7 +1473,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { if (cfgGroupInv->limit != cfgGroupInv->limitNew) { cfgGroupInv->doLimit = 1; - cfgGroupInv->waitLimitAck = 60; + cfgGroupInv->waitAckSetLimit = 60; } cfgGroupInv->limit = cfgGroupInv->limitNew; @@ -1483,7 +1491,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { result = false; *doLog = true; - // send Command + // send Command over RestAPI DynamicJsonDocument doc(512); JsonObject obj = doc.to(); if (cfgGroupInv->limit > 0) { @@ -1495,39 +1503,42 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { obj["path"] = "ctrl"; obj["cmd"] = "limit_nonpersistent_absolute"; mApi->ctrlRequest(obj); + if (mCfg->debug) logObj["d"] = obj; } return result; } - void PubSubInit(String gr, String payload) - { + /** + * + */ + void PubSubInit(String gr, String payload) { mMqtt->publish(gr.c_str(), payload.c_str(), false); mMqtt->subscribe(gr.c_str(), QOS_2); } - void mqttInitTopic() - { + /** + * + */ + void mqttInitTopic() { if (mIsSubscribed) return; if (!mMqtt->isConnected()) return; mIsSubscribed = true; // Global (zeroExport) - // TODO: Global wird fälschlicherweise hier je nach anzahl der aktivierten Gruppen bis zu 6x ausgeführt. mMqtt->publish("zero/set/enabled", ((mCfg->enabled) ? dict[STR_TRUE] : dict[STR_FALSE]), false); mMqtt->subscribe("zero/set/enabled", QOS_2); - // TODO: Global wird fälschlicherweise hier je nach anzahl der aktivierten Gruppen bis zu 6x ausgeführt. + mMqtt->publish("zero/set/sleep", ((mCfg->sleep) ? dict[STR_TRUE] : dict[STR_FALSE]), false); mMqtt->subscribe("zero/set/sleep", QOS_2); - + // Gruppen String gr; - for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) - { + for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) { zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; - gr = "zero/set/groups/" + String(group); + gr = "zero/set/groups/" + String(group); // General PubSubInit(gr + "/enabled", ((cfgGroup->enabled) ? dict[STR_TRUE] : dict[STR_FALSE])); @@ -1553,6 +1564,7 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { PubSubInit(gr + "/advanced/powerMax", String(cfgGroup->powerMax)); } } + /** groupPublish * */ @@ -1564,7 +1576,6 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { cfgGroup->lastRun = *tsp; if (mMqtt->isConnected()) { - // *doLog = true; String gr; @@ -1623,23 +1634,24 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { } /** groupEmergency - * + * Dieser State versucht zeroExport in einen sicheren Zustand zu bringen, wenn technische Ausfälle vorliegen. * @param group + * @param *tsp + * @param *doLog * @returns true/false * @todo Hier ist noch keine Funktion */ bool groupEmergency(uint8_t group, unsigned long *tsp, bool *doLog) { zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; - if (mCfg->debug) mLog["t"] = "groupEmergency"; cfgGroup->lastRun = *tsp; - // *doLog = true; + if (mCfg->debug) { + mLog["t"] = "groupEmergency"; + *doLog = true; + } - // if (!korrect) { - // do - // return; - // } + // TODO: hier fehlt der Code return true; } @@ -1648,14 +1660,27 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { * Sendet den LogSpeicher über Webserial und/oder MQTT */ void sendLog(void) { + +//if (mLog["s"] == 1) return; +//if (mLog["s"] == 2) return; +//if (mLog["s"] == 3) return; +if (mLog["s"] == 4) return; +//if (mLog["s"] == 5) return; +//if (mLog["s"] == 6) return; +//if (mLog["s"] == 7) return; +//if (mLog["s"] == 8) return; +//if (mLog["s"] == 9) return; +//if (mLog["s"] == 10) return; + + // Log over Webserial if (mCfg->log_over_webserial) { - // DBGPRINTLN(String("ze: ") + mDocLog.as()); DPRINTLN(DBG_INFO, String("ze: ") + mDocLog.as()); } + // Log over MQTT if (mCfg->log_over_mqtt) { if (mMqtt->isConnected()) { - mMqtt->publish("ze", mDocLog.as().c_str(), false); + mMqtt->publish("zero/log", mDocLog.as().c_str(), false); } } } @@ -1669,20 +1694,23 @@ if (mCfg->groups[group].power > mCfg->groups[group].powerMax) { // private member variables bool mIsInitialized = false; + zeroExport_t *mCfg; settings_t *mConfig; HMSYSTEM *mSys; RestApiType *mApi; + StaticJsonDocument<5000> mDocLog; JsonObject mLog = mDocLog.to(); - PubMqttType *mMqtt; - powermeter mPowermeter; - bool mIsSubscribed = false; - - StaticJsonDocument<512> mqttDoc; //DynamicJsonDocument mqttDoc(512); - JsonObject mqttObj = mqttDoc.to(); Inverter<> *mIv[ZEROEXPORT_MAX_GROUPS][ZEROEXPORT_GROUP_MAX_INVERTERS]; + + powermeter mPowermeter; + + PubMqttType *mMqtt; + bool mIsSubscribed = false; + StaticJsonDocument<512> mqttDoc; // DynamicJsonDocument mqttDoc(512); + JsonObject mqttObj = mqttDoc.to(); }; #endif /*__ZEROEXPORT__*/