Browse Source

fix power-limit was not checked for max retransmits #667

fix blue LED lights up all the time #672
fix installing schedulers if NTP server isn't available
improved zero values on triggers #671
hardcoded MQTT subtopics, because wildcard `#` leads to errors
rephrased some messages on webif, thx to @Argafal #638
pull/698/head
lumapu 2 years ago
parent
commit
026df8a09b
  1. 8
      src/CHANGES.md
  2. 44
      src/app.cpp
  3. 1
      src/app.h
  4. 2
      src/defines.h
  5. 41
      src/hm/hmPayload.h
  6. 5
      src/hm/hmRadio.h
  7. 11
      src/publisher/pubMqtt.h
  8. 6
      src/web/html/index.html
  9. 11
      src/web/html/setup.html
  10. 3
      src/web/html/style.css

8
src/CHANGES.md

@ -2,6 +2,14 @@
(starting from release version `0.5.66`) (starting from release version `0.5.66`)
## 0.5.85
* fix power-limit was not checked for max retransmits #667
* fix blue LED lights up all the time #672
* fix installing schedulers if NTP server isn't available
* improved zero values on triggers #671
* hardcoded MQTT subtopics, because wildcard `#` leads to errors
* rephrased some messages on webif, thx to @Argafal #638
## 0.5.84 ## 0.5.84
* fix blue LED lights up all the time #672 * fix blue LED lights up all the time #672
* added an instant start communication (once NTP is synced) * added an instant start communication (once NTP is synced)

44
src/app.cpp

@ -161,14 +161,16 @@ void app::tickNtpUpdate(void) {
mMqtt.connect(); mMqtt.connect();
everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS"); everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS");
everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM"); everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM");
mMqttReconnect = false;
} }
if(mConfig->inst.rstValsNotAvail) // only install schedulers once even if NTP wasn't successful in first loop
everyMin(std::bind(&app::tickMinute, this), "tMin"); if(mMqttReconnect) { // @TODO: mMqttReconnect is wrong name here
if(mConfig->inst.rstYieldMidNight) { if(mConfig->inst.rstValsNotAvail)
uint32_t midTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight everyMin(std::bind(&app::tickMinute, this), "tMin");
onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); 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 nxtTrig = isOK ? 43200 : 60; // depending on NTP update success check again in 12 h or in 1 min
@ -183,6 +185,8 @@ void app::tickNtpUpdate(void) {
mSendFirst = false; mSendFirst = false;
once(std::bind(&app::tickSend, this), 2, "senOn"); once(std::bind(&app::tickSend, this), 2, "senOn");
} }
mMqttReconnect = false;
} }
once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp"); once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp");
} }
@ -233,17 +237,8 @@ void app::tickSun(void) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::tickComm(void) { void app::tickComm(void) {
if(!mIVCommunicationOn && (mConfig->inst.rstValsCommStop)) { if((!mIVCommunicationOn) && (mConfig->inst.rstValsCommStop))
Inverter<> *iv; once(std::bind(&app::tickZeroValues, this), mConfig->nrf.sendInterval, "tZero");
// 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 (mMqttEnabled) {
if (!mMqtt.tickerComm(!mIVCommunicationOn)) if (!mMqtt.tickerComm(!mIVCommunicationOn))
@ -251,6 +246,19 @@ void app::tickComm(void) {
} }
} }
//-----------------------------------------------------------------------------
void app::tickZeroValues(void) {
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);
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::tickMinute(void) { void app::tickMinute(void) {
// only triggered if 'reset values on no avail is enabled' // only triggered if 'reset values on no avail is enabled'
@ -273,6 +281,8 @@ void app::tickMidnight(void) {
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight
onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "mid2"); onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "mid2");
DPRINTLN(DBG_INFO, "tickMidnight " + String(nxtTrig));
Inverter<> *iv; Inverter<> *iv;
// set values to zero, except yield total // set values to zero, except yield total
for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { for (uint8_t id = 0; id < mSys.getNumInverters(); id++) {

1
src/app.h

@ -223,6 +223,7 @@ class app : public IApp, public ah::Scheduler {
void tickComm(void); void tickComm(void);
void tickSend(void); void tickSend(void);
void tickMinute(void); void tickMinute(void);
void tickZeroValues(void);
void tickMidnight(void); void tickMidnight(void);
/*void tickSerial(void) { /*void tickSerial(void) {
if(Serial.available() == 0) if(Serial.available() == 0)

2
src/defines.h

@ -13,7 +13,7 @@
//------------------------------------- //-------------------------------------
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 5 #define VERSION_MINOR 5
#define VERSION_PATCH 84 #define VERSION_PATCH 85
//------------------------------------- //-------------------------------------
typedef struct { typedef struct {

41
src/hm/hmPayload.h

@ -71,36 +71,31 @@ class HmPayload {
} }
void zeroYieldDay(Inverter<> *iv) { void zeroYieldDay(Inverter<> *iv) {
DPRINTLN(DBG_INFO, "zeroYieldDay");
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
uint8_t pos = iv->getPosByChFld(CH0, FLD_YD, rec); uint8_t pos;
iv->setValue(pos, rec, 0.0f); for(uint8_t ch = 0; ch < iv->channels; ch++) {
pos = iv->getPosByChFld(CH0, FLD_YD, rec);
iv->setValue(pos, rec, 0.0f);
}
} }
void zeroInverterValues(Inverter<> *iv) { void zeroInverterValues(Inverter<> *iv) {
DPRINTLN(DBG_INFO, "zeroInverterValues");
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
for(uint8_t ch = 0; ch <= iv->channels; ch++) { for(uint8_t ch = 0; ch <= iv->channels; ch++) {
uint8_t pos = 0; uint8_t pos = 0;
uint8_t fld = 0; for(uint8_t fld = 0; fld < FLD_EVT; fld++) {
while(0xff != pos) {
switch(fld) { switch(fld) {
case FLD_YD: case FLD_YD:
case FLD_YT: 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; continue;
} }
pos = iv->getPosByChFld(ch, fld, rec); pos = iv->getPosByChFld(ch, fld, rec);
iv->setValue(pos, rec, 0.0f); iv->setValue(pos, rec, 0.0f);
fld++;
} }
} }
iv->doCalculations();
notify(RealTimeRunData_Debug); notify(RealTimeRunData_Debug);
} }
@ -217,16 +212,16 @@ class HmPayload {
crcPass = build(iv->id, &pyldComplete); crcPass = build(iv->id, &pyldComplete);
if (!crcPass && !pyldComplete) { // payload not complete if (!crcPass && !pyldComplete) { // payload not complete
if ((mPayload[iv->id].requested) && (retransmit)) { if ((mPayload[iv->id].requested) && (retransmit)) {
if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { if (mPayload[iv->id].retransmits < mMaxRetrans) {
// This is required to prevent retransmissions without answer. mPayload[iv->id].retransmits++;
DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) {
mPayload[iv->id].retransmits = mMaxRetrans; // This is required to prevent retransmissions without answer.
} else if(iv->devControlCmd == ActivePowerContr) { DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm..."));
DPRINTLN(DBG_INFO, F("retransmit power limit")); mPayload[iv->id].retransmits = mMaxRetrans;
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else if(iv->devControlCmd == ActivePowerContr) {
} else { DPRINTLN(DBG_INFO, F("retransmit power limit"));
if (mPayload[iv->id].retransmits < mMaxRetrans) { mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true);
mPayload[iv->id].retransmits++; } else {
if(false == mPayload[iv->id].gotFragment) { if(false == mPayload[iv->id].gotFragment) {
/* /*
DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit")); DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit"));

5
src/hm/hmRadio.h

@ -104,6 +104,7 @@ class HmRadio {
mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms
mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.setChannel(mRfChLst[mRxChIdx]);
mNrf24.startListening();
mNrf24.setDataRate(RF24_250KBPS); mNrf24.setDataRate(RF24_250KBPS);
mNrf24.setAutoAck(true); mNrf24.setAutoAck(true);
mNrf24.enableDynamicPayloads(); mNrf24.enableDynamicPayloads();
@ -118,8 +119,6 @@ class HmRadio {
DPRINTLN(DBG_INFO, String(rf24AmpPowerNames[ampPwr])); DPRINTLN(DBG_INFO, String(rf24AmpPowerNames[ampPwr]));
mNrf24.setPALevel(ampPwr & 0x03); mNrf24.setPALevel(ampPwr & 0x03);
mNrf24.startListening();
if(mNrf24.isChipConnected()) { if(mNrf24.isChipConnected()) {
DPRINTLN(DBG_INFO, F("Radio Config:")); DPRINTLN(DBG_INFO, F("Radio Config:"));
mNrf24.printPrettyDetails(); mNrf24.printPrettyDetails();
@ -140,6 +139,7 @@ class HmRadio {
// start listening on the default RX channel // start listening on the default RX channel
mRxChIdx = 0; mRxChIdx = 0;
mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.setChannel(mRfChLst[mRxChIdx]);
mNrf24.startListening();
//uint32_t debug_ms = millis(); //uint32_t debug_ms = millis();
uint16_t cnt = 300; // that is 60 times 5 channels uint16_t cnt = 300; // that is 60 times 5 channels
@ -150,7 +150,6 @@ class HmRadio {
mIrqRcvd = false; mIrqRcvd = false;
if (getReceived()) { // everything received if (getReceived()) { // everything received
//DBGPRINTLN("RX finished Cnt: " + String(300-cnt) + " time used: " + String(millis()-debug_ms)+ " ms"); //DBGPRINTLN("RX finished Cnt: " + String(300-cnt) + " time used: " + String(millis()-debug_ms)+ " ms");
mNrf24.stopListening();
return true; return true;
} }
} }

11
src/publisher/pubMqtt.h

@ -72,7 +72,7 @@ class PubMqtt {
#endif #endif
} }
void connect() { inline void connect() {
mReconnectRequest = false; mReconnectRequest = false;
if(!mClient.connected()) if(!mClient.connected())
mClient.connect(); mClient.connect();
@ -136,6 +136,7 @@ class PubMqtt {
} }
void payloadEventListener(uint8_t cmd) { void payloadEventListener(uint8_t cmd) {
connect();
if(mClient.connected()) { // prevent overflow if MQTT broker is not reachable but set if(mClient.connected()) { // prevent overflow if MQTT broker is not reachable but set
if((0 == mCfgMqtt->interval) || (RealTimeRunData_Debug != cmd)) // no interval or no live data if((0 == mCfgMqtt->interval) || (RealTimeRunData_Debug != cmd)) // no interval or no live data
mSendList.push(cmd); mSendList.push(cmd);
@ -302,8 +303,12 @@ class PubMqtt {
tickerMinute(); tickerMinute();
publish(mLwtTopic, mLwtOnline, true, false); publish(mLwtTopic, mLwtOnline, true, false);
subscribe("ctrl/#"); subscribe("ctrl/limit_persistent_relative");
subscribe("setup/#"); subscribe("ctrl/limit_persistent_absolute");
subscribe("ctrl/limit_nonpersistent_relative");
subscribe("ctrl/limit_nonpersistent_absolute");
subscribe("setup/set_time");
subscribe("setup/sync_ntp");
//subscribe("status/#"); //subscribe("status/#");
} }

6
src/web/html/index.html

@ -145,12 +145,12 @@
if(obj["ts_sunrise"] > 0) { if(obj["ts_sunrise"] > 0) {
if(((obj["ts_sunrise"] - obj["ts_offset"]) < obj["ts_now"]) if(((obj["ts_sunrise"] - obj["ts_offset"]) < obj["ts_now"])
&& ((obj["ts_sunset"] + obj["ts_offset"]) > obj["ts_now"])) { && ((obj["ts_sunset"] + obj["ts_offset"]) > obj["ts_now"])) {
commInfo = "Polling inverter(s), will stop at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); commInfo = "Polling inverter(s), will stop at sunset " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE'));
} }
else if(obj["disNightComm"]) { else if(obj["disNightComm"]) {
commInfo = "Night time, no Communication to Inverter, "; commInfo = "Night time, inverter polling disabled, ";
if(obj["ts_now"] > (obj["ts_sunrise"] - obj["ts_offset"])) { if(obj["ts_now"] > (obj["ts_sunrise"] - obj["ts_offset"])) {
commInfo += "stopped polling at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); commInfo += "stopped at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE'));
} }
else { else {
commInfo += "will start polling at " + (new Date((obj["ts_sunrise"] - obj["ts_offset"]) * 1000).toLocaleString('de-DE')); commInfo += "will start polling at " + (new Date((obj["ts_sunrise"] - obj["ts_offset"]) * 1000).toLocaleString('de-DE'));

11
src/web/html/setup.html

@ -96,11 +96,12 @@
<label for="invRetry">Max retries per Payload</label> <label for="invRetry">Max retries per Payload</label>
<input type="text" class="text" name="invRetry"/> <input type="text" class="text" name="invRetry"/>
<label for="invRstMid">Reset Values and YieldDay at Midnight</label>
<label for="invRstMid">Reset values and YieldDay at midnight</label>
<input type="checkbox" class="cb" name="invRstMid"/><br/> <input type="checkbox" class="cb" name="invRstMid"/><br/>
<label for="invRstComStop">Reset Values at Communication stop</label> <label for="invRstComStop">Reset values when inverter polling stops at sunset</label>
<input type="checkbox" class="cb" name="invRstComStop"/><br/> <input type="checkbox" class="cb" name="invRstComStop"/><br/>
<label for="invRstNotAvail">Reset Values on 'not available'</label> <label for="invRstNotAvail">Reset values when inverter status is 'not available'</label>
<input type="checkbox" class="cb" name="invRstNotAvail"/><br/> <input type="checkbox" class="cb" name="invRstNotAvail"/><br/>
</fieldset> </fieldset>
</div> </div>
@ -125,7 +126,7 @@
<fieldset> <fieldset>
<legend class="des">Sunrise & Sunset</legend> <legend class="des">Sunrise & Sunset</legend>
<p> <p>
Latitude and Longitude must be set to be stored! decimal separator: '.' (dot) Use a decimal separator: '.' (dot) for Latitude and Longitude
</p> </p>
<label for="sunLat">Latitude (decimal)</label> <label for="sunLat">Latitude (decimal)</label>
<input type="text" class="text" name="sunLat"/> <input type="text" class="text" name="sunLat"/>
@ -134,7 +135,7 @@
<label for="sunOffs">Offset (pre sunrise, post sunset)</label> <label for="sunOffs">Offset (pre sunrise, post sunset)</label>
<select name="sunOffs"></select> <select name="sunOffs"></select>
<br> <br>
<label for="sunDisNightCom">disable night communication</label> <label for="sunDisNightCom">Stop polling inverters during night</label>
<input type="checkbox" class="cb" name="sunDisNightCom"/><br/> <input type="checkbox" class="cb" name="sunDisNightCom"/><br/>
</fieldset> </fieldset>
</div> </div>

3
src/web/html/style.css

@ -282,7 +282,8 @@ input.btn:hover {
} }
input.cb { input.cb {
margin-bottom: 20px; margin-bottom: 15px;
margin-top: 10px;
} }
label { label {

Loading…
Cancel
Save