diff --git a/src/CHANGES.md b/src/CHANGES.md index 2e31c0e1..1392b1ac 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,11 @@ (starting from release version `0.5.66`) +## 0.5.82 +* fixed communication error #652 +* reset values is no bound to MQTT any more, setting moved to `inverter` #649 +* fixed wording on `index.hmtl` #661 + ## 0.5.81 * started implementation of MI inverters (setup.html, own processing `MiPayload.h`) diff --git a/src/app.cpp b/src/app.cpp index d64eefdb..ea3b4a2a 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -95,7 +95,7 @@ void app::loopStandard(void) { mStat.frmCnt++; Inverter<> *iv = mSys.findInverter(&p->packet[1]); - if(NULL == iv) { + if(NULL != iv) { if(IV_HM == iv->ivGen) mPayload.add(iv, p); else @@ -161,13 +161,15 @@ void app::tickNtpUpdate(void) { mMqtt.connect(); everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS"); everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM"); - if(mConfig->mqtt.rstYieldMidNight) { - uint32_t midTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight - onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); - } mMqttReconnect = false; } + everyMin(std::bind(&app::tickMinute, this), "tMin"); + if(mConfig->inst.rstYieldMidNight) { + uint32_t midTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight + onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); + } + nxtTrig = isOK ? 43200 : 60; // depending on NTP update success check again in 12 h or in 1 min if((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) { @@ -212,8 +214,7 @@ void app::tickIVCommunication(void) { if (nxtTrig != 0) onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); } - if (mMqttEnabled) - tickComm(); + tickComm(); } //----------------------------------------------------------------------------- @@ -225,18 +226,59 @@ void app::tickSun(void) { //----------------------------------------------------------------------------- void app::tickComm(void) { - // only used and enabled by MQTT (see setup()) - if (!mMqtt.tickerComm(!mIVCommunicationOn)) - once(std::bind(&app::tickComm, this), 1, "mqCom"); // MQTT not connected, retry + if(!mIVCommunicationOn && (mConfig->inst.rstValsCommStop)) { + Inverter<> *iv; + // set values to zero, except yields + for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { + iv = mSys.getInverterByPos(id); + if (NULL == iv) + continue; // skip to next inverter + + mPayload.zeroInverterValues(iv); + } + } + + if (mMqttEnabled) { + if (!mMqtt.tickerComm(!mIVCommunicationOn)) + once(std::bind(&app::tickComm, this), 5, "mqCom"); // MQTT not connected, retry after 5s + } +} + +//----------------------------------------------------------------------------- +void app::tickMinute(void) { + if(mConfig->inst.rstValsNotAvail) { + Inverter<> *iv; + // set values to zero, except yields + for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { + iv = mSys.getInverterByPos(id); + if (NULL == iv) + continue; // skip to next inverter + + if(!iv->isAvailable(mTimestamp) && !iv->isProducing(mTimestamp) && iv->config->enabled) + mPayload.zeroInverterValues(iv); + } + } } //----------------------------------------------------------------------------- void app::tickMidnight(void) { - // only used and enabled by MQTT (see setup()) + // only triggered if 'reset values at midnight is enabled' uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "mid2"); - mMqtt.tickerMidnight(); + Inverter<> *iv; + // set values to zero, except yield total + for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { + iv = mSys.getInverterByPos(id); + if (NULL == iv) + continue; // skip to next inverter + + mPayload.zeroInverterValues(iv); + mPayload.zeroYieldDay(iv); + } + + if (mMqttEnabled) + mMqtt.tickerMidnight(); } //----------------------------------------------------------------------------- diff --git a/src/app.h b/src/app.h index 7e9499b7..47990928 100644 --- a/src/app.h +++ b/src/app.h @@ -222,6 +222,7 @@ class app : public IApp, public ah::Scheduler { void tickSun(void); void tickComm(void); void tickSend(void); + void tickMinute(void); void tickMidnight(void); /*void tickSerial(void) { if(Serial.available() == 0) diff --git a/src/config/settings.h b/src/config/settings.h index 4a922962..d54bbf4e 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -98,9 +98,6 @@ typedef struct { char pwd[MQTT_PWD_LEN]; char topic[MQTT_TOPIC_LEN]; uint16_t interval; - bool rstYieldMidNight; - bool rstValsNotAvail; - bool rstValsCommStop; } cfgMqtt_t; typedef struct { @@ -115,6 +112,10 @@ typedef struct { typedef struct { bool enabled; cfgIv_t iv[MAX_NUM_INVERTERS]; + + bool rstYieldMidNight; + bool rstValsNotAvail; + bool rstValsCommStop; } cfgInst_t; typedef struct { @@ -328,9 +329,10 @@ class settings { snprintf(mCfg.mqtt.pwd, MQTT_PWD_LEN, "%s", DEF_MQTT_PWD); snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC); mCfg.mqtt.interval = 0; // off - mCfg.mqtt.rstYieldMidNight = false; - mCfg.mqtt.rstValsNotAvail = false; - mCfg.mqtt.rstValsCommStop = false; + + mCfg.inst.rstYieldMidNight = false; + mCfg.inst.rstValsNotAvail = false; + mCfg.inst.rstValsCommStop = false; mCfg.led.led0 = DEF_PIN_OFF; mCfg.led.led1 = DEF_PIN_OFF; @@ -439,16 +441,10 @@ class settings { obj[F("pwd")] = mCfg.mqtt.pwd; obj[F("topic")] = mCfg.mqtt.topic; obj[F("intvl")] = mCfg.mqtt.interval; - obj[F("rstMidNight")] = (bool)mCfg.mqtt.rstYieldMidNight; - obj[F("rstNotAvail")] = (bool)mCfg.mqtt.rstValsNotAvail; - obj[F("rstComStop")] = (bool)mCfg.mqtt.rstValsCommStop; } else { mCfg.mqtt.port = obj[F("port")]; mCfg.mqtt.interval = obj[F("intvl")]; - mCfg.mqtt.rstYieldMidNight = (bool)obj["rstMidNight"]; - mCfg.mqtt.rstValsNotAvail = (bool)obj["rstNotAvail"]; - mCfg.mqtt.rstValsCommStop = (bool)obj["rstComStop"]; snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", obj[F("broker")].as()); snprintf(mCfg.mqtt.user, MQTT_USER_LEN, "%s", obj[F("user")].as()); snprintf(mCfg.mqtt.pwd, MQTT_PWD_LEN, "%s", obj[F("pwd")].as()); @@ -495,10 +491,18 @@ class settings { } void jsonInst(JsonObject obj, bool set = false) { - if(set) + if(set) { obj[F("en")] = (bool)mCfg.inst.enabled; - else + obj[F("rstMidNight")] = (bool)mCfg.inst.rstYieldMidNight; + obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail; + obj[F("rstComStop")] = (bool)mCfg.inst.rstValsCommStop; + } + else { mCfg.inst.enabled = (bool)obj[F("en")]; + mCfg.inst.rstYieldMidNight = (bool)obj["rstMidNight"]; + mCfg.inst.rstValsNotAvail = (bool)obj["rstNotAvail"]; + mCfg.inst.rstValsCommStop = (bool)obj["rstComStop"]; + } JsonArray ivArr; if(set) diff --git a/src/defines.h b/src/defines.h index cf16e86b..af32bc15 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 81 +#define VERSION_PATCH 82 //------------------------------------- typedef struct { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index a85f24e3..ab9a8e32 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -70,6 +70,41 @@ class HmPayload { } } + void zeroYieldDay(Inverter<> *iv) { + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + uint8_t pos = iv->getPosByChFld(CH0, FLD_YD, rec); + iv->setValue(pos, rec, 0.0f); + } + + void zeroInverterValues(Inverter<> *iv) { + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + for(uint8_t ch = 0; ch <= iv->channels; ch++) { + uint8_t pos = 0; + uint8_t fld = 0; + while(0xff != pos) { + switch(fld) { + case FLD_YD: + case FLD_YT: + case FLD_FW_VERSION: + case FLD_FW_BUILD_YEAR: + case FLD_FW_BUILD_MONTH_DAY: + case FLD_FW_BUILD_HOUR_MINUTE: + case FLD_HW_ID: + case FLD_ACT_ACTIVE_PWR_LIMIT: + fld++; + continue; + break; + } + pos = iv->getPosByChFld(ch, fld, rec); + iv->setValue(pos, rec, 0.0f); + fld++; + } + } + + iv->doCalculations(); + notify(RealTimeRunData_Debug); + } + void ivSendHighPrio(Inverter<> *iv) { mHighPrioIv = iv; } @@ -169,6 +204,9 @@ class HmPayload { if (NULL == iv) continue; // skip to next inverter + if (IV_MI == iv->ivGen) // only process HM inverters + continue; // skip to next inverter + if ((mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && (0 != mPayload[iv->id].txId)) { // no processing needed if txId is not 0x95 mPayload[iv->id].complete = true; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 5a6edb0e..790fca3d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -291,16 +291,17 @@ class HmRadio { mTxBuf[len++] = (crc ) & 0xff; } // crc over all - mTxBuf[len+1] = ah::crc8(mTxBuf, len); + mTxBuf[len] = ah::crc8(mTxBuf, len); + len++; if(mSerialDebug) { - DPRINT(DBG_INFO, "TX " + String(len+1) + "B Ch" + String(mRfChLst[mTxChIdx]) + " | "); - dumpBuf(mTxBuf, len+1); + DPRINT(DBG_INFO, "TX " + String(len) + "B Ch" + String(mRfChLst[mTxChIdx]) + " | "); + dumpBuf(mTxBuf, len); } mNrf24.setChannel(mRfChLst[mTxChIdx]); mNrf24.openWritingPipe(reinterpret_cast(&invId)); - mNrf24.startWrite(mTxBuf, len+1, false); // false = request ACK response + mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response // switch TX channel for next packet if(++mTxChIdx >= RF_CHANNELS) @@ -316,7 +317,6 @@ class HmRadio { uint64_t DTU_RADIO_ID; uint8_t mRfChLst[RF_CHANNELS]; - uint8_t mTxChIdx; uint8_t mRxChIdx; diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index f578652c..bce671a6 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -126,6 +126,9 @@ class MiPayload { if (NULL == iv) continue; // skip to next inverter + if (IV_HM == iv->ivGen) // only process MI inverters + continue; // skip to next inverter + /*if ((mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && (0 != mPayload[iv->id].txId)) { // no processing needed if txId is not 0x95 mPayload[iv->id].complete = true; diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 213ebd0a..47b62353 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -123,34 +123,17 @@ class PubMqtt { publish("comm_disabled", ((disabled) ? "true" : "false"), true); publish("comm_dis_ts", String(*mUtcTimestamp).c_str(), true); - if(disabled && (mCfgMqtt->rstValsCommStop)) - zeroAllInverters(); - return true; } void tickerMidnight() { - Inverter<> *iv; - record_t<> *rec; char topic[7 + MQTT_TOPIC_LEN], val[4]; - // set YieldDay to zero - for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { - iv = mSys->getInverterByPos(id); - if (NULL == iv) - continue; // skip to next inverter - rec = iv->getRecordStruct(RealTimeRunData_Debug); - uint8_t pos = iv->getPosByChFld(CH0, FLD_YD, rec); - iv->setValue(pos, rec, 0.0f); - - snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch0/%s", iv->config->name, fields[FLD_YD]); - snprintf(val, 2, "0"); - publish(topic, val, true); - } // set Total YieldDay to zero snprintf(topic, 32 + MAX_NAME_LENGTH, "total/%s", fields[FLD_YD]); snprintf(val, 2, "0"); - publish(topic, val, true); } + publish(topic, val, true); + } void payloadEventListener(uint8_t cmd) { if(mClient.connected()) { // prevent overflow if MQTT broker is not reachable but set @@ -455,9 +438,6 @@ class PubMqtt { mLastIvState[id] = status; changed = true; - if((MQTT_STATUS_NOT_AVAIL_NOT_PROD == status) && (mCfgMqtt->rstValsNotAvail)) - zeroValues(iv); - snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->config->name); snprintf(val, 40, "%d", status); publish(topic, val, true); @@ -582,48 +562,6 @@ class PubMqtt { } } - void zeroAllInverters() { - Inverter<> *iv; - - // set values to zero, exept yields - for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { - iv = mSys->getInverterByPos(id); - if (NULL == iv) - continue; // skip to next inverter - - zeroValues(iv); - } - sendIvData(); - } - - void zeroValues(Inverter<> *iv) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - for(uint8_t ch = 0; ch <= iv->channels; ch++) { - uint8_t pos = 0; - uint8_t fld = 0; - while(0xff != pos) { - switch(fld) { - case FLD_YD: - case FLD_YT: - case FLD_FW_VERSION: - case FLD_FW_BUILD_YEAR: - case FLD_FW_BUILD_MONTH_DAY: - case FLD_FW_BUILD_HOUR_MINUTE: - case FLD_HW_ID: - case FLD_ACT_ACTIVE_PWR_LIMIT: - fld++; - continue; - break; - } - pos = iv->getPosByChFld(ch, fld, rec); - iv->setValue(pos, rec, 0.0f); - fld++; - } - } - - mSendList.push(RealTimeRunData_Debug); - } - espMqttClient mClient; cfgMqtt_t *mCfgMqtt; #if defined(ESP8266) diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 43d53500..36cf1357 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -298,6 +298,9 @@ class RestApi { obj[F("interval")] = String(mConfig->nrf.sendInterval); obj[F("retries")] = String(mConfig->nrf.maxRetransPerPyld); obj[F("max_num_inverters")] = MAX_NUM_INVERTERS; + obj[F("rstMid")] = (bool)mConfig->inst.rstYieldMidNight; + obj[F("rstNAvail")] = (bool)mConfig->inst.rstValsNotAvail; + obj[F("rstComStop")] = (bool)mConfig->inst.rstValsCommStop; } void getMqtt(JsonObject obj) { @@ -307,9 +310,6 @@ class RestApi { obj[F("pwd")] = (strlen(mConfig->mqtt.pwd) > 0) ? F("{PWD}") : String(""); obj[F("topic")] = String(mConfig->mqtt.topic); obj[F("interval")] = String(mConfig->mqtt.interval); - obj[F("rstMid")] = (bool)mConfig->mqtt.rstYieldMidNight; - obj[F("rstNAvail")] = (bool)mConfig->mqtt.rstValsNotAvail; - obj[F("rstComStop")] = (bool)mConfig->mqtt.rstValsCommStop; } void getNtp(JsonObject obj) { diff --git a/src/web/html/index.html b/src/web/html/index.html index 0e71fcf7..cb16ddc9 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -173,6 +173,10 @@ color = "#00d"; avail = "not yet available"; } + else if(0 == i["ts_last_success"]) { + icon = iconSuccess; + avail = "available but no data was received until now"; + } else { icon = iconSuccess; avail = "available and is "; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 8db3e687..58c3153e 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -95,6 +95,13 @@ + + +
+ +
+ +
@@ -146,12 +153,6 @@ - -
- -
- -

Send Inverter data in a fixed interval, even if there is no change. A value of '0' disables the fixed interval. The data is published once it was successfully received from inverter. (default: 0)

@@ -453,6 +454,8 @@ function ivGlob(obj) { for(var i of [["invInterval", "interval"], ["invRetry", "retries"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; + for(var i of [["Mid", "rstMid"], ["ComStop", "rstComStop"], ["NotAvail", "rstNAvail"]]) + document.getElementsByName("invRst"+i[0])[0].checked = obj[i[1]]; } function parseSys(obj) { @@ -496,9 +499,6 @@ function parseMqtt(obj) { for(var i of [["Addr", "broker"], ["Port", "port"], ["User", "user"], ["Pwd", "pwd"], ["Topic", "topic"], ["Interval", "interval"]]) document.getElementsByName("mqtt"+i[0])[0].value = obj[i[1]]; - - for(var i of [["Mid", "rstMid"], ["ComStop", "rstNAvail"], ["NotAvail", "rstComStop"]]) - document.getElementsByName("mqttRst"+i[0])[0].checked = obj[i[1]]; } function parseNtp(obj) { diff --git a/src/web/web.h b/src/web/web.h index 887f65aa..bbe97a30 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -500,6 +500,9 @@ class Web { mConfig->nrf.sendInterval = request->arg("invInterval").toInt(); if(request->arg("invRetry") != "") mConfig->nrf.maxRetransPerPyld = request->arg("invRetry").toInt(); + mConfig->inst.rstYieldMidNight = (request->arg("invRstMid") == "on"); + mConfig->inst.rstValsCommStop = (request->arg("invRstComStop") == "on"); + mConfig->inst.rstValsNotAvail = (request->arg("invRstNotAvail") == "on"); // pinout uint8_t pin; @@ -550,9 +553,6 @@ class Web { request->arg("mqttTopic").toCharArray(mConfig->mqtt.topic, MQTT_TOPIC_LEN); mConfig->mqtt.port = request->arg("mqttPort").toInt(); mConfig->mqtt.interval = request->arg("mqttInterval").toInt(); - mConfig->mqtt.rstYieldMidNight = (request->arg("mqttRstMid") == "on"); - mConfig->mqtt.rstValsCommStop = (request->arg("mqttRstComStop") == "on"); - mConfig->mqtt.rstValsNotAvail = (request->arg("mqttRstNotAvail") == "on"); // serial console if(request->arg("serIntvl") != "") {