diff --git a/src/CHANGES.md b/src/CHANGES.md index f8a2c5ca..e62f1333 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,36 +1,7 @@ -# Changelog v0.5.66 +# Changelog -**Note:** Version `0.5.42` to `0.5.65` were development versions. Last release version was `0.5.41` -Detailed change log (development changes): https://github.com/lumapu/ahoy/blob/945a671d27d10d0f7c175ebbf2fbb2806f9cd79a/src/CHANGES.md +(starting from release version `0.5.66`) - -* updated REST API and MQTT (both of them use the same functionality) -* improved stability -* Regular expressions for input fields which are used for MQTT to be compliant to MQTT -* WiFi optimization (AP Mode and STA in parallel, reconnect if local STA is unavailable) -* improved display of `/system` -* fix Update button protection (prevent double click #527) -* optimized scheduler #515 -* fix of duplicates in API `/api/record/live` (#526) -* added update information to `index.html` (check for update with github.com) -* fix web logout (auto logout) -* switched MQTT library -* removed MQTT `available_text` (can be deducted from `available`) -* enhanced MQTT documentation in `User_Manual.md` -* changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` -* added immediate (each minute) report of inverter status MQTT #522 -* increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 -* added disable night communication flag to MQTT #505 -* added MQTT /status to show status over all inverters -* added MQTT RX counter to index.html -* added protection mask to select which pages should be protected -* added monochrome display that show values also if nothing changed and in offline mode #498 -* added icons to index.html, added WiFi-strength symbol on each page -* refactored communication offset (adjustable in minutes now) -* factory reset formats entire little fs -* renamed sunrise / sunset on index.html to start / stop communication -* fixed static IP save -* fix NTP with static IP -* all values are displayed on /live even if they are 0 -* added NRF24 info to Systeminfo -* reordered enqueue commands after boot up to prevent same payload length for successive commands +## 0.5.67 +* changed calculation of start / stop communication to 1 min after last comm. stop #515 +* moved payload send to `payload.h`, function `ivSend` #515 diff --git a/src/app.cpp b/src/app.cpp index 29df1e64..b0e310c4 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -51,7 +51,7 @@ void app::setup() { #endif mSys->addInverters(&mConfig->inst); - mPayload.setup(mSys); + mPayload.setup(mSys, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); mPayload.enableSerialDebug(mConfig->serial.debug); if(!mSys->Radio.isChipConnected()) @@ -115,7 +115,9 @@ void app::loop(void) { yield(); if (rxRdy) - mPayload.process(true, mConfig->nrf.maxRetransPerPyld, &mStat); + mPayload.process(true); + + mRxTicker = 0; } #if !defined(AP_ONLY) @@ -138,14 +140,18 @@ void app::tickNtpUpdate(void) { //----------------------------------------------------------------------------- void app::tickCalcSunrise(void) { - ah::calculateSunriseSunset(mTimestamp, mCalculatedTimezoneOffset, mConfig->sun.lat, mConfig->sun.lon, &mSunrise, &mSunset); + if (mSunrise == 0) // on boot/reboot calc sun values for current time + ah::calculateSunriseSunset(mTimestamp, mCalculatedTimezoneOffset, mConfig->sun.lat, mConfig->sun.lon, &mSunrise, &mSunset); + + if (mTimestamp > (mSunset + mConfig->sun.offsetSec)) // current time is past communication stop, calc sun values for next day + ah::calculateSunriseSunset(mTimestamp + 86400, mCalculatedTimezoneOffset, mConfig->sun.lat, mConfig->sun.lon, &mSunrise, &mSunset); + tickIVCommunication(); - uint32_t nxtTrig = mTimestamp - ((mTimestamp + mCalculatedTimezoneOffset - 10) % 86400) + 86400;; // next midnight, -10 for safety that it is certain next day, local timezone + uint32_t nxtTrig = mSunset + mConfig->sun.offsetSec + 60; // set next trigger to communication stop, +60 for safety that it is certain past communication stop onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig); - if (mConfig->mqtt.broker[0] > 0) { + if (mConfig->mqtt.broker[0] > 0) mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec, mConfig->sun.disNightCom); - } } //----------------------------------------------------------------------------- @@ -187,49 +193,8 @@ void app::tickSend(void) { } while ((NULL == iv) && ((maxLoop--) > 0)); if (NULL != iv) { - if(iv->config->enabled) { - if (!mPayload.isComplete(iv)) - mPayload.process(false, mConfig->nrf.maxRetransPerPyld, &mStat); - - if (!mPayload.isComplete(iv)) { - if (0 == mPayload.getMaxPacketId(iv)) - mStat.rxFailNoAnser++; - else - mStat.rxFail++; - - iv->setQueuedCmdFinished(); // command failed - if (mConfig->serial.debug) - DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); - if (mConfig->serial.debug) { - DPRINT(DBG_INFO, F("(#") + String(iv->id) + ") "); - DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload.getRetransmits(iv)) + ")"); - } - } - - mPayload.reset(iv, mTimestamp); - mPayload.request(iv); - - yield(); - if (mConfig->serial.debug) { - DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status())); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX)); - } - - if (iv->devControlRequest) { - if (mConfig->serial.debug) - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0])); - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit); - mPayload.setTxCmd(iv, iv->devControlCmd); - iv->clearCmdQueue(); - iv->enqueCommand(SystemConfigPara); // read back power limit - } else { - uint8_t cmd = iv->getQueuedCmd(); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); - mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload.getTs(iv), iv->alarmMesIndex); - mPayload.setTxCmd(iv, cmd); - mRxTicker = 0; - } - } + if(iv->config->enabled) + mPayload.ivSend(iv); } } else { if (mConfig->serial.debug) diff --git a/src/defines.h b/src/defines.h index ddfda35e..301c9f17 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 66 +#define VERSION_PATCH 67 //------------------------------------- typedef struct { diff --git a/src/hm/payload.h b/src/hm/payload.h index ef69c4fe..9a23fbfe 100644 --- a/src/hm/payload.h +++ b/src/hm/payload.h @@ -34,47 +34,67 @@ class Payload : public Handler { public: Payload() : Handler() {} - void setup(HMSYSTEM *sys) { - mSys = sys; + void setup(HMSYSTEM *sys, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { + mSys = sys; + mStat = stat; + mMaxRetrans = maxRetransmits; + mTimestamp = timestamp; memset(mPayload, 0, (MAX_NUM_INVERTERS * sizeof(invPayload_t))); mLastPacketId = 0x00; - mSerialDebug = false; + mSerialDebug = false; } void enableSerialDebug(bool enable) { mSerialDebug = enable; } - bool isComplete(Inverter<> *iv) { - return mPayload[iv->id].complete; - } - - uint8_t getMaxPacketId(Inverter<> *iv) { - return mPayload[iv->id].maxPackId; - } - - uint8_t getRetransmits(Inverter<> *iv) { - return mPayload[iv->id].retransmits; - } - - uint32_t getTs(Inverter<> *iv) { - return mPayload[iv->id].ts; - } - - void request(Inverter<> *iv) { - mPayload[iv->id].requested = true; - } - - void setTxCmd(Inverter<> *iv, uint8_t cmd) { - mPayload[iv->id].txCmd = cmd; - } - void notify(uint8_t val) { for(typename std::list::iterator it = mList.begin(); it != mList.end(); ++it) { (*it)(val); } } + void ivSend(Inverter<> *iv) { + if (!mPayload[iv->id].complete) + process(false); + + if (!mPayload[iv->id].complete) { + if (0 == mPayload[iv->id].maxPackId) + mStat->rxFailNoAnser++; + else + mStat->rxFail++; + + iv->setQueuedCmdFinished(); // command failed + if (mSerialDebug) + DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + if (mSerialDebug) { + DPRINT(DBG_INFO, F("(#") + String(iv->id) + ") "); + DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload[iv->id].retransmits) + ")"); + } + } + + reset(iv); + mPayload[iv->id].requested = true; + + yield(); + if (mSerialDebug) + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX)); + + if (iv->devControlRequest) { + if (mSerialDebug) + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0])); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit); + mPayload[iv->id].txCmd = iv->devControlCmd; + iv->clearCmdQueue(); + iv->enqueCommand(SystemConfigPara); // read back power limit + } else { + uint8_t cmd = iv->getQueuedCmd(); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); + mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex); + mPayload[iv->id].txCmd = cmd; + } + } + void add(packet_t *p, uint8_t len) { Inverter<> *iv = mSys->findInverter(&p->packet[1]); if ((NULL != iv) && (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES))) { // response from get information command @@ -134,7 +154,7 @@ class Payload : public Handler { return (crc == crcRcv) ? true : false; } - void process(bool retransmit, uint8_t maxRetransmits, statistics_t *stat) { + void process(bool retransmit) { for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { Inverter<> *iv = mSys->getInverterByPos(id); if (NULL == iv) @@ -152,9 +172,9 @@ class Payload : public Handler { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); - mPayload[iv->id].retransmits = maxRetransmits; + mPayload[iv->id].retransmits = mMaxRetrans; } else { - if (mPayload[iv->id].retransmits < maxRetransmits) { + if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if (mPayload[iv->id].maxPackId != 0) { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { @@ -207,7 +227,7 @@ class Payload : public Handler { DPRINTLN(DBG_ERROR, F("record is NULL!")); } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { if (mPayload[iv->id].txId == (TX_REQ_INFO + 0x80)) - stat->rxSuccess++; + mStat->rxSuccess++; rec->ts = mPayload[iv->id].ts; for (uint8_t i = 0; i < rec->length; i++) { @@ -218,7 +238,7 @@ class Payload : public Handler { notify(mPayload[iv->id].txCmd); } else { DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); - stat->rxFail++; + mStat->rxFail++; } iv->setQueuedCmdFinished(); @@ -230,7 +250,7 @@ class Payload : public Handler { } } - void reset(Inverter<> *iv, uint32_t utcTs) { + void reset(Inverter<> *iv) { DPRINTLN(DBG_INFO, "resetPayload: id: " + String(iv->id)); memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[iv->id].txCmd = 0; @@ -238,11 +258,14 @@ class Payload : public Handler { mPayload[iv->id].maxPackId = 0; mPayload[iv->id].complete = false; mPayload[iv->id].requested = false; - mPayload[iv->id].ts = utcTs; + mPayload[iv->id].ts = *mTimestamp; } private: HMSYSTEM *mSys; + statistics_t *mStat; + uint8_t mMaxRetrans; + uint32_t *mTimestamp; invPayload_t mPayload[MAX_NUM_INVERTERS]; uint8_t mLastPacketId; bool mSerialDebug;