From b69ab066378412fc3bb17dce2b13f090861b9fe9 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 13 Feb 2023 22:14:17 +0100 Subject: [PATCH] MQTT Yield Day zero, next try to fix #671, thx @beegee3 added Solenso inverter to supported devices improved reconnection of MQTT #650 --- src/CHANGES.md | 5 ++ src/app.h | 3 +- src/publisher/pubMqtt.h | 183 +++++++++++++++++++++++----------------- 3 files changed, 111 insertions(+), 80 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 9274d8aa..3b810e1d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,11 @@ (starting from release version `0.5.66`) +## 0.5.88 +* MQTT Yield Day zero, next try to fix #671, thx @beegee3 +* added Solenso inverter to supported devices +* improved reconnection of MQTT #650 + ## 0.5.87 * fix yield total correction as module (inverter input) value #570 * reneabled instant start communication (once NTP is synced) #674 diff --git a/src/app.h b/src/app.h index b449a9a3..15dbf8f7 100644 --- a/src/app.h +++ b/src/app.h @@ -198,7 +198,8 @@ class app : public IApp, public ah::Scheduler { void payloadEventListener(uint8_t cmd) { #if !defined(AP_ONLY) - mMqtt.payloadEventListener(cmd); + if (mMqttEnabled) + mMqtt.payloadEventListener(cmd); #endif if(mConfig->plugin.display.type != 0) mMonoDisplay.payloadEventListener(cmd); diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 03304ab0..9ea674e8 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -40,6 +40,7 @@ class PubMqtt { mTxCnt = 0; mSubscriptionCb = NULL; memset(mLastIvState, MQTT_STATUS_NOT_AVAIL_NOT_PROD, MAX_NUM_INVERTERS); + mLastAnyAvail = false; } ~PubMqtt() { } @@ -51,7 +52,6 @@ class PubMqtt { mSys = sys; mUtcTimestamp = utcTs; mIntervalTimeout = 1; - mReconnectRequest = false; snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic); @@ -73,29 +73,31 @@ class PubMqtt { } inline void connect() { - mReconnectRequest = false; if(!mClient.connected()) mClient.connect(); } void tickerSecond() { + if (mIntervalTimeout > 0) + mIntervalTimeout--; + + if(!mClient.connected()) { + mClient.connect(); + return; // next try in a second + } + if(0 == mCfgMqtt->interval) // no fixed interval, publish once new data were received (from inverter) sendIvData(); else { // send mqtt data in a fixed interval - if(--mIntervalTimeout == 0) { + if(mIntervalTimeout == 0) { mIntervalTimeout = mCfgMqtt->interval; mSendList.push(RealTimeRunData_Debug); sendIvData(); } } - if(mReconnectRequest) { - connect(); - return; - } } void tickerMinute() { - processIvStatus(); char val[12]; snprintf(val, 12, "%ld", millis() / 1000); publish("uptime", val); @@ -317,7 +319,6 @@ class PubMqtt { switch (reason) { case espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED: DBGPRINTLN(F("TCP disconnect")); - mReconnectRequest = true; break; case espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION: DBGPRINTLN(F("wrong protocol version")); @@ -414,7 +415,7 @@ class PubMqtt { } bool processIvStatus() { - // returns true if all inverters are available + // returns true if any inverter is available bool allAvail = true; // shows if all enabled inverters are available bool anyAvail = false; // shows if at least one enabled inverter is available bool changed = false; @@ -439,6 +440,10 @@ class PubMqtt { } if(mLastIvState[id] != status) { + // if status changed from producing to not producing send last data immediately + if (MQTT_STATUS_AVAIL_PROD == mLastIvState[id]) + sendData(iv, RealTimeRunData_Debug); + mLastIvState[id] = status; changed = true; @@ -455,10 +460,9 @@ class PubMqtt { if(changed) { snprintf(val, 32, "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); publish("status", val, true); - //sendIvData(false); // false prevents loop of same function } - return allAvail; + return anyAvail; } void sendAlarmData() { @@ -474,93 +478,114 @@ class PubMqtt { } } + void sendData(Inverter<> *iv, uint8_t curInfoCmd) { + char topic[7 + MQTT_TOPIC_LEN], val[40]; + record_t<> *rec = iv->getRecordStruct(curInfoCmd); + + for (uint8_t i = 0; i < rec->length; i++) { + bool retained = false; + if (curInfoCmd == RealTimeRunData_Debug) { + switch (rec->assign[i].fieldId) { + case FLD_YT: + case FLD_YD: + if ((rec->assign[i].ch == CH0) && (!iv->isProducing(*mUtcTimestamp))) // avoids returns to 0 on restart + continue; + retained = true; + break; + } + } + + snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); + snprintf(val, 40, "%g", ah::round3(iv->getValue(i, rec))); + publish(topic, val, retained); + + yield(); + } + } + void sendIvData() { + bool anyAvail = processIvStatus(); + if (mLastAnyAvail != anyAvail) + mSendList.push(RealTimeRunData_Debug); // makes shure that total values are calculated + if(mSendList.empty()) return; char topic[7 + MQTT_TOPIC_LEN], val[40]; float total[4]; - bool sendTotal = false; + bool RTRDataHasBeenSent = false; while(!mSendList.empty()) { memset(total, 0, sizeof(float) * 4); - for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { - Inverter<> *iv = mSys->getInverterByPos(id); - if ((NULL == iv) || (MQTT_STATUS_NOT_AVAIL_NOT_PROD == mLastIvState[id])) - continue; // skip to next inverter - - record_t<> *rec = iv->getRecordStruct(mSendList.front()); - - // data - //if(iv->isAvailable(*mUtcTimestamp, rec) || (0 != mCfgMqtt->interval)) { // is avail or fixed pulish interval was set - for (uint8_t i = 0; i < rec->length; i++) { - bool retained = false; - if (mSendList.front() == RealTimeRunData_Debug) { - switch (rec->assign[i].fieldId) { - case FLD_YT: - case FLD_YD: - if ((rec->assign[i].ch == CH0) && (!iv->isProducing(*mUtcTimestamp))) // avoids returns to 0 on restart - continue; - retained = true; - break; - } - } + uint8_t curInfoCmd = mSendList.front(); - snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); - snprintf(val, 40, "%g", ah::round3(iv->getValue(i, rec))); - publish(topic, val, retained); + if ((curInfoCmd != RealTimeRunData_Debug) || !RTRDataHasBeenSent) { // send RTR Data only once + for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { + Inverter<> *iv = mSys->getInverterByPos(id); + if (NULL == iv) + continue; // skip to next inverter + + // send RTR Data only if status is available + if ((curInfoCmd != RealTimeRunData_Debug) || (MQTT_STATUS_AVAIL_PROD == mLastIvState[id])) + sendData(iv, curInfoCmd); // calculate total values for RealTimeRunData_Debug - if (mSendList.front() == RealTimeRunData_Debug) { - if (CH0 == rec->assign[i].ch) { - switch (rec->assign[i].fieldId) { - case FLD_PAC: - total[0] += iv->getValue(i, rec); - break; - case FLD_YT: - total[1] += iv->getValue(i, rec); - break; - case FLD_YD: - total[2] += iv->getValue(i, rec); - break; - case FLD_PDC: - total[3] += iv->getValue(i, rec); - break; + if (curInfoCmd == RealTimeRunData_Debug) { + record_t<> *rec = iv->getRecordStruct(curInfoCmd); + + for (uint8_t i = 0; i < rec->length; i++) { + if (CH0 == rec->assign[i].ch) { + switch (rec->assign[i].fieldId) { + case FLD_PAC: + total[0] += iv->getValue(i, rec); + break; + case FLD_YT: + total[1] += iv->getValue(i, rec); + break; + case FLD_YD: + total[2] += iv->getValue(i, rec); + break; + case FLD_PDC: + total[3] += iv->getValue(i, rec); + break; + } } - sendTotal = true; } + yield(); } - yield(); } - //} - } - - mSendList.pop(); // remove from list once all inverters were processed - if ((true == sendTotal) && processIvStatus()) { - uint8_t fieldId; - for (uint8_t i = 0; i < 4; i++) { - switch (i) { - default: - case 0: - fieldId = FLD_PAC; - break; - case 1: - fieldId = FLD_YT; - break; - case 2: - fieldId = FLD_YD; - break; - case 3: - fieldId = FLD_PDC; - break; + if (curInfoCmd == RealTimeRunData_Debug) { + uint8_t fieldId; + for (uint8_t i = 0; i < 4; i++) { + switch (i) { + default: + case 0: + fieldId = FLD_PAC; + break; + case 1: + fieldId = FLD_YT; + break; + case 2: + fieldId = FLD_YD; + break; + case 3: + fieldId = FLD_PDC; + break; + } + snprintf(topic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); + snprintf(val, 40, "%g", ah::round3(total[i])); + publish(topic, val, true); } - snprintf(topic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); - snprintf(val, 40, "%g", ah::round3(total[i])); - publish(topic, val, true); + RTRDataHasBeenSent = true; + yield(); } } + + mSendList.pop(); // remove from list once all inverters were processed } + + mLastAnyAvail = anyAvail; } espMqttClient mClient; @@ -575,7 +600,7 @@ class PubMqtt { std::queue mSendList; std::queue mAlarmList; subscriptionCb mSubscriptionCb; - bool mReconnectRequest; + bool mLastAnyAvail; uint8_t mLastIvState[MAX_NUM_INVERTERS]; uint16_t mIntervalTimeout;