Browse Source

fixed communication error #652

reset values is no bound to MQTT any more, setting moved to `inverter` #649
fixed wording on `index.hmtl` #661
pull/664/head
lumapu 2 years ago
parent
commit
5765e054f3
  1. 5
      src/CHANGES.md
  2. 66
      src/app.cpp
  3. 1
      src/app.h
  4. 32
      src/config/settings.h
  5. 2
      src/defines.h
  6. 38
      src/hm/hmPayload.h
  7. 10
      src/hm/hmRadio.h
  8. 3
      src/hm/miPayload.h
  9. 66
      src/publisher/pubMqtt.h
  10. 6
      src/web/RestApi.h
  11. 4
      src/web/html/index.html
  12. 18
      src/web/html/setup.html
  13. 6
      src/web/web.h

5
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`)

66
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();
}
//-----------------------------------------------------------------------------

1
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)

32
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<const char*>());
snprintf(mCfg.mqtt.user, MQTT_USER_LEN, "%s", obj[F("user")].as<const char*>());
snprintf(mCfg.mqtt.pwd, MQTT_PWD_LEN, "%s", obj[F("pwd")].as<const char*>());
@ -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)

2
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 {

38
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;

10
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<uint8_t*>(&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;

3
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;

66
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)

6
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) {

4
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 ";

18
src/web/html/setup.html

@ -95,6 +95,13 @@
<input type="text" class="text" name="invInterval" pattern="[0-9]+" title="Invalid input"/>
<label for="invRetry">Max retries per Payload</label>
<input type="text" class="text" name="invRetry"/>
<label for="invRstMid">Reset Values and YieldDay at Midnight</label>
<input type="checkbox" class="cb" name="invRstMid"/><br/>
<label for="invRstComStop">Reset Values at Communication stop</label>
<input type="checkbox" class="cb" name="invRstComStop"/><br/>
<label for="invRstNotAvail">Reset Values on 'not available'</label>
<input type="checkbox" class="cb" name="invRstNotAvail"/><br/>
</fieldset>
</div>
@ -146,12 +153,6 @@
<input type="password" class="text" name="mqttPwd"/>
<label for="mqttTopic">Topic</label>
<input type="text" class="text" name="mqttTopic" pattern="[A-Za-z0-9./#$%&=+_-]+" title="Invalid input" />
<label for="mqttRstMid">Reset YieldDay at Midnight</label>
<input type="checkbox" class="cb" name="mqttRstMid"/><br/>
<label for="mqttRstComStop">Reset Values at Communication stop</label>
<input type="checkbox" class="cb" name="mqttRstComStop"/><br/>
<label for="mqttRstNotAvail">Reset Values on 'not available'</label>
<input type="checkbox" class="cb" name="mqttRstNotAvail"/><br/>
<p class="des">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)</p>
<label for="mqttIntvl">Interval [s]</label>
<input type="text" class="text" name="mqttInterval" pattern="[0-9]+" title="Invalid input" />
@ -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) {

6
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") != "") {

Loading…
Cancel
Save