From 81f7c350d025710d956d2dad9d004cf4c78cb8ae Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 11:53:50 +0100 Subject: [PATCH 01/79] dynamic retries discord version 0.8.6401 --- src/hm/Communication.h | 10 +++++++-- src/hm/Heuristic.h | 48 ++++++++++++++++++++++++++++++++++++++++-- src/hm/HeuristicInv.h | 3 +++ src/hm/hmRadio.h | 12 +++++++++-- src/hm/radio.h | 1 + 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 98dd06e1..60e87918 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -148,6 +148,7 @@ class Communication : public CommQueue<> { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTime.startTimeMonitor(1000); } else { + mHeu.setIvRetriesBad(q->iv); if(IV_MI == q->iv->ivGen) q->iv->mIvTxCnt++; @@ -180,8 +181,11 @@ class Communication : public CommQueue<> { q->iv->mDtuRxCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - if(parseFrame(p)) + if(parseFrame(p)) { q->iv->curFrmCnt++; + if(!mIsRetransmit && p->packet[9] == 2 && p->millis < 85) + mHeu.setIvRetriesGood(q->iv,p->millis < 70); + } } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command if(parseDevCtrl(p, q)) closeRequest(q, true); @@ -417,6 +421,8 @@ class Communication : public CommQueue<> { } inline bool parseMiFrame(packet_t *p, const queue_s *q) { + if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < 35) //first frame is fast? + mHeu.setIvRetriesGood(q->iv,p->millis < 22); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) @@ -527,7 +533,7 @@ class Communication : public CommQueue<> { len -= 2; - DPRINT_IVID(DBG_INFO, q->iv->id); + //DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 64c78cc8..642eca13 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -23,8 +23,8 @@ class Heuristic { public: uint8_t getTxCh(Inverter<> *iv) { - if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) - return 0; // not used for these inverter types + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return 0; // not used for other than nRF inverter types HeuristicInv *ih = &iv->heuristics; @@ -66,6 +66,8 @@ class Heuristic { ih->testPeriodFailCnt = 0; } + iv->radio->mTxRetriesNext = getIvRetries(iv); + return id2Ch(ih->txRfChId); } @@ -155,6 +157,48 @@ class Heuristic { DBGPRINTLN(String(iv->config->powerLevel)); } + uint8_t getIvRetries(Inverter<> *iv) { + if(iv->heuristics.rxSpeeds[0]) + return 5; + if(iv->heuristics.rxSpeeds[1]) + return 10; + return 15; + } + + void setIvRetriesGood(Inverter<> *iv, bool veryGood) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[veryGood] > 9) + return; + iv->heuristics.rxSpeedCnt[veryGood]++; + iv->heuristics.rxSpeeds[veryGood] = true; + } + + void setIvRetriesBad(Inverter<> *iv) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[0]) { + iv->heuristics.rxSpeedCnt[0]--; + return; + } + if(iv->heuristics.rxSpeeds[0]) { + iv->heuristics.rxSpeeds[0] = false; + return; + } + + if(iv->heuristics.rxSpeedCnt[1]) { + iv->heuristics.rxSpeedCnt[1]--; + return; + } + if(iv->heuristics.rxSpeeds[1]) { + iv->heuristics.rxSpeeds[1] = false; + return; + } + return; + } + private: bool isNewTxCh(HeuristicInv *ih) { return ih->txRfChId != ih->lastBestTxChId; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index e7ad6edd..fc782a7b 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -27,6 +27,9 @@ class HeuristicInv { uint8_t testChId = 0; int8_t saveOldTestQuality = -6; uint8_t lastRxFragments = 0; + bool rxSpeeds[2] = {false,false}; // is inverter responding very fast respective fast? + uint8_t rxSpeedCnt[2] = {0,0}; // count how many messages had been received very fast respective fast (10 max) + }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ef37e266..d41dc36a 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -161,7 +161,7 @@ class HmRadio : public Radio { rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); - innerLoopTimeout = DURATION_TXFRAME; + innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; } if(rx_ready) { @@ -356,11 +356,14 @@ class HmRadio : public Radio { mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { + /* remark rejoe2: imo this has no added value here. + As this belongs to the last tx cycle, we should print that info + directly when switching from tx to rx. Otherwise we might confuse users. if(!isRetransmit) { DPRINT(DBG_INFO, "last tx setup: "); DBGPRINT(String(mTxSetupTime)); DBGPRINTLN("ms"); - } + }*/ DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); @@ -383,6 +386,10 @@ class HmRadio : public Radio { } mNrf24->stopListening(); + if(!isRetransmit && mTxRetries != mTxRetriesNext) { + mNrf24->setRetries(3, mTxRetriesNext); + mTxRetries = mTxRetriesNext; + } mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response @@ -425,6 +432,7 @@ class HmRadio : public Radio { bool rxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; uint8_t mTxSetupTime = 0; + uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hm/radio.h b/src/hm/radio.h index a71e24c7..e11d8682 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -78,6 +78,7 @@ class Radio { std::queue mBufCtrl; uint8_t mIrqOk = IRQ_UNKNOWN; TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) + uint8_t mTxRetriesNext = 15; // let heuristics tell us the next reties count (for nRF type radios only) protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; From 8f5310ffd35dd7ea9b48af188ef5e95b1e0dc2fb Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 12:41:41 +0100 Subject: [PATCH 02/79] reduce serial output --- src/hm/Communication.h | 12 +++++++----- src/hm/hmRadio.h | 12 +++++++----- src/hm/radio.h | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 60e87918..b02c03b7 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -134,14 +134,16 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); - DBGPRINT(F("ms")); - if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINTLN(F("ms")); + /*if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINT(F(", retries ")); + DBGPRINTLN(String(q->iv->radio->mTxRetriesNext)); DBGPRINT(F(", ARC ")); DBGPRINT(String(q->iv->radio->getARC())); DBGPRINT(F(", PLOS ")); DBGPRINTLN(String(q->iv->radio->getPLOS())); } else - DBGPRINTLN(""); + DBGPRINTLN("");*/ } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { @@ -295,10 +297,10 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - DBGPRINT(F(", ARC ")); + /*DBGPRINT(F(", ARC ")); DBGPRINT(String(p->arc)); DBGPRINT(F(", PLOS ")); - DBGPRINT(String(p->plos)); + DBGPRINT(String(p->plos));*/ DBGPRINT(F(" |")); if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { DBGPRINT(F(" CH")); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d41dc36a..9915a9a8 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -293,13 +293,13 @@ class HmRadio : public Radio { return mNrf24->isPVariant(); } - uint8_t getARC(void) { + /*uint8_t getARC(void) { return mNrf24->getARC(); } uint8_t getPLOS(void) { return mNrf24->getPLOS(); - } + }*/ private: inline bool getReceived(void) { @@ -315,8 +315,8 @@ class HmRadio : public Radio { p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - p.arc = mNrf24->getARC(); - p.plos = mNrf24->getPLOS(); + //p.arc = mNrf24->getARC(); + //p.plos = mNrf24->getPLOS(); mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { @@ -370,7 +370,9 @@ class HmRadio : public Radio { DBGPRINT(String(len)); DBGPRINT(" CH"); DBGPRINT(String(mRfChLst[mTxChIdx])); - DBGPRINT(F(" | ")); + DBGPRINT(F(", ")); + DBGPRINT(String(mTxRetriesNext)); + DBGPRINT(F(" retries | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); diff --git a/src/hm/radio.h b/src/hm/radio.h index e11d8682..e6baf792 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -29,8 +29,8 @@ class Radio { virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual bool isChipConnected(void) { return false; } virtual bool loop(void) = 0; - virtual uint8_t getARC(void) { return 0xff; } - virtual uint8_t getPLOS(void) { return 0xff; } + //virtual uint8_t getARC(void) { return 0xff; } + //virtual uint8_t getPLOS(void) { return 0xff; } void handleIntr(void) { mIrqRcvd = true; From bfedf4f0c23db7161ae3aadd4995f88b5f9c815d Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 16:09:54 +0100 Subject: [PATCH 03/79] fix 2nd frame detection for 2ch HM and add faster exiting CMT wait state --- src/hm/Communication.h | 25 ++++++++++++++-------- src/hm/Heuristic.h | 48 ++++++++++++++++++++++++++++++++++++++++-- src/hm/HeuristicInv.h | 3 +++ src/hm/hmRadio.h | 24 +++++++++++++++------ src/hm/radio.h | 5 +++-- src/hms/hmsRadio.h | 5 +++-- 6 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 98dd06e1..15ca3d5d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -86,7 +86,7 @@ class Communication : public CommQueue<> { mIsRetransmit = false; if(NULL == q->iv->radio) cmdDone(false); // can't communicate while radio is not defined! - mFirstTry = q->iv->isAvailable(); + mFirstTry = INV_RADIO_TYPE_NRF == q->iv->ivRadioType && q->iv->isAvailable(); q->iv->mCmd = q->cmd; q->iv->mIsSingleframeReq = false; mFramesExpected = getFramesExpected(q); // function to get expected frame count. @@ -134,20 +134,23 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); - DBGPRINT(F("ms")); - if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINTLN(F("ms")); + /*if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINT(F(", retries ")); + DBGPRINTLN(String(q->iv->radio->mTxRetriesNext)); DBGPRINT(F(", ARC ")); DBGPRINT(String(q->iv->radio->getARC())); DBGPRINT(F(", PLOS ")); DBGPRINTLN(String(q->iv->radio->getPLOS())); } else - DBGPRINTLN(""); + DBGPRINTLN("");*/ } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTime.startTimeMonitor(1000); } else { + mHeu.setIvRetriesBad(q->iv); if(IV_MI == q->iv->ivGen) q->iv->mIvTxCnt++; @@ -180,8 +183,11 @@ class Communication : public CommQueue<> { q->iv->mDtuRxCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - if(parseFrame(p)) + if(parseFrame(p)) { q->iv->curFrmCnt++; + if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < 85) + mHeu.setIvRetriesGood(q->iv,p->millis < 70); + } } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command if(parseDevCtrl(p, q)) closeRequest(q, true); @@ -291,10 +297,10 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - DBGPRINT(F(", ARC ")); + /*DBGPRINT(F(", ARC ")); DBGPRINT(String(p->arc)); DBGPRINT(F(", PLOS ")); - DBGPRINT(String(p->plos)); + DBGPRINT(String(p->plos));*/ DBGPRINT(F(" |")); if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { DBGPRINT(F(" CH")); @@ -417,6 +423,8 @@ class Communication : public CommQueue<> { } inline bool parseMiFrame(packet_t *p, const queue_s *q) { + if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < 35) //first frame is fast? + mHeu.setIvRetriesGood(q->iv,p->millis < 22); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) @@ -436,7 +444,6 @@ class Communication : public CommQueue<> { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = q->ts; miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); - //mHeu.setGotFragment(q->iv); only do this when we are through the cycle? } return true; @@ -527,7 +534,7 @@ class Communication : public CommQueue<> { len -= 2; - DPRINT_IVID(DBG_INFO, q->iv->id); + //DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 64c78cc8..642eca13 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -23,8 +23,8 @@ class Heuristic { public: uint8_t getTxCh(Inverter<> *iv) { - if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) - return 0; // not used for these inverter types + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return 0; // not used for other than nRF inverter types HeuristicInv *ih = &iv->heuristics; @@ -66,6 +66,8 @@ class Heuristic { ih->testPeriodFailCnt = 0; } + iv->radio->mTxRetriesNext = getIvRetries(iv); + return id2Ch(ih->txRfChId); } @@ -155,6 +157,48 @@ class Heuristic { DBGPRINTLN(String(iv->config->powerLevel)); } + uint8_t getIvRetries(Inverter<> *iv) { + if(iv->heuristics.rxSpeeds[0]) + return 5; + if(iv->heuristics.rxSpeeds[1]) + return 10; + return 15; + } + + void setIvRetriesGood(Inverter<> *iv, bool veryGood) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[veryGood] > 9) + return; + iv->heuristics.rxSpeedCnt[veryGood]++; + iv->heuristics.rxSpeeds[veryGood] = true; + } + + void setIvRetriesBad(Inverter<> *iv) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[0]) { + iv->heuristics.rxSpeedCnt[0]--; + return; + } + if(iv->heuristics.rxSpeeds[0]) { + iv->heuristics.rxSpeeds[0] = false; + return; + } + + if(iv->heuristics.rxSpeedCnt[1]) { + iv->heuristics.rxSpeedCnt[1]--; + return; + } + if(iv->heuristics.rxSpeeds[1]) { + iv->heuristics.rxSpeeds[1] = false; + return; + } + return; + } + private: bool isNewTxCh(HeuristicInv *ih) { return ih->txRfChId != ih->lastBestTxChId; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index e7ad6edd..fc782a7b 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -27,6 +27,9 @@ class HeuristicInv { uint8_t testChId = 0; int8_t saveOldTestQuality = -6; uint8_t lastRxFragments = 0; + bool rxSpeeds[2] = {false,false}; // is inverter responding very fast respective fast? + uint8_t rxSpeedCnt[2] = {0,0}; // count how many messages had been received very fast respective fast (10 max) + }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ef37e266..9915a9a8 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -161,7 +161,7 @@ class HmRadio : public Radio { rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); - innerLoopTimeout = DURATION_TXFRAME; + innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; } if(rx_ready) { @@ -293,13 +293,13 @@ class HmRadio : public Radio { return mNrf24->isPVariant(); } - uint8_t getARC(void) { + /*uint8_t getARC(void) { return mNrf24->getARC(); } uint8_t getPLOS(void) { return mNrf24->getPLOS(); - } + }*/ private: inline bool getReceived(void) { @@ -315,8 +315,8 @@ class HmRadio : public Radio { p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - p.arc = mNrf24->getARC(); - p.plos = mNrf24->getPLOS(); + //p.arc = mNrf24->getARC(); + //p.plos = mNrf24->getPLOS(); mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { @@ -356,18 +356,23 @@ class HmRadio : public Radio { mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { + /* remark rejoe2: imo this has no added value here. + As this belongs to the last tx cycle, we should print that info + directly when switching from tx to rx. Otherwise we might confuse users. if(!isRetransmit) { DPRINT(DBG_INFO, "last tx setup: "); DBGPRINT(String(mTxSetupTime)); DBGPRINTLN("ms"); - } + }*/ DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); DBGPRINT(String(mRfChLst[mTxChIdx])); - DBGPRINT(F(" | ")); + DBGPRINT(F(", ")); + DBGPRINT(String(mTxRetriesNext)); + DBGPRINT(F(" retries | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); @@ -383,6 +388,10 @@ class HmRadio : public Radio { } mNrf24->stopListening(); + if(!isRetransmit && mTxRetries != mTxRetriesNext) { + mNrf24->setRetries(3, mTxRetriesNext); + mTxRetries = mTxRetriesNext; + } mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response @@ -425,6 +434,7 @@ class HmRadio : public Radio { bool rxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; uint8_t mTxSetupTime = 0; + uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hm/radio.h b/src/hm/radio.h index a71e24c7..e6baf792 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -29,8 +29,8 @@ class Radio { virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual bool isChipConnected(void) { return false; } virtual bool loop(void) = 0; - virtual uint8_t getARC(void) { return 0xff; } - virtual uint8_t getPLOS(void) { return 0xff; } + //virtual uint8_t getARC(void) { return 0xff; } + //virtual uint8_t getPLOS(void) { return 0xff; } void handleIntr(void) { mIrqRcvd = true; @@ -78,6 +78,7 @@ class Radio { std::queue mBufCtrl; uint8_t mIrqOk = IRQ_UNKNOWN; TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) + uint8_t mTxRetriesNext = 15; // let heuristics tell us the next reties count (for nRF type radios only) protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 48ff3750..3c569e02 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -166,9 +166,10 @@ class CmtRadio : public Radio { mBufCtrl.push(p); // this code completly stops communication! - //if(p.packet[9] > ALL_FRAMES) // indicates last frame + if(p.packet[9] > ALL_FRAMES) // indicates last frame // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... - //optionally instead: mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? + //optionally instead: + mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? } CmtType mCmt; From 3fbd2c7c88e933e42af35d84dba243598bceed95 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 17:54:57 +0100 Subject: [PATCH 04/79] fix retransmit counter for secondtry - try to fix "45ms"-Problem --- src/hm/Communication.h | 4 ++-- src/hm/hmRadio.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 15ca3d5d..94cf23ff 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -156,9 +156,9 @@ class Communication : public CommQueue<> { if(mFirstTry) { mFirstTry = false; - setAttempt(); + //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); - q->iv->radioStatistics.rxFailNoAnser++; + //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.stopTimeMonitor(); mState = States::START; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 9915a9a8..54f099dd 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -167,6 +167,7 @@ class HmRadio : public Radio { if(rx_ready) { if (getReceived()) { // check what we got, returns true for last package mNRFisInRX = false; + rx_ready = false; mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions mNrf24->stopListening(); } else { From 444a7160128b2a6e8d7628b8d940ca14236f31d6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 24 Jan 2024 10:42:39 +0100 Subject: [PATCH 05/79] partly fix statistics - add more data requests to startup phase --- src/hm/Communication.h | 7 +++++-- src/hm/hmInverter.h | 12 ++++++++---- src/hm/hmRadio.h | 12 +++++++++--- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 94cf23ff..4003c13e 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -159,6 +159,7 @@ class Communication : public CommQueue<> { //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. + q->iv->radioStatistics.txCnt--; q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.stopTimeMonitor(); mState = States::START; @@ -835,8 +836,9 @@ class Communication : public CommQueue<> { DBGHEXLN(cmd); } - if(q->iv->miMultiParts == 7) - q->iv->radioStatistics.rxSuccess++; + //if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7) + q->iv->radioStatistics.rxSuccess++; + q->iv->radioStatistics.ivSent++; mFramesExpected = getFramesExpected(q); q->iv->radio->setExpectedFrames(mFramesExpected); @@ -861,6 +863,7 @@ class Communication : public CommQueue<> { } q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); + q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); mIsRetransmit = false; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b28682e5..049b5501 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -200,13 +200,17 @@ class Inverter { cb(devControlCmd, false); // custom command which was received by API devControlCmd = InitDataState; mGetLossInterval = 1; - } else if(0 == getFwVersion()) + } else if(0 == getFwVersion()) { + cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_All, false); // get firmware version - else if(0 == getHwVersion()) + } + else if(0 == getHwVersion()) { + cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_Simple, false); // get hardware version - else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { + cb(RealTimeRunData_Debug, false); // get live data cb(AlarmData, false); // get last alarms - else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile + } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile cb(GridOnProFilePara, false); } else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate mGetLossInterval = 1; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 54f099dd..feb4fde5 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -113,6 +113,7 @@ class HmRadio : public Radio { if (mRadioWaitTime.isTimeout()) { // timeout reached! mNRFisInRX = false; + rx_ready = false; return false; } @@ -165,7 +166,7 @@ class HmRadio : public Radio { } if(rx_ready) { - if (getReceived()) { // check what we got, returns true for last package + if (getReceived()) { // check what we got, returns true for last package or success for single frame request mNRFisInRX = false; rx_ready = false; mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions @@ -183,6 +184,7 @@ class HmRadio : public Radio { mRxChIdx = tempRxChIdx; } } + rx_ready = false; // reset return mNRFisInRX; } /*else if(tx_fail) { mNRFisInRX = false; @@ -305,6 +307,7 @@ class HmRadio : public Radio { private: inline bool getReceived(void) { bool isLastPackage = false; + bool isRetransmitAnswer = false; rx_ready = false; // reset for ACK case while(mNrf24->available()) { @@ -329,8 +332,11 @@ class HmRadio : public Radio { mLastIv->mGotFragment = true; mBufCtrl.push(p); - if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received + if(mLastIv->mIsSingleframeReq) // we only expect one frame here... + isRetransmitAnswer = true; + } if(IV_MI == mLastIv->ivGen) { if (p.packet[0] == (0x0f + ALL_FRAMES)) // response from MI get information command @@ -346,7 +352,7 @@ class HmRadio : public Radio { } if(isLastPackage) mLastIv->mGotLastMsg = true; - return isLastPackage; + return isLastPackage || isRetransmitAnswer; } void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { From d7ea4bcb892b0d63e8875bbc49a1a352d1afc1f8 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 24 Jan 2024 17:31:58 +0100 Subject: [PATCH 06/79] fix 0 attempts in Communication - 45ms-Problem seems to be solved --- src/hm/Communication.h | 4 ++-- src/hm/hmRadio.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 4003c13e..38925059 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -129,7 +129,7 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) || (0 == q->attempts)) { // radio buffer empty or no more answers + if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) ) { // || (0 == q->attempts)) { // radio buffer empty or no more answers if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); @@ -259,7 +259,7 @@ class Communication : public CommQueue<> { if(framnr) { if(0 == q->attempts) { DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("no attempts left")); + DBGPRINTLN(F("no attempts left")); closeRequest(q, false); return; } diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index feb4fde5..0df22f5a 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -336,6 +336,8 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received if(mLastIv->mIsSingleframeReq) // we only expect one frame here... isRetransmitAnswer = true; + if(isLastPackage) + mFramesExpected = p.packet[9] - ALL_FRAMES; } if(IV_MI == mLastIv->ivGen) { @@ -350,8 +352,9 @@ class HmRadio : public Radio { } yield(); } - if(isLastPackage) + if(isLastPackage) { mLastIv->mGotLastMsg = true; + } return isLastPackage || isRetransmitAnswer; } From 97d74d309000e8e210178ee829c51a1ad6a4545f Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 25 Jan 2024 00:03:49 +0100 Subject: [PATCH 07/79] 0.8.65 - 2024-01-24 * removed patch for NRF `PLOS` * fix lang issues #1388 * fix build on Windows of `opendtufusion` environments (git: trailing whitespaces) --- patches/RF24.patch | 35 ----------------------------------- scripts/applyPatches.py | 6 ++---- src/CHANGES.md | 5 +++++ src/defines.h | 2 +- src/hm/CommQueue.h | 6 ++---- src/hm/Communication.h | 14 +------------- src/hm/hmRadio.h | 27 ++++++--------------------- src/hm/radio.h | 10 ++++------ src/hms/hmsRadio.h | 11 +++++------ src/web/lang.json | 4 ++-- 10 files changed, 28 insertions(+), 92 deletions(-) delete mode 100644 patches/RF24.patch diff --git a/patches/RF24.patch b/patches/RF24.patch deleted file mode 100644 index 63db8823..00000000 --- a/patches/RF24.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/RF24.cpp b/RF24.cpp -index 9e5b4a8..a4de63c 100644 ---- a/RF24.cpp -+++ b/RF24.cpp -@@ -1871,6 +1871,11 @@ uint8_t RF24::getARC(void) - return read_register(OBSERVE_TX) & 0x0F; - } - -+uint8_t RF24::getPLOS(void) -+{ -+ return read_register(OBSERVE_TX) & 0x0F; -+} -+ - /****************************************************************************/ - - bool RF24::setDataRate(rf24_datarate_e speed) -diff --git a/RF24.h b/RF24.h -index dbd32ae..a3d6b52 100644 ---- a/RF24.h -+++ b/RF24.h -@@ -1644,6 +1644,7 @@ public: - * @return Returns values from 0 to 15. - */ - uint8_t getARC(void); -+ uint8_t getPLOS(void); - - /** - * Set the transmission @ref Datarate -@@ -2415,4 +2416,4 @@ private: - * Use `ctrl+c` to quit at any time. - */ - --#endif // __RF24_H__ -\ No newline at end of file -+#endif // __RF24_H__ diff --git a/scripts/applyPatches.py b/scripts/applyPatches.py index 3289badb..147fb0f3 100644 --- a/scripts/applyPatches.py +++ b/scripts/applyPatches.py @@ -12,11 +12,11 @@ def applyPatch(libName, patchFile): os.chdir('.pio/libdeps/' + env['PIOENV'] + '/' + libName) - process = subprocess.run(['git', 'apply', '--reverse', '--check', '../../../../' + patchFile], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + process = subprocess.run(['git', 'apply', '--ignore-whitespace', '--reverse', '--check', '../../../../' + patchFile], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if (process.returncode == 0): print('\'' + patchFile + '\' already applied') else: - process = subprocess.run(['git', 'apply', '../../../../' + patchFile]) + process = subprocess.run(['git', 'apply', '--ignore-whitespace', '../../../../' + patchFile]) if (process.returncode == 0): print('\'' + patchFile + '\' applied') else: @@ -32,5 +32,3 @@ if env['PIOENV'][:22] != "opendtufusion-ethernet": if env['PIOENV'][:13] == "opendtufusion": applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch") applyPatch("RF24", "../patches/RF24_Hal.patch") -else: - applyPatch("RF24", "../patches/RF24.patch") diff --git a/src/CHANGES.md b/src/CHANGES.md index a4942d55..b8547302 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.65 - 2024-01-24 +* removed patch for NRF `PLOS` +* fix lang issues #1388 +* fix build on Windows of `opendtufusion` environments (git: trailing whitespaces) + ## 0.8.64 - 2024-01-22 * add `ARC` to log (NRF24 Debug) * merge PR: ETH NTP update bugfix #1385 diff --git a/src/defines.h b/src/defines.h index b8ddace9..ed975b7a 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 64 +#define VERSION_PATCH 65 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index d3fe1c69..0ca9279f 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -18,8 +18,6 @@ template class CommQueue { public: - CommQueue() {} - void addImportant(Inverter<> *iv, uint8_t cmd) { dec(&mRdPtr); mQueue[mRdPtr] = queue_s(iv, cmd, true); @@ -34,12 +32,12 @@ class CommQueue { mQueue[mWrPtr] = queue_s(iv, cmd, false); } - uint8_t getFillState(void) { + uint8_t getFillState(void) const { //DPRINTLN(DBG_INFO, "wr: " + String(mWrPtr) + ", rd: " + String(mRdPtr)); return abs(mRdPtr - mWrPtr); } - uint8_t getMaxFill(void) { + uint8_t getMaxFill(void) const { return N; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 98dd06e1..3a6fdd0b 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -134,14 +134,7 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); - DBGPRINT(F("ms")); - if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { - DBGPRINT(F(", ARC ")); - DBGPRINT(String(q->iv->radio->getARC())); - DBGPRINT(F(", PLOS ")); - DBGPRINTLN(String(q->iv->radio->getPLOS())); - } else - DBGPRINTLN(""); + DBGPRINTLN(F("ms")); } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { @@ -291,11 +284,6 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - DBGPRINT(F(", ARC ")); - DBGPRINT(String(p->arc)); - DBGPRINT(F(", PLOS ")); - DBGPRINT(String(p->plos)); - DBGPRINT(F(" |")); if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { DBGPRINT(F(" CH")); if(3 == p->ch) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ef37e266..d73b2b0e 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -15,7 +15,6 @@ #endif #define SPI_SPEED 1000000 - #define RF_CHANNELS 5 const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; @@ -183,17 +182,13 @@ class HmRadio : public Radio { } } return mNRFisInRX; - } /*else if(tx_fail) { - mNRFisInRX = false; - return false; - }*/ + } } return false; } - bool isChipConnected(void) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); + bool isChipConnected(void) const { return mNrf24->isChipConnected(); } @@ -283,24 +278,16 @@ class HmRadio : public Radio { sendPacket(iv, cnt, isRetransmit, (IV_MI != iv->ivGen)); } - uint8_t getDataRate(void) { + uint8_t getDataRate(void) const { if(!mNrf24->isChipConnected()) return 3; // unknown return mNrf24->getDataRate(); } - bool isPVariant(void) { + bool isPVariant(void) const { return mNrf24->isPVariant(); } - uint8_t getARC(void) { - return mNrf24->getARC(); - } - - uint8_t getPLOS(void) { - return mNrf24->getPLOS(); - } - private: inline bool getReceived(void) { bool isLastPackage = false; @@ -315,8 +302,6 @@ class HmRadio : public Radio { p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - p.arc = mNrf24->getARC(); - p.plos = mNrf24->getPLOS(); mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { @@ -393,11 +378,11 @@ class HmRadio : public Radio { mNRFisInRX = false; } - uint64_t getIvId(Inverter<> *iv) { + uint64_t getIvId(Inverter<> *iv) const { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) { + uint8_t getIvGen(Inverter<> *iv) const { return iv->ivGen; } diff --git a/src/hm/radio.h b/src/hm/radio.h index a71e24c7..f7d61e42 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -27,10 +27,8 @@ class Radio { virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } - virtual bool isChipConnected(void) { return false; } + virtual bool isChipConnected(void) const { return false; } virtual bool loop(void) = 0; - virtual uint8_t getARC(void) { return 0xff; } - virtual uint8_t getPLOS(void) { return 0xff; } void handleIntr(void) { mIrqRcvd = true; @@ -66,7 +64,7 @@ class Radio { sendPacket(iv, 24, isRetransmit); } - uint32_t getDTUSn(void) { + uint32_t getDTUSn(void) const { return mDtuSn; } @@ -81,8 +79,8 @@ class Radio { protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; - virtual uint64_t getIvId(Inverter<> *iv) = 0; - virtual uint8_t getIvGen(Inverter<> *iv) = 0; + virtual uint64_t getIvId(Inverter<> *iv) const = 0; + virtual uint8_t getIvGen(Inverter<> *iv) const = 0; void initPacket(uint64_t ivId, uint8_t mid, uint8_t pid) { mTxBuf[0] = mid; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 48ff3750..2f0a5f31 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -14,8 +14,7 @@ class CmtRadio : public Radio { typedef Cmt2300a CmtType; public: CmtRadio() { - mDtuSn = DTU_SN; - mCmtAvail = false; + mDtuSn = DTU_SN; } void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { @@ -38,7 +37,7 @@ class CmtRadio : public Radio { return false; } - bool isChipConnected(void) { + bool isChipConnected(void) const { return mCmtAvail; } @@ -116,11 +115,11 @@ class CmtRadio : public Radio { iv->mDtuTxCnt++; } - uint64_t getIvId(Inverter<> *iv) { + uint64_t getIvId(Inverter<> *iv) const { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) { + uint8_t getIvGen(Inverter<> *iv) const { return iv->ivGen; } @@ -172,7 +171,7 @@ class CmtRadio : public Radio { } CmtType mCmt; - bool mCmtAvail; + bool mCmtAvail = false; bool mRqstGetRx = false; uint32_t mMillis; }; diff --git a/src/web/lang.json b/src/web/lang.json index 1eece937..9f3df46e 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -670,7 +670,7 @@ }, { "token": "INV_DELETE_SURE", - "en": "do you realy want to delete inverter?", + "en": "do you really want to delete inverter?", "de": "Willst du den Wechselrichter wirklich löschen?" }, { @@ -1070,7 +1070,7 @@ }, { "token": "WARN_DIFF_ENV", - "en": "your environment does not match the update file!", + "en": "your environment may not match the update file!", "de": "Die ausgewählte Firmware passt u.U. nicht zum Chipsatz!" }, { From d8af39820816baa94c919bb8127a5a1c63b758d8 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 25 Jan 2024 08:22:03 +0100 Subject: [PATCH 08/79] pendular version let rx channel change between tx+2 and tx+3 --- src/hm/Communication.h | 10 +++++----- src/hm/Heuristic.h | 4 ++-- src/hm/hmDefines.h | 8 ++++++++ src/hm/hmRadio.h | 13 ++++++------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 38925059..924356e0 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -186,8 +186,8 @@ class Communication : public CommQueue<> { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command if(parseFrame(p)) { q->iv->curFrmCnt++; - if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < 85) - mHeu.setIvRetriesGood(q->iv,p->millis < 70); + if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < LIMIT_FAST_IV) + mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV); } } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command if(parseDevCtrl(p, q)) @@ -259,7 +259,7 @@ class Communication : public CommQueue<> { if(framnr) { if(0 == q->attempts) { DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINTLN(F("no attempts left")); + DBGPRINTLN(F("timeout, no attempts left")); closeRequest(q, false); return; } @@ -424,8 +424,8 @@ class Communication : public CommQueue<> { } inline bool parseMiFrame(packet_t *p, const queue_s *q) { - if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < 35) //first frame is fast? - mHeu.setIvRetriesGood(q->iv,p->millis < 22); + if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < LIMIT_FAST_IV_MI) //first frame is fast? + mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV_MI); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 642eca13..3fb86614 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -159,9 +159,9 @@ class Heuristic { uint8_t getIvRetries(Inverter<> *iv) { if(iv->heuristics.rxSpeeds[0]) - return 5; + return RETRIES_VERYFAST_IV; if(iv->heuristics.rxSpeeds[1]) - return 10; + return RETRIES_FAST_IV; return 15; } diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 969e4e1b..9235b3f9 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -94,6 +94,14 @@ enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; #define DURATION_PAUSE_LASTFR 45 // how long to pause after last frame (ms) const uint8_t duration_reserve[2] = {115,115}; +#define LIMIT_FAST_IV 85 // time limit to qualify an inverter as very fast answering inverter +#define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter +#define LIMIT_FAST_IV_MI 35 // time limit to qualify a MI type inverter as fast answering inverter +#define LIMIT_VERYFAST_IV_MI 22 // time limit to qualify a MI type inverter as very fast answering inverter +#define RETRIES_FAST_IV 11 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter) +#define RETRIES_VERYFAST_IV 7 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter) + + typedef struct { uint8_t fieldId; // field id uint8_t unitId; // uint id diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 0df22f5a..81b27c57 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -124,7 +124,7 @@ class HmRadio : public Radio { rxPendular = !rxPendular; //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; - innerLoopTimeout = DURATION_LISTEN_MIN; + //innerLoopTimeout = DURATION_LISTEN_MIN; if(mNRFloopChannels) tempRxChIdx = (tempRxChIdx + 4) % RF_CHANNELS; @@ -154,7 +154,8 @@ class HmRadio : public Radio { if(tx_ok) mLastIv->mAckCount++; - mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + //mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + mRxChIdx = (mTxChIdx + 3) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); @@ -162,7 +163,8 @@ class HmRadio : public Radio { rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); - innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; + //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; + innerLoopTimeout = DURATION_LISTEN_MIN; } if(rx_ready) { @@ -186,10 +188,7 @@ class HmRadio : public Radio { } rx_ready = false; // reset return mNRFisInRX; - } /*else if(tx_fail) { - mNRFisInRX = false; - return false; - }*/ + } } return false; From 1118407019b7bc543b426a7384dd7828f77c0678 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 25 Jan 2024 11:10:44 +0100 Subject: [PATCH 09/79] retransmit review - look at how many frames are missing first - more "second try" if inverter is available (dependent on attempts) --- src/hm/CommQueue.h | 4 ++-- src/hm/Communication.h | 38 +++++++++++++++++++++++++++++--------- src/hm/hmDefines.h | 2 +- src/hm/hmInverter.h | 28 ++++++++++++++-------------- src/hm/radio.h | 2 +- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index d3fe1c69..227e8c33 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -12,8 +12,8 @@ #include "../utils/dbg.h" #define DEFAULT_ATTEMPS 5 -#define MORE_ATTEMPS_ALARMDATA 8 -#define MORE_ATTEMPS_GRIDONPROFILEPARA 5 +#define MORE_ATTEMPS_ALARMDATA 0 // 8 +#define MORE_ATTEMPS_GRIDONPROFILEPARA 0 // 5 template class CommQueue { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 924356e0..bc7f7236 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -114,11 +114,11 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.txCnt++; q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout); + if(!mIsRetransmit && (q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) + incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); mIsRetransmit = false; setAttempt(); - if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) - incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); mState = States::WAIT; break; @@ -155,7 +155,8 @@ class Communication : public CommQueue<> { q->iv->mIvTxCnt++; if(mFirstTry) { - mFirstTry = false; + if(q->attempts < 3 || !q->iv->isProducing()) + mFirstTry = false; //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. @@ -209,7 +210,7 @@ class Communication : public CommQueue<> { if(q->iv->ivGen != IV_MI) { mState = States::CHECK_PACKAGE; } else { - bool fastNext = true; + //bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; if((q->iv->radio->mRadioWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { @@ -222,11 +223,11 @@ class Communication : public CommQueue<> { || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); - fastNext = false; + //fastNext = false; } - if(fastNext) + /*if(fastNext) miNextRequest(q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, q); - else + else*/ closeRequest(q, true); } } @@ -263,6 +264,25 @@ class Communication : public CommQueue<> { closeRequest(q, false); return; } + //count missing frames + if(!q->iv->mIsSingleframeReq && q->iv->ivRadioType == INV_RADIO_TYPE_NRF) { // already checked? + uint8_t missedFrames = 0; + for(uint8_t i = 0; i < q->iv->radio->mFramesExpected; i++) { + if(mLocalBuf[i].len == 0) + missedFrames++; + } + if(missedFrames > 3 || (q->cmd == RealTimeRunData_Debug && missedFrames > 1) || (missedFrames > 1 && missedFrames + 2 > q->attempts)) { + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(String(missedFrames)); + DBGPRINT(F(" frames missing ")); + DBGPRINTLN(F("-> complete retransmit")); + } + mState = States::RESET; + return; + } + } + setAttempt(); if(*mSerialDebug) { @@ -411,8 +431,8 @@ class Communication : public CommQueue<> { if((*frameId & ALL_FRAMES) == ALL_FRAMES) { mMaxFrameId = (*frameId & 0x7f); - if(mMaxFrameId > 8) // large payloads, e.g. AlarmData - incrAttempt(mMaxFrameId - 6); + /*if(mMaxFrameId > 8) // large payloads, e.g. AlarmData + incrAttempt(mMaxFrameId - 6);*/ } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 9235b3f9..6bd66e66 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -92,7 +92,7 @@ enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; #define DURATION_TXFRAME 85 // timeout parameter for first transmission and first expected frame (time to first channel switch from tx start!) (ms) #define DURATION_LISTEN_MIN 5 // time to stay at least on a listening channel (ms) #define DURATION_PAUSE_LASTFR 45 // how long to pause after last frame (ms) -const uint8_t duration_reserve[2] = {115,115}; +const uint8_t duration_reserve[2] = {65,115}; #define LIMIT_FAST_IV 85 // time limit to qualify an inverter as very fast answering inverter #define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 049b5501..5ef3752d 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -220,21 +220,21 @@ class Inverter { cb(RealTimeRunData_Debug, false); // get live data } } else { // MI - if(0 == getFwVersion()) { - mIvRxCnt +=2; - cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number - } else { - record_t<> *rec = getRecordStruct(InverterDevInform_Simple); - if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) { - cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); + mGetLossInterval++; + if (type != INV_TYPE_4CH) + mIvRxCnt++; // statistics workaround... + if(isAvailable()) { + if(0 == getFwVersion()) { mIvRxCnt +=2; - } else if((getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec) == 0) && generalConfig->readGrid) // read grid profile - cb(0x10, false); // legacy GPF command - else { - cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); - mGetLossInterval++; - if (type != INV_TYPE_4CH) - mIvRxCnt++; // statistics workaround... + cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number + } else { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) { + cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + mIvRxCnt +=2; + } else if((getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec) == 0) && generalConfig->readGrid) // read grid profile + cb(0x10, false); // legacy GPF command } } } diff --git a/src/hm/radio.h b/src/hm/radio.h index e6baf792..ec087f47 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -79,6 +79,7 @@ class Radio { uint8_t mIrqOk = IRQ_UNKNOWN; TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) uint8_t mTxRetriesNext = 15; // let heuristics tell us the next reties count (for nRF type radios only) + uint8_t mFramesExpected = 0x0c; protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; @@ -130,7 +131,6 @@ class Radio { volatile bool mIrqRcvd; bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace; uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; - uint8_t mFramesExpected = 0x0c; }; #endif /*__RADIO_H__*/ From 626ca86d0d14a04f4cb1081fd25cabb9539e1636 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 26 Jan 2024 11:31:21 +0100 Subject: [PATCH 10/79] fix statistics - based on 0.8.65! --- src/hm/CommQueue.h | 6 ++---- src/hm/Communication.h | 41 ++++++++++++----------------------------- src/hm/hmRadio.h | 22 +++++----------------- src/hm/radio.h | 10 ++++------ src/hms/hmsRadio.h | 14 ++++++-------- 5 files changed, 29 insertions(+), 64 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 227e8c33..d7cc5642 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -18,8 +18,6 @@ template class CommQueue { public: - CommQueue() {} - void addImportant(Inverter<> *iv, uint8_t cmd) { dec(&mRdPtr); mQueue[mRdPtr] = queue_s(iv, cmd, true); @@ -34,12 +32,12 @@ class CommQueue { mQueue[mWrPtr] = queue_s(iv, cmd, false); } - uint8_t getFillState(void) { + uint8_t getFillState(void) const { //DPRINTLN(DBG_INFO, "wr: " + String(mWrPtr) + ", rd: " + String(mRdPtr)); return abs(mRdPtr - mWrPtr); } - uint8_t getMaxFill(void) { + uint8_t getMaxFill(void) const { return N; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index bc7f7236..bfb6a4df 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -83,6 +83,7 @@ class Communication : public CommQueue<> { q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; q->iv->curFrmCnt = 0; + q->iv->radioStatistics.txCnt++; mIsRetransmit = false; if(NULL == q->iv->radio) cmdDone(false); // can't communicate while radio is not defined! @@ -112,7 +113,7 @@ class Communication : public CommQueue<> { } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - q->iv->radioStatistics.txCnt++; + //q->iv->radioStatistics.txCnt++; q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout); if(!mIsRetransmit && (q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); @@ -129,22 +130,13 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) ) { // || (0 == q->attempts)) { // radio buffer empty or no more answers + if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) ) { // || (0 == q->attempts)) { // radio buffer empty. No more answers will be checked later if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); DBGPRINTLN(F("ms")); - /*if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { - DBGPRINT(F(", retries ")); - DBGPRINTLN(String(q->iv->radio->mTxRetriesNext)); - DBGPRINT(F(", ARC ")); - DBGPRINT(String(q->iv->radio->getARC())); - DBGPRINT(F(", PLOS ")); - DBGPRINTLN(String(q->iv->radio->getPLOS())); - } else - DBGPRINTLN("");*/ - } + } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); @@ -157,14 +149,13 @@ class Communication : public CommQueue<> { if(mFirstTry) { if(q->attempts < 3 || !q->iv->isProducing()) mFirstTry = false; - //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); + mHeu.getTxCh(q->iv); //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. - q->iv->radioStatistics.txCnt--; + //q->iv->radioStatistics.txCnt--; q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.stopTimeMonitor(); mState = States::START; - return; } } @@ -210,7 +201,6 @@ class Communication : public CommQueue<> { if(q->iv->ivGen != IV_MI) { mState = States::CHECK_PACKAGE; } else { - //bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; if((q->iv->radio->mRadioWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { @@ -223,12 +213,8 @@ class Communication : public CommQueue<> { || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); - //fastNext = false; } - /*if(fastNext) - miNextRequest(q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, q); - else*/ - closeRequest(q, true); + closeRequest(q, true); } } @@ -278,6 +264,8 @@ class Communication : public CommQueue<> { DBGPRINT(F(" frames missing ")); DBGPRINTLN(F("-> complete retransmit")); } + q->iv->radioStatistics.txCnt--; + q->iv->radioStatistics.retransmits++; mState = States::RESET; return; } @@ -318,11 +306,6 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - /*DBGPRINT(F(", ARC ")); - DBGPRINT(String(p->arc)); - DBGPRINT(F(", PLOS ")); - DBGPRINT(String(p->plos));*/ - DBGPRINT(F(" |")); if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { DBGPRINT(F(" CH")); if(3 == p->ch) @@ -555,7 +538,7 @@ class Communication : public CommQueue<> { len -= 2; - //DPRINT_IVID(DBG_INFO, q->iv->id); + //DPRINT_IVID(DBG_INFO, q->iv->id); // it's already above "for"-loop DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { @@ -856,8 +839,8 @@ class Communication : public CommQueue<> { DBGHEXLN(cmd); } - //if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7) - q->iv->radioStatistics.rxSuccess++; + /*if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7) + q->iv->radioStatistics.rxSuccess++;*/ q->iv->radioStatistics.ivSent++; mFramesExpected = getFramesExpected(q); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 81b27c57..bc1e3652 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -15,7 +15,6 @@ #endif #define SPI_SPEED 1000000 - #define RF_CHANNELS 5 const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; @@ -194,8 +193,7 @@ class HmRadio : public Radio { return false; } - bool isChipConnected(void) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); + bool isChipConnected(void) const { return mNrf24->isChipConnected(); } @@ -285,24 +283,16 @@ class HmRadio : public Radio { sendPacket(iv, cnt, isRetransmit, (IV_MI != iv->ivGen)); } - uint8_t getDataRate(void) { + uint8_t getDataRate(void) const { if(!mNrf24->isChipConnected()) return 3; // unknown return mNrf24->getDataRate(); } - bool isPVariant(void) { + bool isPVariant(void) const { return mNrf24->isPVariant(); } - /*uint8_t getARC(void) { - return mNrf24->getARC(); - } - - uint8_t getPLOS(void) { - return mNrf24->getPLOS(); - }*/ - private: inline bool getReceived(void) { bool isLastPackage = false; @@ -318,8 +308,6 @@ class HmRadio : public Radio { p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - //p.arc = mNrf24->getARC(); - //p.plos = mNrf24->getPLOS(); mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { @@ -411,11 +399,11 @@ class HmRadio : public Radio { mNRFisInRX = false; } - uint64_t getIvId(Inverter<> *iv) { + uint64_t getIvId(Inverter<> *iv) const { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) { + uint8_t getIvGen(Inverter<> *iv) const { return iv->ivGen; } diff --git a/src/hm/radio.h b/src/hm/radio.h index ec087f47..ea6d8c05 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -27,10 +27,8 @@ class Radio { virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } - virtual bool isChipConnected(void) { return false; } + virtual bool isChipConnected(void) const { return false; } virtual bool loop(void) = 0; - //virtual uint8_t getARC(void) { return 0xff; } - //virtual uint8_t getPLOS(void) { return 0xff; } void handleIntr(void) { mIrqRcvd = true; @@ -66,7 +64,7 @@ class Radio { sendPacket(iv, 24, isRetransmit); } - uint32_t getDTUSn(void) { + uint32_t getDTUSn(void) const { return mDtuSn; } @@ -83,8 +81,8 @@ class Radio { protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; - virtual uint64_t getIvId(Inverter<> *iv) = 0; - virtual uint8_t getIvGen(Inverter<> *iv) = 0; + virtual uint64_t getIvId(Inverter<> *iv) const = 0; + virtual uint8_t getIvGen(Inverter<> *iv) const = 0; void initPacket(uint64_t ivId, uint8_t mid, uint8_t pid) { mTxBuf[0] = mid; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 3c569e02..33b6a75c 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -14,8 +14,7 @@ class CmtRadio : public Radio { typedef Cmt2300a CmtType; public: CmtRadio() { - mDtuSn = DTU_SN; - mCmtAvail = false; + mDtuSn = DTU_SN; } void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { @@ -38,7 +37,7 @@ class CmtRadio : public Radio { return false; } - bool isChipConnected(void) { + bool isChipConnected(void) const { return mCmtAvail; } @@ -116,11 +115,11 @@ class CmtRadio : public Radio { iv->mDtuTxCnt++; } - uint64_t getIvId(Inverter<> *iv) { + uint64_t getIvId(Inverter<> *iv) const { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) { + uint8_t getIvGen(Inverter<> *iv) const { return iv->ivGen; } @@ -165,11 +164,10 @@ class CmtRadio : public Radio { if(CMT_SUCCESS == status) mBufCtrl.push(p); - // this code completly stops communication! if(p.packet[9] > ALL_FRAMES) // indicates last frame - // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... - //optionally instead: mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? + // optionally instead: + // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... } CmtType mCmt; From 19184727bc0251c26dc606c7be2e1f10404954a5 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sat, 27 Jan 2024 09:37:55 +0100 Subject: [PATCH 11/79] add data request to PowerLimit update req. --- src/hm/Communication.h | 11 ++++++++--- src/hm/hmInverter.h | 5 +++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index bfb6a4df..23ffe158 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -264,8 +264,10 @@ class Communication : public CommQueue<> { DBGPRINT(F(" frames missing ")); DBGPRINTLN(F("-> complete retransmit")); } + mHeu.evalTxChQuality(q->iv, false, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); q->iv->radioStatistics.txCnt--; q->iv->radioStatistics.retransmits++; + mCompleteRetry = true; mState = States::RESET; return; } @@ -511,6 +513,7 @@ class Communication : public CommQueue<> { } else DBGPRINTLN(F("-> complete retransmit")); + mCompleteRetry = true; mState = States::RESET; return; } @@ -611,7 +614,7 @@ class Communication : public CommQueue<> { mHeu.evalTxChQuality(q->iv, crcPass, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); if(crcPass) q->iv->radioStatistics.rxSuccess++; - else if(q->iv->mGotFragment) + else if(q->iv->mGotFragment || mCompleteRetry) q->iv->radioStatistics.rxFail++; // got no complete payload else q->iv->radioStatistics.rxFailNoAnser++; // got nothing @@ -626,6 +629,7 @@ class Communication : public CommQueue<> { q->iv->mGotLastMsg = false; q->iv->miMultiParts = 0; mIsRetransmit = false; + mCompleteRetry = false; mState = States::RESET; DBGPRINTLN(F("-----")); } @@ -1020,8 +1024,9 @@ class Communication : public CommQueue<> { uint16_t *mInverterGap; TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) std::array mLocalBuf; - bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we already had waited one complete cycle + bool mFirstTry = false; // see, if we should do a second try + bool mCompleteRetry = false; // remember if we did request a complete retransmission + bool mIsRetransmit = false; // we already had waited one complete cycle uint8_t mMaxFrameId; uint8_t mFramesExpected = 12; // 0x8c was highest last frame for alarm data uint16_t mTimeout = 0; // calculating that once should be ok diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 5ef3752d..bcf732ea 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -194,9 +194,10 @@ class Inverter { if(mNextLive) cb(RealTimeRunData_Debug, false); // get live data else { - if(actPowerLimit == 0xffff) + if(actPowerLimit == 0xffff) { cb(SystemConfigPara, false); // power limit info - else if(InitDataState != devControlCmd) { + cb(RealTimeRunData_Debug, false); + } else if(InitDataState != devControlCmd) { cb(devControlCmd, false); // custom command which was received by API devControlCmd = InitDataState; mGetLossInterval = 1; From 1b4b5874df3c7252c2a4b7dd7f681823b07d2f27 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sat, 27 Jan 2024 17:52:08 +0100 Subject: [PATCH 12/79] Individual rx-channel offset per inverter (based on serial, but unfortunately not working yet) --- src/hm/hmInverter.h | 2 +- src/hm/hmRadio.h | 9 ++++++--- src/hm/hmSystem.h | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index bcf732ea..00f05c79 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -133,6 +133,7 @@ class Inverter { bool isConnected; // shows if inverter was successfully identified (fw version and hardware info) InverterStatus status; // indicates the current inverter status std::array lastAlarm; // holds last 10 alarms + uint8_t rxOffset; // holds the default channel offset between tx and rx channel (nRF only) int8_t rssi; // RSSI uint16_t alarmCnt; // counts the total number of occurred alarms uint16_t alarmLastId; // lastId which was received @@ -179,7 +180,6 @@ class Inverter { tsMaxAcPower = 0; memset(&radioStatistics, 0, sizeof(statistics_t)); - memset(heuristics.txRfQuality, -6, 5); memset(mOffYD, 0, sizeof(float) * 6); memset(mLastYD, 0, sizeof(float) * 6); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index bc1e3652..fbb23b57 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -154,11 +154,11 @@ class HmRadio : public Radio { mLastIv->mAckCount++; //mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; - mRxChIdx = (mTxChIdx + 3) % RF_CHANNELS; + mRxChIdx = (mTxChIdx + mLastIv->rxOffset) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); - tempRxChIdx = mRxChIdx; + tempRxChIdx = mRxChIdx; // might be better to start off with one channel less? rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); @@ -369,7 +369,10 @@ class HmRadio : public Radio { DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(", ")); DBGPRINT(String(mTxRetriesNext)); - DBGPRINT(F(" retries | ")); + //DBGPRINT(F(" retries | ")); + DBGPRINT(F(" ret., rx offset: ")); + DBGPRINT(String(iv->rxOffset)); + DBGPRINT(F(" | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 8229378e..1e8641cb 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -28,6 +28,8 @@ class HmSystem { iv->config = &mInverter[0].generalConfig->iv[id]; DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX)); + //iv->rxOffset = 5 - (iv->config->serial.b[2] % 5); //RF_CHANNELS; + iv->rxOffset = (iv->config->serial.b[1] % 5); //RF_CHANNELS; if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 From dc696d727fa0eecff28e301febe1f3f72fe8a09f Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 28 Jan 2024 23:32:44 +0100 Subject: [PATCH 13/79] 0.8.66 * added support for other regions - untested #1271 * fix generation of DTU-ID; was computed twice without reset if two radios are enabled --- src/CHANGES.md | 4 + src/app.cpp | 2 +- src/config/settings.h | 14 ++- src/defines.h | 2 +- src/hm/Communication.h | 2 +- src/hm/hmDefines.h | 8 -- src/hm/hmInverter.h | 2 - src/hm/radio.h | 9 +- src/hms/cmt2300a.h | 259 +++++++++++++++++++++++++--------------- src/hms/hmsRadio.h | 34 ++++-- src/web/RestApi.h | 5 + src/web/html/setup.html | 25 +++- src/web/lang.json | 10 ++ src/web/web.h | 3 +- 14 files changed, 251 insertions(+), 128 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index b8547302..7f544e69 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.66 - 2024-01-28 +* added support for other regions - untested #1271 +* fix generation of DTU-ID; was computed twice without reset if two radios are enabled + ## 0.8.65 - 2024-01-24 * removed patch for NRF `PLOS` * fix lang issues #1388 diff --git a/src/app.cpp b/src/app.cpp index 9f569259..a14a8811 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -47,7 +47,7 @@ void app::setup() { } #if defined(ESP32) if(mConfig->cmt.enabled) { - mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb); + mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, mConfig->sys.region); } #endif #ifdef ETHERNET diff --git a/src/config/settings.h b/src/config/settings.h index d8c93b10..e074d5b1 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 9 +#define CONFIG_VERSION 10 #define PROT_MASK_INDEX 0x0001 @@ -68,6 +68,8 @@ typedef struct { uint16_t protectionMask; bool darkMode; bool schedReboot; + uint8_t region; + int8_t timezone; #if !defined(ETHERNET) // wifi @@ -395,6 +397,8 @@ class settings { #endif /* !defined(ETHERNET) */ snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME); + mCfg.sys.region = 0; // Europe + mCfg.sys.timezone = 1; mCfg.nrf.pinCs = DEF_NRF_CS_PIN; mCfg.nrf.pinCe = DEF_NRF_CE_PIN; @@ -512,6 +516,10 @@ class settings { if(mCfg.configVersion < 9) { mCfg.inst.gapMs = 1; } + if(mCfg.configVersion < 10) { + mCfg.sys.region = 0; // Europe + mCfg.sys.timezone = 1; + } } } @@ -537,6 +545,8 @@ class settings { obj[F("prot_mask")] = mCfg.sys.protectionMask; obj[F("dark")] = mCfg.sys.darkMode; obj[F("reb")] = (bool) mCfg.sys.schedReboot; + obj[F("region")] = mCfg.sys.region; + obj[F("timezone")] = mCfg.sys.timezone; ah::ip2Char(mCfg.sys.ip.ip, buf); obj[F("ip")] = String(buf); ah::ip2Char(mCfg.sys.ip.mask, buf); obj[F("mask")] = String(buf); ah::ip2Char(mCfg.sys.ip.dns1, buf); obj[F("dns1")] = String(buf); @@ -554,6 +564,8 @@ class settings { getVal(obj, F("prot_mask"), &mCfg.sys.protectionMask); getVal(obj, F("dark"), &mCfg.sys.darkMode); getVal(obj, F("reb"), &mCfg.sys.schedReboot); + getVal(obj, F("region"), &mCfg.sys.region); + getVal(obj, F("timezone"), &mCfg.sys.timezone); if(obj.containsKey(F("ip"))) ah::ip2Arr(mCfg.sys.ip.ip, obj[F("ip")].as()); if(obj.containsKey(F("mask"))) ah::ip2Arr(mCfg.sys.ip.mask, obj[F("mask")].as()); if(obj.containsKey(F("dns1"))) ah::ip2Arr(mCfg.sys.ip.dns1, obj[F("dns1")].as()); diff --git a/src/defines.h b/src/defines.h index ed975b7a..786908d0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 65 +#define VERSION_PATCH 66 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 3a6fdd0b..ae97dbb2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -138,7 +138,7 @@ class Communication : public CommQueue<> { } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); + q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000)); mWaitTime.startTimeMonitor(1000); } else { if(IV_MI == q->iv->ivGen) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 969e4e1b..8df06dc1 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -78,14 +78,6 @@ enum {CH0 = 0, CH1, CH2, CH3, CH4, CH5, CH6}; enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; -#define WORK_FREQ_KHZ 865000 // desired work frequency between DTU and - // inverter in kHz -#define HOY_BASE_FREQ_KHZ 860000 // in kHz -#define HOY_MAX_FREQ_KHZ 923500 // 0xFE * 250kHz + Base_freq -#define HOY_BOOT_FREQ_KHZ 868000 // Hoymiles boot/init frequency after power up inverter -#define FREQ_STEP_KHZ 250 // channel step size in kHz -#define FREQ_WARN_MIN_KHZ 863000 // for EU 863 - 870 MHz is allowed -#define FREQ_WARN_MAX_KHZ 870000 // for EU 863 - 870 MHz is allowed #define DURATION_ONEFRAME 50 // timeout parameter for each expected frame (ms) //#define DURATION_RESERVE {90,120} // timeout parameter to still wait after last expected frame (ms) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b28682e5..cc73cb0b 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -179,8 +179,6 @@ class Inverter { tsMaxAcPower = 0; memset(&radioStatistics, 0, sizeof(statistics_t)); - memset(heuristics.txRfQuality, -6, 5); - memset(mOffYD, 0, sizeof(float) * 6); memset(mLastYD, 0, sizeof(float) * 6); } diff --git a/src/hm/radio.h b/src/hm/radio.h index f7d61e42..907a2023 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -28,6 +28,9 @@ class Radio { virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual bool isChipConnected(void) const { return false; } + virtual uint16_t getBaseFreqMhz() { return 0; } + virtual uint16_t getBootFreqMhz() { return 0; } + virtual std::pair getFreqRangeMhz(void) { return std::make_pair(0, 0); } virtual bool loop(void) = 0; void handleIntr(void) { @@ -113,6 +116,7 @@ class Radio { chipID = ESP.getChipId(); #endif + mDtuSn = 0; uint8_t t; for(int i = 0; i < (7 << 2); i += 4) { t = (chipID >> i) & 0x0f; @@ -121,7 +125,8 @@ class Radio { mDtuSn |= (t << i); } mDtuSn |= 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal - } + } + uint32_t mDtuSn; volatile bool mIrqRcvd; diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 1ff112e2..524472f0 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -12,8 +12,23 @@ #include "esp32_3wSpi.h" #endif -// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf +#include + +enum class RegionCfg : uint8_t { + EUROPE, USA, BRAZIL, NUM +}; + +enum class CmtStatus : uint8_t { + SUCCESS = 0, + ERR_SWITCH_STATE, + ERR_TX_PENDING, + FIFO_EMPTY, + ERR_RX_IN_FIFO +}; + +#define FREQ_STEP_KHZ 250 // channel step size in kHz +// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf #define CMT2300A_MASK_CFG_RETAIN 0x10 #define CMT2300A_MASK_RSTN_IN_EN 0x20 #define CMT2300A_MASK_LOCKING_EN 0x20 @@ -152,67 +167,6 @@ #define CMT2300A_MASK_TX_DONE_FLG 0x08 #define CMT2300A_MASK_PKT_OK_FLG 0x01 -// this list and the TX5, TX10 registers were compiled from the output of -// HopeRF RFPDK Tool v1.54 -static uint8_t paLevelList[31][2] PROGMEM = { - {0x17, 0x01}, // -10dBm - {0x1a, 0x01}, // -09dBm - {0x1d, 0x01}, // -08dBm - {0x21, 0x01}, // -07dBm - {0x25, 0x01}, // -06dBm - {0x29, 0x01}, // -05dBm - {0x2d, 0x01}, // -04dBm - {0x33, 0x01}, // -03dBm - {0x39, 0x02}, // -02dBm - {0x41, 0x02}, // -01dBm - {0x4b, 0x02}, // 00dBm - {0x56, 0x03}, // 01dBm - {0x63, 0x03}, // 02dBm - {0x71, 0x04}, // 03dBm - {0x80, 0x04}, // 04dBm - {0x22, 0x01}, // 05dBm - {0x27, 0x04}, // 06dBm - {0x2c, 0x05}, // 07dBm - {0x31, 0x06}, // 08dBm - {0x38, 0x06}, // 09dBm - {0x3f, 0x07}, // 10dBm - {0x48, 0x08}, // 11dBm - {0x52, 0x09}, // 12dBm - {0x5d, 0x0b}, // 13dBm - {0x6a, 0x0c}, // 14dBm - {0x79, 0x0d}, // 15dBm - {0x46, 0x10}, // 16dBm - {0x51, 0x10}, // 17dBm - {0x60, 0x12}, // 18dBm - {0x71, 0x14}, // 19dBm - {0x8c, 0x1c} // 20dBm -}; - -// default CMT parameters -static uint8_t cmtConfig[0x60] PROGMEM { - // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm - 0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08, - 0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00, - // 0x10 - 0x1f - 0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81, - 0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default - // 0x20 - 0x2f - 0xA6, 0xC9, 0x20, 0x20, 0xD2, 0x35, 0x0C, 0x0A, - 0x9F, 0x4B, 0x29, 0x29, 0xC0, 0x14, 0x05, 0x53, - // 0x30 - 0x3f - 0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, - // 0x40 - 0x4f - 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, - // 0x50 - 0x5f - 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, - 0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // - TX 13dBm -}; - - -enum {CMT_SUCCESS = 0, CMT_ERR_SWITCH_STATE, CMT_ERR_TX_PENDING, CMT_FIFO_EMPTY, CMT_ERR_RX_IN_FIFO}; - class Cmt2300a { public: Cmt2300a() {} @@ -234,12 +188,12 @@ class Cmt2300a { } } - uint8_t goRx(void) { + CmtStatus goRx(void) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(mInRxMode) - return CMT_SUCCESS; + return CmtStatus::SUCCESS; mSpi.readReg(CMT2300A_CUS_INT1_CTL); mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); @@ -260,47 +214,47 @@ class Cmt2300a { mSpi.writeReg(0x16, 0x0C); // [4:3]: RSSI_DET_SEL, [2:0]: RSSI_AVG_MODE if(!cmtSwitchStatus(CMT2300A_GO_RX, CMT2300A_STA_RX)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mInRxMode = true; - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } - uint8_t getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) { + CmtStatus getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(0x1b != (mSpi.readReg(CMT2300A_CUS_INT_FLAG) & 0x1b)) - return CMT_FIFO_EMPTY; + return CmtStatus::FIFO_EMPTY; // receive ok (pream, sync, node, crc) if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mSpi.readFifo(buf, rxLen, maxlen); *rssi = mSpi.readReg(CMT2300A_CUS_RSSI_DBM) - 128; if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mInRxMode = false; mCusIntFlag = mSpi.readReg(CMT2300A_CUS_INT_FLAG); - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } - uint8_t tx(uint8_t buf[], uint8_t len) { + CmtStatus tx(uint8_t buf[], uint8_t len) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(mInRxMode) { mInRxMode = false; if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; } mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); @@ -325,16 +279,17 @@ class Cmt2300a { } if(!cmtSwitchStatus(CMT2300A_GO_TX, CMT2300A_STA_TX)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; // wait for tx done mTxPending = true; - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } // initialize CMT2300A, returns true on success - bool reset(void) { + bool reset(RegionCfg region) { + mRegionCfg = region; mSpi.writeReg(0x7f, 0xff); // soft reset delay(30); @@ -346,10 +301,19 @@ class Cmt2300a { if(mSpi.readReg(0x62) != 0x20) return false; // not connected! - for(uint8_t i = 0; i < 0x60; i++) { + for(uint8_t i = 0; i < 0x18; i++) { + mSpi.writeReg(i, cmtConfig[i]); + } + for(uint8_t i = 0; i < 8; i++) { + mSpi.writeReg(0x18 + i, mBaseFreqCfg[static_cast(region)][i]); + } + for(uint8_t i = 0x20; i < 0x60; i++) { mSpi.writeReg(i, cmtConfig[i]); } + if(RegionCfg::EUROPE != region) + mSpi.writeReg(0x27, 0x0B); + mSpi.writeReg(CMT2300A_CUS_IO_SEL, 0x20); // -> GPIO3_SEL[1:0] = 0x02 @@ -389,23 +353,14 @@ class Cmt2300a { } inline uint8_t freq2Chan(const uint32_t freqKhz) { - if((freqKhz % FREQ_STEP_KHZ) != 0) { - DPRINT(DBG_WARN, F("switch frequency to ")); - DBGPRINT(String(freqKhz)); - DBGPRINT(F("kHz not possible!")); + if((freqKhz % FREQ_STEP_KHZ) != 0) return 0xff; // error - // apply the nearest frequency - //freqKhz = (freqKhz + FREQ_STEP_KHZ/2) / FREQ_STEP_KHZ; - //freqKhz *= FREQ_STEP_KHZ; - } - if((freqKhz < HOY_BASE_FREQ_KHZ) || (freqKhz > HOY_MAX_FREQ_KHZ)) + std::pair range = getFreqRangeMhz(); + if((freqKhz < range.first) || (freqKhz > range.second)) return 0xff; // error - if((freqKhz < FREQ_WARN_MIN_KHZ) || (freqKhz > FREQ_WARN_MAX_KHZ)) - DPRINTLN(DBG_WARN, F("Desired frequency is out of EU legal range! (863 - 870MHz)")); - - return (freqKhz - HOY_BASE_FREQ_KHZ) / FREQ_STEP_KHZ; + return (freqKhz - getBaseFreqMhz()) / FREQ_STEP_KHZ; } inline void switchChannel(uint8_t ch) { @@ -414,9 +369,9 @@ class Cmt2300a { inline uint32_t getFreqKhz(void) { if(0xff != mRqstCh) - return HOY_BASE_FREQ_KHZ + (mRqstCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() + (mRqstCh * FREQ_STEP_KHZ); else - return HOY_BASE_FREQ_KHZ + (mCurCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() + (mCurCh * FREQ_STEP_KHZ); } uint8_t getCurrentChannel(void) { @@ -443,6 +398,114 @@ class Cmt2300a { mSpi.writeReg(CMT2300A_CUS_TX9, paLevelList[level][1]); } + public: + uint16_t getBaseFreqMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return 905; + case RegionCfg::BRAZIL: + return 915; + } + return 860; + } + + uint16_t getBootFreqMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return 915; + case RegionCfg::BRAZIL: + return 915; + } + return 868; + } + + std::pair getFreqRangeMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return std::make_pair(905, 925); + case RegionCfg::BRAZIL: + return std::make_pair(915, 928); + } + return std::make_pair(860, 870); // Europe + } + + private: + // this list and the TX5, TX10 registers were compiled from the output of + // HopeRF RFPDK Tool v1.54 + constexpr static uint8_t paLevelList[31][2] PROGMEM = { + {0x17, 0x01}, // -10dBm + {0x1a, 0x01}, // -09dBm + {0x1d, 0x01}, // -08dBm + {0x21, 0x01}, // -07dBm + {0x25, 0x01}, // -06dBm + {0x29, 0x01}, // -05dBm + {0x2d, 0x01}, // -04dBm + {0x33, 0x01}, // -03dBm + {0x39, 0x02}, // -02dBm + {0x41, 0x02}, // -01dBm + {0x4b, 0x02}, // 00dBm + {0x56, 0x03}, // 01dBm + {0x63, 0x03}, // 02dBm + {0x71, 0x04}, // 03dBm + {0x80, 0x04}, // 04dBm + {0x22, 0x01}, // 05dBm + {0x27, 0x04}, // 06dBm + {0x2c, 0x05}, // 07dBm + {0x31, 0x06}, // 08dBm + {0x38, 0x06}, // 09dBm + {0x3f, 0x07}, // 10dBm + {0x48, 0x08}, // 11dBm + {0x52, 0x09}, // 12dBm + {0x5d, 0x0b}, // 13dBm + {0x6a, 0x0c}, // 14dBm + {0x79, 0x0d}, // 15dBm + {0x46, 0x10}, // 16dBm + {0x51, 0x10}, // 17dBm + {0x60, 0x12}, // 18dBm + {0x71, 0x14}, // 19dBm + {0x8c, 0x1c} // 20dBm + }; + + // default CMT parameters + constexpr static uint8_t cmtConfig[0x60] PROGMEM { + // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm + 0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08, + 0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00, + // 0x10 - 0x1f + 0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81, + 0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default + // 0x20 - 0x2f + 0xA6, 0xC9, 0x20, 0x20, 0xD2, 0x35, 0x0C, 0x0A, + 0x9F, 0x4B, 0x29, 0x29, 0xC0, 0x14, 0x05, 0x53, + // 0x30 - 0x3f + 0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, + // 0x40 - 0x4f + 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, + // 0x50 - 0x5f + 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, + 0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // TX 13dBm + }; + + constexpr static uint8_t mBaseFreqCfg[static_cast(RegionCfg::NUM)][8] { + {0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12}, // 860MHz + {0x45, 0xA8, 0x31, 0x8A, 0x45, 0x9D, 0xD8, 0x19}, // 905MHz (USA, Indonesia) + {0x46, 0x6D, 0x80, 0x86, 0x46, 0x62, 0x27, 0x16} // 915MHz (Brazil) + }; + private: void init() { mTxPending = false; @@ -480,6 +543,7 @@ class Cmt2300a { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; } + private: #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) cmtHal mSpi; #else @@ -490,6 +554,7 @@ class Cmt2300a { bool mInRxMode; uint8_t mCusIntFlag; uint8_t mRqstCh, mCurCh; + RegionCfg mRegionCfg = RegionCfg::EUROPE; }; #endif /*__CMT2300A_H__*/ diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 2f0a5f31..beea5829 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -17,9 +17,9 @@ class CmtRadio : public Radio { mDtuSn = DTU_SN; } - void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { + void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, uint8_t region = 0, bool genDtuSn = true) { mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb); - reset(genDtuSn); + reset(genDtuSn, static_cast(region)); mPrivacyMode = privacyMode; mSerialDebug = serialDebug; mPrintWholeTrace = printWholeTrace; @@ -30,7 +30,7 @@ class CmtRadio : public Radio { if((!mIrqRcvd) && (!mRqstGetRx)) return false; getRx(); - if(CMT_SUCCESS == mCmt.goRx()) { + if(CmtStatus::SUCCESS == mCmt.goRx()) { mIrqRcvd = false; mRqstGetRx = false; } @@ -76,6 +76,18 @@ class CmtRadio : public Radio { return true; } + uint16_t getBaseFreqMhz(void) override { + return mCmt.getBaseFreqMhz(); + } + + uint16_t getBootFreqMhz(void) override { + return mCmt.getBootFreqMhz(); + } + + std::pair getFreqRangeMhz(void) override { + return mCmt.getFreqRangeMhz(); + } + private: void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { @@ -104,12 +116,12 @@ class CmtRadio : public Radio { } } - uint8_t status = mCmt.tx(mTxBuf, len); + CmtStatus status = mCmt.tx(mTxBuf, len); mMillis = millis(); - if(CMT_SUCCESS != status) { + if(CmtStatus::SUCCESS != status) { DPRINT(DBG_WARN, F("CMT TX failed, code: ")); - DBGPRINTLN(String(status)); - if(CMT_ERR_RX_IN_FIFO == status) + DBGPRINTLN(String(static_cast(status))); + if(CmtStatus::ERR_RX_IN_FIFO == status) mIrqRcvd = true; } iv->mDtuTxCnt++; @@ -123,10 +135,10 @@ class CmtRadio : public Radio { return iv->ivGen; } - inline void reset(bool genDtuSn) { + inline void reset(bool genDtuSn, RegionCfg region) { if(genDtuSn) generateDtuSn(); - if(!mCmt.reset()) { + if(!mCmt.reset(region)) { mCmtAvail = false; DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!")); } else { @@ -160,8 +172,8 @@ class CmtRadio : public Radio { inline void getRx(void) { packet_t p; p.millis = millis() - mMillis; - uint8_t status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); - if(CMT_SUCCESS == status) + CmtStatus status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); + if(CmtStatus::SUCCESS == status) mBufCtrl.push(p); // this code completly stops communication! diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 98e0afd2..9ec717c1 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -268,6 +268,8 @@ class RestApi { obj[F("menu_protEn")] = (bool) (strlen(mConfig->sys.adminPwd) > 0); obj[F("cst_lnk")] = String(mConfig->plugin.customLink); obj[F("cst_lnk_txt")] = String(mConfig->plugin.customLinkText); + obj[F("region")] = mConfig->sys.region; + obj[F("timezone")] = mConfig->sys.timezone; #if defined(ESP32) obj[F("esp_type")] = F("ESP32"); @@ -651,6 +653,9 @@ class RestApi { obj[F("fcsb")] = mConfig->cmt.pinFcsb; obj[F("gpio3")] = mConfig->cmt.pinIrq; obj[F("en")] = (bool) mConfig->cmt.enabled; + std::pair range = mRadioCmt->getFreqRangeMhz(); + obj[F("freq_min")] = range.first; + obj[F("freq_max")] = range.second; } void getRadioCmtInfo(JsonObject obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index b4c72069..d4f245ef 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -26,6 +26,14 @@
{#DARK_MODE_NOTE}
+
+
{#REGION}
+
+
+
+
{#TIMEZONE}
+
+
{#CUSTOM_LINK}
@@ -499,9 +507,6 @@ for(var i = 0; i < 31; i++) { esp32cmtPa.push([i, String(i-10) + " dBm"]); } - for(var i = 12; i < 41; i++) { - esp32cmtFreq.push([i, freqFmt.format(860 + i*0.25) + " MHz"]); - } /*ENDIF_ESP32*/ var led_high_active = [ [0, "{#PIN_LOW_ACTIVE}"], @@ -650,6 +655,14 @@ el.push(mlCb("protMask" + i, a[i], chk)) } d.append(...el); + + var tz = [] + for(i = 0; i < 24; i += 0.5) + tz.push([i, ((i-12 > 0) ? "+" : "") + String(i-12)]); + document.getElementById("timezone").append(sel("timezone", tz, obj.timezone + 12)) + var region = [[0, "Europe (860 - 870 MHz)"], [1, "USA, Indonesia (905 - 925 MHz)"], [2, "Brazil (915 - 928 MHz)"]] + document.getElementById("region").append(sel("region", region, obj.region)) + } function parseGeneric(obj) { @@ -1019,6 +1032,12 @@ ]) ); } + + var i = 0 + while(obj.freq_max >= (obj.freq_min + i * 0.25)) { + esp32cmtFreq.push([i, freqFmt.format(obj.freq_min + i * 0.25) + " MHz"]) + i++ + } } /*ENDIF_ESP32*/ diff --git a/src/web/lang.json b/src/web/lang.json index 9f3df46e..d083ddff 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -148,6 +148,16 @@ "en": "(empty browser cache or use CTRL + F5 after reboot to apply this setting)", "de": "(der Browser-Cache muss geleert oder STRG + F5 gedrückt werden, um diese Einstellung zu aktivieren)" }, + { + "token": "REGION", + "en": "Region", + "de": "Region" + }, + { + "token": "TIMEZONE", + "en": "Timezone", + "de": "Zeitzone" + }, { "token": "CUSTOM_LINK", "en": "Custom link (leave empty to hide element in navigation)", diff --git a/src/web/web.h b/src/web/web.h index ba4540b1..6de9c877 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -481,7 +481,8 @@ class Web { request->arg("device").toCharArray(mConfig->sys.deviceName, DEVNAME_LEN); mConfig->sys.darkMode = (request->arg("darkMode") == "on"); mConfig->sys.schedReboot = (request->arg("schedReboot") == "on"); - + mConfig->sys.region = (request->arg("region")).toInt(); + mConfig->sys.timezone = (request->arg("timezone")).toInt() - 12; if (request->arg("cstLnk") != "") { request->arg("cstLnk").toCharArray(mConfig->plugin.customLink, MAX_CUSTOM_LINK_LEN); From 7655abc805e2ef7aaf8f95f423fea7f607f49269 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 28 Jan 2024 23:39:04 +0100 Subject: [PATCH 14/79] 0.8.66 fix compile --- src/hm/Communication.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index ae97dbb2..132faeb8 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -138,8 +138,10 @@ class Communication : public CommQueue<> { } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { + #if defined(ESP32) q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000)); mWaitTime.startTimeMonitor(1000); + #endif } else { if(IV_MI == q->iv->ivGen) q->iv->mIvTxCnt++; From 6b305651affcb4753699b935ff8c3c1eb32d2622 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 29 Jan 2024 09:28:17 +0100 Subject: [PATCH 15/79] 0.8.67 * fix HMS frequency * fix display of inverter id in serial log (was displayed twice) --- src/CHANGES.md | 6 +++++- src/defines.h | 2 +- src/hm/Communication.h | 1 - src/hms/cmt2300a.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 7f544e69..651d068d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.67 - 2024-01-29 +* fix HMS frequency +* fix display of inverter id in serial log (was displayed twice) + ## 0.8.66 - 2024-01-28 * added support for other regions - untested #1271 * fix generation of DTU-ID; was computed twice without reset if two radios are enabled @@ -169,7 +173,7 @@ ## 0.8.37 - 2023-12-30 * added grid profiles -* format version of grid profile +* format version of grid profile # RELEASE 0.8.36 - 2023-12-30 diff --git a/src/defines.h b/src/defines.h index 786908d0..4ff2fc1e 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 66 +#define VERSION_PATCH 67 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 132faeb8..396a98a5 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -502,7 +502,6 @@ class Communication : public CommQueue<> { int8_t rssi = -127; uint8_t len = 0; - DPRINT_IVID(DBG_INFO, q->iv->id); for(uint8_t i = 0; i < mMaxFrameId; i++) { if(mLocalBuf[i].len + len > MAX_BUFFER) { DPRINTLN(DBG_ERROR, F("payload buffer to small!")); diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 524472f0..3cdc2660 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -360,7 +360,7 @@ class Cmt2300a { if((freqKhz < range.first) || (freqKhz > range.second)) return 0xff; // error - return (freqKhz - getBaseFreqMhz()) / FREQ_STEP_KHZ; + return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ; } inline void switchChannel(uint8_t ch) { @@ -369,9 +369,9 @@ class Cmt2300a { inline uint32_t getFreqKhz(void) { if(0xff != mRqstCh) - return getBaseFreqMhz() + (mRqstCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() * 1000 + (mRqstCh * FREQ_STEP_KHZ); else - return getBaseFreqMhz() + (mCurCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() * 1000 + (mCurCh * FREQ_STEP_KHZ); } uint8_t getCurrentChannel(void) { From e5ce1f5094592dd50ae890c440b0806eef6c044b Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Mon, 29 Jan 2024 16:44:26 +0100 Subject: [PATCH 16/79] individualize rx offset for nRF --- src/hm/Communication.h | 7 +- src/hm/HeuristicInv.h | 2 +- src/hm/hmDefines.h | 8 -- src/hm/hmInverter.h | 1 - src/hm/hmRadio.h | 14 ++- src/hm/hmSystem.h | 3 +- src/hm/radio.h | 7 +- src/hms/cmt2300a.h | 259 ++++++++++++++++++++++++++--------------- src/hms/hmsRadio.h | 36 ++++-- 9 files changed, 209 insertions(+), 128 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 23ffe158..9219bb8e 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -139,8 +139,10 @@ class Communication : public CommQueue<> { } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); + #if defined(ESP32) + q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000)); mWaitTime.startTimeMonitor(1000); + #endif } else { mHeu.setIvRetriesBad(q->iv); if(IV_MI == q->iv->ivGen) @@ -526,7 +528,6 @@ class Communication : public CommQueue<> { int8_t rssi = -127; uint8_t len = 0; - DPRINT_IVID(DBG_INFO, q->iv->id); for(uint8_t i = 0; i < mMaxFrameId; i++) { if(mLocalBuf[i].len + len > MAX_BUFFER) { DPRINTLN(DBG_ERROR, F("payload buffer to small!")); @@ -541,7 +542,7 @@ class Communication : public CommQueue<> { len -= 2; - //DPRINT_IVID(DBG_INFO, q->iv->id); // it's already above "for"-loop + DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index fc782a7b..e9c7084e 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -14,7 +14,7 @@ class HeuristicInv { public: HeuristicInv() { - memset(txRfQuality, -6, RF_MAX_CHANNEL_ID); + memset(txRfQuality, 0, RF_MAX_CHANNEL_ID); } public: diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 6bd66e66..4705c061 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -78,14 +78,6 @@ enum {CH0 = 0, CH1, CH2, CH3, CH4, CH5, CH6}; enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; -#define WORK_FREQ_KHZ 865000 // desired work frequency between DTU and - // inverter in kHz -#define HOY_BASE_FREQ_KHZ 860000 // in kHz -#define HOY_MAX_FREQ_KHZ 923500 // 0xFE * 250kHz + Base_freq -#define HOY_BOOT_FREQ_KHZ 868000 // Hoymiles boot/init frequency after power up inverter -#define FREQ_STEP_KHZ 250 // channel step size in kHz -#define FREQ_WARN_MIN_KHZ 863000 // for EU 863 - 870 MHz is allowed -#define FREQ_WARN_MAX_KHZ 870000 // for EU 863 - 870 MHz is allowed #define DURATION_ONEFRAME 50 // timeout parameter for each expected frame (ms) //#define DURATION_RESERVE {90,120} // timeout parameter to still wait after last expected frame (ms) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 00f05c79..a74ad02f 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -180,7 +180,6 @@ class Inverter { tsMaxAcPower = 0; memset(&radioStatistics, 0, sizeof(statistics_t)); - memset(mOffYD, 0, sizeof(float) * 6); memset(mLastYD, 0, sizeof(float) * 6); } diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index fbb23b57..e759576c 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -118,7 +118,7 @@ class HmRadio : public Radio { // otherwise switch to next RX channel mTimeslotStart = millis(); - if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME+DURATION_ONEFRAME))) + if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME))) //(DURATION_TXFRAME+DURATION_ONEFRAME))) mNRFloopChannels = true; rxPendular = !rxPendular; @@ -163,7 +163,7 @@ class HmRadio : public Radio { mNRFloopChannels = (mLastIv->ivGen == IV_MI); //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; - innerLoopTimeout = DURATION_LISTEN_MIN; + innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; } if(rx_ready) { @@ -324,7 +324,13 @@ class HmRadio : public Radio { if(mLastIv->mIsSingleframeReq) // we only expect one frame here... isRetransmitAnswer = true; if(isLastPackage) - mFramesExpected = p.packet[9] - ALL_FRAMES; + setExpectedFrames(p.packet[9] - ALL_FRAMES); + if(p.packet[9] == 1 && p.millis < DURATION_ONEFRAME) + mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS; + else if(mNRFloopChannels && mLastIv->rxOffset > RF_CHANNELS) { // unsure setting? + mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset + mNRFloopChannels = false; + } } if(IV_MI == mLastIv->ivGen) { @@ -332,6 +338,8 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && isLastPackage = true; // response from dev control command + if(p.packet[9] == 0x00 && p.millis < DURATION_ONEFRAME) + mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS; } rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads } diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 1e8641cb..26d0ea5d 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -28,8 +28,7 @@ class HmSystem { iv->config = &mInverter[0].generalConfig->iv[id]; DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX)); - //iv->rxOffset = 5 - (iv->config->serial.b[2] % 5); //RF_CHANNELS; - iv->rxOffset = (iv->config->serial.b[1] % 5); //RF_CHANNELS; + iv->rxOffset = 13; // effective 3, but can easily be recognized as default setting if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 diff --git a/src/hm/radio.h b/src/hm/radio.h index ea6d8c05..9702c304 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -28,6 +28,9 @@ class Radio { virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual bool isChipConnected(void) const { return false; } + virtual uint16_t getBaseFreqMhz() { return 0; } + virtual uint16_t getBootFreqMhz() { return 0; } + virtual std::pair getFreqRangeMhz(void) { return std::make_pair(0, 0); } virtual bool loop(void) = 0; void handleIntr(void) { @@ -115,6 +118,7 @@ class Radio { chipID = ESP.getChipId(); #endif + mDtuSn = 0; uint8_t t; for(int i = 0; i < (7 << 2); i += 4) { t = (chipID >> i) & 0x0f; @@ -125,6 +129,7 @@ class Radio { mDtuSn |= 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal } + uint32_t mDtuSn; volatile bool mIrqRcvd; bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace; diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 1ff112e2..3cdc2660 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -12,8 +12,23 @@ #include "esp32_3wSpi.h" #endif -// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf +#include + +enum class RegionCfg : uint8_t { + EUROPE, USA, BRAZIL, NUM +}; + +enum class CmtStatus : uint8_t { + SUCCESS = 0, + ERR_SWITCH_STATE, + ERR_TX_PENDING, + FIFO_EMPTY, + ERR_RX_IN_FIFO +}; + +#define FREQ_STEP_KHZ 250 // channel step size in kHz +// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf #define CMT2300A_MASK_CFG_RETAIN 0x10 #define CMT2300A_MASK_RSTN_IN_EN 0x20 #define CMT2300A_MASK_LOCKING_EN 0x20 @@ -152,67 +167,6 @@ #define CMT2300A_MASK_TX_DONE_FLG 0x08 #define CMT2300A_MASK_PKT_OK_FLG 0x01 -// this list and the TX5, TX10 registers were compiled from the output of -// HopeRF RFPDK Tool v1.54 -static uint8_t paLevelList[31][2] PROGMEM = { - {0x17, 0x01}, // -10dBm - {0x1a, 0x01}, // -09dBm - {0x1d, 0x01}, // -08dBm - {0x21, 0x01}, // -07dBm - {0x25, 0x01}, // -06dBm - {0x29, 0x01}, // -05dBm - {0x2d, 0x01}, // -04dBm - {0x33, 0x01}, // -03dBm - {0x39, 0x02}, // -02dBm - {0x41, 0x02}, // -01dBm - {0x4b, 0x02}, // 00dBm - {0x56, 0x03}, // 01dBm - {0x63, 0x03}, // 02dBm - {0x71, 0x04}, // 03dBm - {0x80, 0x04}, // 04dBm - {0x22, 0x01}, // 05dBm - {0x27, 0x04}, // 06dBm - {0x2c, 0x05}, // 07dBm - {0x31, 0x06}, // 08dBm - {0x38, 0x06}, // 09dBm - {0x3f, 0x07}, // 10dBm - {0x48, 0x08}, // 11dBm - {0x52, 0x09}, // 12dBm - {0x5d, 0x0b}, // 13dBm - {0x6a, 0x0c}, // 14dBm - {0x79, 0x0d}, // 15dBm - {0x46, 0x10}, // 16dBm - {0x51, 0x10}, // 17dBm - {0x60, 0x12}, // 18dBm - {0x71, 0x14}, // 19dBm - {0x8c, 0x1c} // 20dBm -}; - -// default CMT parameters -static uint8_t cmtConfig[0x60] PROGMEM { - // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm - 0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08, - 0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00, - // 0x10 - 0x1f - 0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81, - 0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default - // 0x20 - 0x2f - 0xA6, 0xC9, 0x20, 0x20, 0xD2, 0x35, 0x0C, 0x0A, - 0x9F, 0x4B, 0x29, 0x29, 0xC0, 0x14, 0x05, 0x53, - // 0x30 - 0x3f - 0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, - // 0x40 - 0x4f - 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, - // 0x50 - 0x5f - 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, - 0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // - TX 13dBm -}; - - -enum {CMT_SUCCESS = 0, CMT_ERR_SWITCH_STATE, CMT_ERR_TX_PENDING, CMT_FIFO_EMPTY, CMT_ERR_RX_IN_FIFO}; - class Cmt2300a { public: Cmt2300a() {} @@ -234,12 +188,12 @@ class Cmt2300a { } } - uint8_t goRx(void) { + CmtStatus goRx(void) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(mInRxMode) - return CMT_SUCCESS; + return CmtStatus::SUCCESS; mSpi.readReg(CMT2300A_CUS_INT1_CTL); mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); @@ -260,47 +214,47 @@ class Cmt2300a { mSpi.writeReg(0x16, 0x0C); // [4:3]: RSSI_DET_SEL, [2:0]: RSSI_AVG_MODE if(!cmtSwitchStatus(CMT2300A_GO_RX, CMT2300A_STA_RX)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mInRxMode = true; - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } - uint8_t getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) { + CmtStatus getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(0x1b != (mSpi.readReg(CMT2300A_CUS_INT_FLAG) & 0x1b)) - return CMT_FIFO_EMPTY; + return CmtStatus::FIFO_EMPTY; // receive ok (pream, sync, node, crc) if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mSpi.readFifo(buf, rxLen, maxlen); *rssi = mSpi.readReg(CMT2300A_CUS_RSSI_DBM) - 128; if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mInRxMode = false; mCusIntFlag = mSpi.readReg(CMT2300A_CUS_INT_FLAG); - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } - uint8_t tx(uint8_t buf[], uint8_t len) { + CmtStatus tx(uint8_t buf[], uint8_t len) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(mInRxMode) { mInRxMode = false; if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; } mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); @@ -325,16 +279,17 @@ class Cmt2300a { } if(!cmtSwitchStatus(CMT2300A_GO_TX, CMT2300A_STA_TX)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; // wait for tx done mTxPending = true; - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } // initialize CMT2300A, returns true on success - bool reset(void) { + bool reset(RegionCfg region) { + mRegionCfg = region; mSpi.writeReg(0x7f, 0xff); // soft reset delay(30); @@ -346,10 +301,19 @@ class Cmt2300a { if(mSpi.readReg(0x62) != 0x20) return false; // not connected! - for(uint8_t i = 0; i < 0x60; i++) { + for(uint8_t i = 0; i < 0x18; i++) { + mSpi.writeReg(i, cmtConfig[i]); + } + for(uint8_t i = 0; i < 8; i++) { + mSpi.writeReg(0x18 + i, mBaseFreqCfg[static_cast(region)][i]); + } + for(uint8_t i = 0x20; i < 0x60; i++) { mSpi.writeReg(i, cmtConfig[i]); } + if(RegionCfg::EUROPE != region) + mSpi.writeReg(0x27, 0x0B); + mSpi.writeReg(CMT2300A_CUS_IO_SEL, 0x20); // -> GPIO3_SEL[1:0] = 0x02 @@ -389,23 +353,14 @@ class Cmt2300a { } inline uint8_t freq2Chan(const uint32_t freqKhz) { - if((freqKhz % FREQ_STEP_KHZ) != 0) { - DPRINT(DBG_WARN, F("switch frequency to ")); - DBGPRINT(String(freqKhz)); - DBGPRINT(F("kHz not possible!")); + if((freqKhz % FREQ_STEP_KHZ) != 0) return 0xff; // error - // apply the nearest frequency - //freqKhz = (freqKhz + FREQ_STEP_KHZ/2) / FREQ_STEP_KHZ; - //freqKhz *= FREQ_STEP_KHZ; - } - if((freqKhz < HOY_BASE_FREQ_KHZ) || (freqKhz > HOY_MAX_FREQ_KHZ)) + std::pair range = getFreqRangeMhz(); + if((freqKhz < range.first) || (freqKhz > range.second)) return 0xff; // error - if((freqKhz < FREQ_WARN_MIN_KHZ) || (freqKhz > FREQ_WARN_MAX_KHZ)) - DPRINTLN(DBG_WARN, F("Desired frequency is out of EU legal range! (863 - 870MHz)")); - - return (freqKhz - HOY_BASE_FREQ_KHZ) / FREQ_STEP_KHZ; + return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ; } inline void switchChannel(uint8_t ch) { @@ -414,9 +369,9 @@ class Cmt2300a { inline uint32_t getFreqKhz(void) { if(0xff != mRqstCh) - return HOY_BASE_FREQ_KHZ + (mRqstCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() * 1000 + (mRqstCh * FREQ_STEP_KHZ); else - return HOY_BASE_FREQ_KHZ + (mCurCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() * 1000 + (mCurCh * FREQ_STEP_KHZ); } uint8_t getCurrentChannel(void) { @@ -443,6 +398,114 @@ class Cmt2300a { mSpi.writeReg(CMT2300A_CUS_TX9, paLevelList[level][1]); } + public: + uint16_t getBaseFreqMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return 905; + case RegionCfg::BRAZIL: + return 915; + } + return 860; + } + + uint16_t getBootFreqMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return 915; + case RegionCfg::BRAZIL: + return 915; + } + return 868; + } + + std::pair getFreqRangeMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return std::make_pair(905, 925); + case RegionCfg::BRAZIL: + return std::make_pair(915, 928); + } + return std::make_pair(860, 870); // Europe + } + + private: + // this list and the TX5, TX10 registers were compiled from the output of + // HopeRF RFPDK Tool v1.54 + constexpr static uint8_t paLevelList[31][2] PROGMEM = { + {0x17, 0x01}, // -10dBm + {0x1a, 0x01}, // -09dBm + {0x1d, 0x01}, // -08dBm + {0x21, 0x01}, // -07dBm + {0x25, 0x01}, // -06dBm + {0x29, 0x01}, // -05dBm + {0x2d, 0x01}, // -04dBm + {0x33, 0x01}, // -03dBm + {0x39, 0x02}, // -02dBm + {0x41, 0x02}, // -01dBm + {0x4b, 0x02}, // 00dBm + {0x56, 0x03}, // 01dBm + {0x63, 0x03}, // 02dBm + {0x71, 0x04}, // 03dBm + {0x80, 0x04}, // 04dBm + {0x22, 0x01}, // 05dBm + {0x27, 0x04}, // 06dBm + {0x2c, 0x05}, // 07dBm + {0x31, 0x06}, // 08dBm + {0x38, 0x06}, // 09dBm + {0x3f, 0x07}, // 10dBm + {0x48, 0x08}, // 11dBm + {0x52, 0x09}, // 12dBm + {0x5d, 0x0b}, // 13dBm + {0x6a, 0x0c}, // 14dBm + {0x79, 0x0d}, // 15dBm + {0x46, 0x10}, // 16dBm + {0x51, 0x10}, // 17dBm + {0x60, 0x12}, // 18dBm + {0x71, 0x14}, // 19dBm + {0x8c, 0x1c} // 20dBm + }; + + // default CMT parameters + constexpr static uint8_t cmtConfig[0x60] PROGMEM { + // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm + 0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08, + 0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00, + // 0x10 - 0x1f + 0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81, + 0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default + // 0x20 - 0x2f + 0xA6, 0xC9, 0x20, 0x20, 0xD2, 0x35, 0x0C, 0x0A, + 0x9F, 0x4B, 0x29, 0x29, 0xC0, 0x14, 0x05, 0x53, + // 0x30 - 0x3f + 0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, + // 0x40 - 0x4f + 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, + // 0x50 - 0x5f + 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, + 0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // TX 13dBm + }; + + constexpr static uint8_t mBaseFreqCfg[static_cast(RegionCfg::NUM)][8] { + {0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12}, // 860MHz + {0x45, 0xA8, 0x31, 0x8A, 0x45, 0x9D, 0xD8, 0x19}, // 905MHz (USA, Indonesia) + {0x46, 0x6D, 0x80, 0x86, 0x46, 0x62, 0x27, 0x16} // 915MHz (Brazil) + }; + private: void init() { mTxPending = false; @@ -480,6 +543,7 @@ class Cmt2300a { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; } + private: #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) cmtHal mSpi; #else @@ -490,6 +554,7 @@ class Cmt2300a { bool mInRxMode; uint8_t mCusIntFlag; uint8_t mRqstCh, mCurCh; + RegionCfg mRegionCfg = RegionCfg::EUROPE; }; #endif /*__CMT2300A_H__*/ diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 33b6a75c..07afd4b8 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -17,9 +17,9 @@ class CmtRadio : public Radio { mDtuSn = DTU_SN; } - void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { + void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, uint8_t region = 0, bool genDtuSn = true) { mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb); - reset(genDtuSn); + reset(genDtuSn, static_cast(region)); mPrivacyMode = privacyMode; mSerialDebug = serialDebug; mPrintWholeTrace = printWholeTrace; @@ -30,7 +30,7 @@ class CmtRadio : public Radio { if((!mIrqRcvd) && (!mRqstGetRx)) return false; getRx(); - if(CMT_SUCCESS == mCmt.goRx()) { + if(CmtStatus::SUCCESS == mCmt.goRx()) { mIrqRcvd = false; mRqstGetRx = false; } @@ -76,6 +76,18 @@ class CmtRadio : public Radio { return true; } +uint16_t getBaseFreqMhz(void) override { + return mCmt.getBaseFreqMhz(); + } + + uint16_t getBootFreqMhz(void) override { + return mCmt.getBootFreqMhz(); + } + + std::pair getFreqRangeMhz(void) override { + return mCmt.getFreqRangeMhz(); + } + private: void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { @@ -104,12 +116,12 @@ class CmtRadio : public Radio { } } - uint8_t status = mCmt.tx(mTxBuf, len); + CmtStatus status = mCmt.tx(mTxBuf, len); mMillis = millis(); - if(CMT_SUCCESS != status) { + if(CmtStatus::SUCCESS != status) { DPRINT(DBG_WARN, F("CMT TX failed, code: ")); - DBGPRINTLN(String(status)); - if(CMT_ERR_RX_IN_FIFO == status) + DBGPRINTLN(String(static_cast(status))); + if(CmtStatus::ERR_RX_IN_FIFO == status) mIrqRcvd = true; } iv->mDtuTxCnt++; @@ -123,10 +135,10 @@ class CmtRadio : public Radio { return iv->ivGen; } - inline void reset(bool genDtuSn) { + inline void reset(bool genDtuSn, RegionCfg region) { if(genDtuSn) generateDtuSn(); - if(!mCmt.reset()) { + if(!mCmt.reset(region)) { mCmtAvail = false; DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!")); } else { @@ -160,8 +172,8 @@ class CmtRadio : public Radio { inline void getRx(void) { packet_t p; p.millis = millis() - mMillis; - uint8_t status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); - if(CMT_SUCCESS == status) + CmtStatus status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); + if(CmtStatus::SUCCESS == status) mBufCtrl.push(p); if(p.packet[9] > ALL_FRAMES) // indicates last frame @@ -171,7 +183,7 @@ class CmtRadio : public Radio { } CmtType mCmt; - bool mCmtAvail; + bool mCmtAvail = false; bool mRqstGetRx = false; uint32_t mMillis; }; From 163a9e485ef7f01cd85548d41aeb575fbc15146b Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 29 Jan 2024 21:51:49 +0100 Subject: [PATCH 17/79] 0.8.68 * fix HMS / HMT startup * added `flush_rx` to NRF on TX * start with heuristics set to `0` * added warning for WiFi channel 12-14 (ESP8266 only) #1381 --- src/CHANGES.md | 6 ++++++ src/app.h | 4 ++++ src/appInterface.h | 1 + src/defines.h | 2 +- src/hm/Communication.h | 5 ++++- src/hm/HeuristicInv.h | 19 +++++++++++++++++-- src/hm/hmInverter.h | 9 +++++++++ src/hm/hmRadio.h | 26 ++++++++++++++------------ src/hms/cmt2300a.h | 6 +++--- src/web/RestApi.h | 6 ++++++ src/web/lang.h | 6 ++++++ src/wifi/ahoywifi.cpp | 2 ++ src/wifi/ahoywifi.h | 5 +++++ 13 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 651d068d..f690b192 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,11 @@ # Development Changes +## 0.8.68 - 2024-01-29 +* fix HMS / HMT startup +* added `flush_rx` to NRF on TX +* start with heuristics set to `0` +* added warning for WiFi channel 12-14 (ESP8266 only) #1381 + ## 0.8.67 - 2024-01-29 * fix HMS frequency * fix display of inverter id in serial log (was displayed twice) diff --git a/src/app.h b/src/app.h index 851ad3c8..ccf46297 100644 --- a/src/app.h +++ b/src/app.h @@ -182,6 +182,10 @@ class app : public IApp, public ah::Scheduler { return mWifi.getStationIp(); } + bool getWasInCh12to14(void) const { + return mWifi.getWasInCh12to14(); + } + #endif /* !defined(ETHERNET) */ void setRebootFlag() { diff --git a/src/appInterface.h b/src/appInterface.h index ad38f756..f98fb0cb 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -35,6 +35,7 @@ class IApp { virtual void setupStation(void) = 0; virtual void setStopApAllowedMode(bool allowed) = 0; virtual String getStationIp(void) = 0; + virtual bool getWasInCh12to14(void) const = 0; #endif /* defined(ETHERNET) */ virtual uint32_t getUptime() = 0; diff --git a/src/defines.h b/src/defines.h index 4ff2fc1e..442008ff 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 67 +#define VERSION_PATCH 68 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 396a98a5..b74f689d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -139,7 +139,10 @@ class Communication : public CommQueue<> { if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { #if defined(ESP32) - q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000)); + if(!q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000))) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("switch frequency failed!")); + } mWaitTime.startTimeMonitor(1000); #endif } else { diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index e7ad6edd..0391e758 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -14,7 +14,22 @@ class HeuristicInv { public: HeuristicInv() { - memset(txRfQuality, -6, RF_MAX_CHANNEL_ID); + clear(); + } + + void clear() { + memset(txRfQuality, 0, RF_MAX_CHANNEL_ID); + txRfChId = 0; + lastBestTxChId = 0; + testPeriodSendCnt = 0; + testPeriodFailCnt = 0; + testChId = 0; + saveOldTestQuality = -6; + lastRxFragments = 0; + } + + bool isTxAtMax(void) const { + return (RF_MAX_QUALITY == txRfQuality[txRfChId]); } public: diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index cc73cb0b..f63fa688 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -192,6 +192,14 @@ class Inverter { if(mNextLive) cb(RealTimeRunData_Debug, false); // get live data else { + if(INV_RADIO_TYPE_NRF == ivRadioType) { + // get live data until quility reaches maximum + if(!heuristics.isTxAtMax()) { + cb(RealTimeRunData_Debug, false); // get live data + return; + } + } + if(actPowerLimit == 0xffff) cb(SystemConfigPara, false); // power limit info else if(InitDataState != devControlCmd) { @@ -449,6 +457,7 @@ class Inverter { status = InverterStatus::OFF; actPowerLimit = 0xffff; // power limit will be read once inverter becomes available alarmMesIndex = 0; + heuristics.clear(); } else status = InverterStatus::WAS_ON; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d73b2b0e..5730c492 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -77,7 +77,7 @@ class HmRadio : public Radio { #else mNrf24->begin(mSpi.get(), ce, cs); #endif - mNrf24->setRetries(3, 15); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms + mNrf24->setRetries(3, 9); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms mNrf24->setDataRate(RF24_250KBPS); //mNrf24->setAutoAck(true); // enabled by default @@ -120,14 +120,14 @@ class HmRadio : public Radio { if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME+DURATION_ONEFRAME))) mNRFloopChannels = true; - rxPendular = !rxPendular; - //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; + mRxPendular = !mRxPendular; + //innerLoopTimeout = (mRxPendular ? 1 : 2)*DURATION_LISTEN_MIN; innerLoopTimeout = DURATION_LISTEN_MIN; if(mNRFloopChannels) tempRxChIdx = (tempRxChIdx + 4) % RF_CHANNELS; else - tempRxChIdx = (mRxChIdx + rxPendular*4) % RF_CHANNELS; + tempRxChIdx = (mRxChIdx + mRxPendular*4) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[tempRxChIdx]); isRxInit = false; @@ -141,7 +141,7 @@ class HmRadio : public Radio { if(tx_ok || tx_fail) { // tx related interrupt, basically we should start listening mNrf24->flush_tx(); // empty TX FIFO - mTxSetupTime = millis() - mMillis; + //mTxSetupTime = millis() - mMillis; if(mNRFisInRX) { DPRINTLN(DBG_WARN, F("unexpected tx irq!")); @@ -157,7 +157,7 @@ class HmRadio : public Radio { mNrf24->startListening(); mTimeslotStart = millis(); tempRxChIdx = mRxChIdx; - rxPendular = false; + mRxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); innerLoopTimeout = DURATION_TXFRAME; @@ -168,11 +168,12 @@ class HmRadio : public Radio { mNRFisInRX = false; mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions mNrf24->stopListening(); + return false; } else { innerLoopTimeout = DURATION_LISTEN_MIN; mTimeslotStart = millis(); if (!mNRFloopChannels) { - //rxPendular = true; // stay longer on the next rx channel + //mRxPendular = true; // stay longer on the next rx channel if (isRxInit) { isRxInit = false; tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; @@ -180,8 +181,8 @@ class HmRadio : public Radio { } else mRxChIdx = tempRxChIdx; } + return true; } - return mNRFisInRX; } } @@ -341,11 +342,11 @@ class HmRadio : public Radio { mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { - if(!isRetransmit) { + /*if(!isRetransmit) { DPRINT(DBG_INFO, "last tx setup: "); DBGPRINT(String(mTxSetupTime)); DBGPRINTLN("ms"); - } + }*/ DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); @@ -368,6 +369,7 @@ class HmRadio : public Radio { } mNrf24->stopListening(); + mNrf24->flush_rx(); mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response @@ -407,9 +409,9 @@ class HmRadio : public Radio { bool mNRFloopChannels = false; bool mNRFisInRX = false; bool isRxInit = true; - bool rxPendular = false; + bool mRxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; - uint8_t mTxSetupTime = 0; + //uint8_t mTxSetupTime = 0; std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 3cdc2660..e6456f5b 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -356,11 +356,11 @@ class Cmt2300a { if((freqKhz % FREQ_STEP_KHZ) != 0) return 0xff; // error - std::pair range = getFreqRangeMhz(); - if((freqKhz < range.first) || (freqKhz > range.second)) + std::pair range = getFreqRangeMhz(); + if((freqKhz < (range.first * 1000)) || (freqKhz > (range.second * 1000))) return 0xff; // error - return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ; + return (freqKhz - (getBaseFreqMhz() * 1000)) / FREQ_STEP_KHZ; } inline void switchChannel(uint8_t ch) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 9ec717c1..ccdc8747 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -754,6 +754,12 @@ class RestApi { warn.add(F(REBOOT_ESP_APPLY_CHANGES)); if(0 == mApp->getTimestamp()) warn.add(F(TIME_NOT_SET)); + #if !defined(ETHERNET) + #if !defined(ESP32) + if(mApp->getWasInCh12to14()) + warn.add(F(WAS_IN_CH_12_TO_14)); + #endif + #endif } void getSetup(AsyncWebServerRequest *request, JsonObject obj) { diff --git a/src/web/lang.h b/src/web/lang.h index 546399aa..e55493eb 100644 --- a/src/web/lang.h +++ b/src/web/lang.h @@ -18,6 +18,12 @@ #define TIME_NOT_SET "time not set. No communication to inverter possible" #endif +#ifdef LANG_DE + #define WAS_IN_CH_12_TO_14 "Der ESP war in WLAN Kanal 12 bis 14, was uU. zu Abstürzen führt" +#else /*LANG_EN*/ + #define WAS_IN_CH_12_TO_14 "Your ESP was in wifi channel 12 to 14. It may cause reboots of your AhoyDTU" +#endif + #ifdef LANG_DE #define INV_INDEX_INVALID "Wechselrichterindex ungültig; " #else /*LANG_EN*/ diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index defca5bc..9bcbdadc 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -92,6 +92,8 @@ void ahoywifi::tickWifiLoop() { } #if !defined(ESP32) MDNS.update(); + if(WiFi.channel() > 11) + mWasInCh12to14 = true; #endif return; case IN_AP_MODE: diff --git a/src/wifi/ahoywifi.h b/src/wifi/ahoywifi.h index 7fb62a20..709c08c4 100644 --- a/src/wifi/ahoywifi.h +++ b/src/wifi/ahoywifi.h @@ -37,6 +37,10 @@ class ahoywifi { } void setupStation(void); + bool getWasInCh12to14() const { + return mWasInCh12to14; + } + private: typedef enum WiFiStatus { DISCONNECTED = 0, @@ -86,6 +90,7 @@ class ahoywifi { bool mGotDisconnect; std::list mBSSIDList; bool mStopApAllowed; + bool mWasInCh12to14 = false; }; #endif /*__AHOYWIFI_H__*/ From bba82d8b3a9a634381dfdf128f1fa11e72b163a8 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 30 Jan 2024 13:32:55 +0100 Subject: [PATCH 18/79] different tx-offests for 4ch HM * discord 0.8.6803 * tx+3 for 4ch-HM, tx+2 for other Inverters --- src/hm/CommQueue.h | 2 +- src/hm/Communication.h | 9 ++++++--- src/hm/HeuristicInv.h | 15 +++++++++++++++ src/hm/hmInverter.h | 21 ++++++++++++++++++--- src/hm/hmRadio.h | 43 ++++++++++++++++++++++++++---------------- src/hm/hmSystem.h | 7 ++++++- src/hms/cmt2300a.h | 6 +++--- 7 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index d7cc5642..acbe9a35 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -12,7 +12,7 @@ #include "../utils/dbg.h" #define DEFAULT_ATTEMPS 5 -#define MORE_ATTEMPS_ALARMDATA 0 // 8 +#define MORE_ATTEMPS_ALARMDATA 3 // 8 #define MORE_ATTEMPS_GRIDONPROFILEPARA 0 // 5 template diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 9219bb8e..8887a4a2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -140,7 +140,10 @@ class Communication : public CommQueue<> { if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { #if defined(ESP32) - q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000)); + if(!q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000))) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("switch frequency failed!")); + } mWaitTime.startTimeMonitor(1000); #endif } else { @@ -418,8 +421,8 @@ class Communication : public CommQueue<> { if((*frameId & ALL_FRAMES) == ALL_FRAMES) { mMaxFrameId = (*frameId & 0x7f); - /*if(mMaxFrameId > 8) // large payloads, e.g. AlarmData - incrAttempt(mMaxFrameId - 6);*/ + if(mMaxFrameId > 8) // large payloads, e.g. AlarmData + incrAttempt(mMaxFrameId - 6); } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index e9c7084e..505562e3 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -14,7 +14,22 @@ class HeuristicInv { public: HeuristicInv() { + clear(); + } + + void clear() { memset(txRfQuality, 0, RF_MAX_CHANNEL_ID); + txRfChId = 0; + lastBestTxChId = 0; + testPeriodSendCnt = 0; + testPeriodFailCnt = 0; + testChId = 0; + saveOldTestQuality = -6; + lastRxFragments = 0; + } + + bool isTxAtMax(void) const { + return (RF_MAX_QUALITY == txRfQuality[txRfChId]); } public: diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index a74ad02f..e6e22fb7 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -193,6 +193,14 @@ class Inverter { if(mNextLive) cb(RealTimeRunData_Debug, false); // get live data else { + if(INV_RADIO_TYPE_NRF == ivRadioType) { + // get live data until quality reaches maximum + if(!heuristics.isTxAtMax()) { + cb(RealTimeRunData_Debug, false); // get live data + return; + } + } + if(actPowerLimit == 0xffff) { cb(SystemConfigPara, false); // power limit info cb(RealTimeRunData_Debug, false); @@ -201,17 +209,18 @@ class Inverter { devControlCmd = InitDataState; mGetLossInterval = 1; } else if(0 == getFwVersion()) { - cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_All, false); // get firmware version + cb(RealTimeRunData_Debug, false); // get live data } else if(0 == getHwVersion()) { - cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_Simple, false); // get hardware version - } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { cb(RealTimeRunData_Debug, false); // get live data + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { cb(AlarmData, false); // get last alarms + cb(RealTimeRunData_Debug, false); // get live data } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile cb(GridOnProFilePara, false); + cb(RealTimeRunData_Debug, false); // get live data } else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate mGetLossInterval = 1; cb(RealTimeRunData_Debug, false); // get live data @@ -455,6 +464,12 @@ class Inverter { status = InverterStatus::OFF; actPowerLimit = 0xffff; // power limit will be read once inverter becomes available alarmMesIndex = 0; + if(ivRadioType == INV_RADIO_TYPE_NRF) { + heuristics.clear(); + #ifdef DYNAMIC_OFFSET + rxOffset = ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting + #endif + } } else status = InverterStatus::WAS_ON; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index e759576c..0dcbccb3 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -121,14 +121,14 @@ class HmRadio : public Radio { if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME))) //(DURATION_TXFRAME+DURATION_ONEFRAME))) mNRFloopChannels = true; - rxPendular = !rxPendular; + mRxPendular = !mRxPendular; //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; - //innerLoopTimeout = DURATION_LISTEN_MIN; + innerLoopTimeout = DURATION_LISTEN_MIN; if(mNRFloopChannels) tempRxChIdx = (tempRxChIdx + 4) % RF_CHANNELS; else - tempRxChIdx = (mRxChIdx + rxPendular*4) % RF_CHANNELS; + tempRxChIdx = (mRxChIdx + mRxPendular*4) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[tempRxChIdx]); isRxInit = false; @@ -142,7 +142,7 @@ class HmRadio : public Radio { if(tx_ok || tx_fail) { // tx related interrupt, basically we should start listening mNrf24->flush_tx(); // empty TX FIFO - mTxSetupTime = millis() - mMillis; + //mTxSetupTime = millis() - mMillis; if(mNRFisInRX) { DPRINTLN(DBG_WARN, F("unexpected tx irq!")); @@ -153,17 +153,21 @@ class HmRadio : public Radio { if(tx_ok) mLastIv->mAckCount++; - //mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + //#ifdef DYNAMIC_OFFSET mRxChIdx = (mTxChIdx + mLastIv->rxOffset) % RF_CHANNELS; + /*#else + mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + #endif*/ mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); tempRxChIdx = mRxChIdx; // might be better to start off with one channel less? - rxPendular = false; + mRxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; - innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; + //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; + innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME; } if(rx_ready) { @@ -176,7 +180,7 @@ class HmRadio : public Radio { innerLoopTimeout = DURATION_LISTEN_MIN; mTimeslotStart = millis(); if (!mNRFloopChannels) { - //rxPendular = true; // stay longer on the next rx channel + //mRxPendular = true; // stay longer on the next rx channel if (isRxInit) { isRxInit = false; tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; @@ -325,12 +329,14 @@ class HmRadio : public Radio { isRetransmitAnswer = true; if(isLastPackage) setExpectedFrames(p.packet[9] - ALL_FRAMES); + #ifdef DYNAMIC_OFFSET if(p.packet[9] == 1 && p.millis < DURATION_ONEFRAME) mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS; else if(mNRFloopChannels && mLastIv->rxOffset > RF_CHANNELS) { // unsure setting? mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset mNRFloopChannels = false; } + #endif } if(IV_MI == mLastIv->ivGen) { @@ -338,8 +344,10 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && isLastPackage = true; // response from dev control command + #ifdef DYNAMIC_OFFSET if(p.packet[9] == 0x00 && p.millis < DURATION_ONEFRAME) mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS; + #endif } rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads } @@ -347,9 +355,8 @@ class HmRadio : public Radio { } yield(); } - if(isLastPackage) { + if(isLastPackage) mLastIv->mGotLastMsg = true; - } return isLastPackage || isRetransmitAnswer; } @@ -361,10 +368,7 @@ class HmRadio : public Radio { mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { - /* remark rejoe2: imo this has no added value here. - As this belongs to the last tx cycle, we should print that info - directly when switching from tx to rx. Otherwise we might confuse users. - if(!isRetransmit) { + /*if(!isRetransmit) { DPRINT(DBG_INFO, "last tx setup: "); DBGPRINT(String(mTxSetupTime)); DBGPRINTLN("ms"); @@ -374,13 +378,19 @@ class HmRadio : public Radio { DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); + if(mTxChIdx == 0) + DBGPRINT("0"); DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(", ")); DBGPRINT(String(mTxRetriesNext)); //DBGPRINT(F(" retries | ")); + //#ifdef DYNAMIC_OFFSET DBGPRINT(F(" ret., rx offset: ")); DBGPRINT(String(iv->rxOffset)); DBGPRINT(F(" | ")); + /*#else + DBGPRINT(F(" ret. | ")); + #endif*/ if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); @@ -396,6 +406,7 @@ class HmRadio : public Radio { } mNrf24->stopListening(); + mNrf24->flush_rx(); if(!isRetransmit && mTxRetries != mTxRetriesNext) { mNrf24->setRetries(3, mTxRetriesNext); mTxRetries = mTxRetriesNext; @@ -439,9 +450,9 @@ class HmRadio : public Radio { bool mNRFloopChannels = false; bool mNRFisInRX = false; bool isRxInit = true; - bool rxPendular = false; + bool mRxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; - uint8_t mTxSetupTime = 0; + //uint8_t mTxSetupTime = 0; uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); std::unique_ptr mSpi; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 26d0ea5d..b727e0bb 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -28,7 +28,6 @@ class HmSystem { iv->config = &mInverter[0].generalConfig->iv[id]; DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX)); - iv->rxOffset = 13; // effective 3, but can easily be recognized as default setting if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 @@ -96,6 +95,12 @@ class HmSystem { if((iv->config->serial.b[5] == 0x10) && ((iv->config->serial.b[4] & 0x03) == 0x01)) DPRINTLN(DBG_WARN, F("MI Inverter, has some restrictions!")); + #ifdef DYNAMIC_OFFSET + iv->rxOffset = iv->ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting + #else + iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2; // effective 3 (or 2), but can easily be recognized as default setting + #endif + cb(iv); } diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 3cdc2660..e6456f5b 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -356,11 +356,11 @@ class Cmt2300a { if((freqKhz % FREQ_STEP_KHZ) != 0) return 0xff; // error - std::pair range = getFreqRangeMhz(); - if((freqKhz < range.first) || (freqKhz > range.second)) + std::pair range = getFreqRangeMhz(); + if((freqKhz < (range.first * 1000)) || (freqKhz > (range.second * 1000))) return 0xff; // error - return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ; + return (freqKhz - (getBaseFreqMhz() * 1000)) / FREQ_STEP_KHZ; } inline void switchChannel(uint8_t ch) { From fddd03af6b98f75c73ba1b93a29cec88358ef527 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 30 Jan 2024 15:37:40 +0100 Subject: [PATCH 19/79] re-flexibilisize rx-channels also for HM 2ch devices --- src/hm/hmDefines.h | 4 ++-- src/hm/hmRadio.h | 5 ++--- src/hm/hmSystem.h | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 4705c061..f06c06fe 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -90,8 +90,8 @@ const uint8_t duration_reserve[2] = {65,115}; #define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter #define LIMIT_FAST_IV_MI 35 // time limit to qualify a MI type inverter as fast answering inverter #define LIMIT_VERYFAST_IV_MI 22 // time limit to qualify a MI type inverter as very fast answering inverter -#define RETRIES_FAST_IV 11 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter) -#define RETRIES_VERYFAST_IV 7 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter) +#define RETRIES_FAST_IV 12 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter) +#define RETRIES_VERYFAST_IV 9 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter) typedef struct { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 0dcbccb3..a88e43c6 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -122,7 +122,6 @@ class HmRadio : public Radio { mNRFloopChannels = true; mRxPendular = !mRxPendular; - //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; innerLoopTimeout = DURATION_LISTEN_MIN; if(mNRFloopChannels) @@ -167,7 +166,8 @@ class HmRadio : public Radio { //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; - innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME; + //innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME; + innerLoopTimeout = DURATION_LISTEN_MIN; } if(rx_ready) { @@ -180,7 +180,6 @@ class HmRadio : public Radio { innerLoopTimeout = DURATION_LISTEN_MIN; mTimeslotStart = millis(); if (!mNRFloopChannels) { - //mRxPendular = true; // stay longer on the next rx channel if (isRxInit) { isRxInit = false; tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index b727e0bb..aa5d7492 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -98,7 +98,8 @@ class HmSystem { #ifdef DYNAMIC_OFFSET iv->rxOffset = iv->ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting #else - iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2; // effective 3 (or 2), but can easily be recognized as default setting + iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2; + iv->rxOffset = iv->ivGen == IV_HM ? 3 : 2; #endif cb(iv); From 349184a11331463b6e80363ea11b6f59e376d9a8 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 31 Jan 2024 22:24:08 +0100 Subject: [PATCH 20/79] 0.8.69 * fix brackets --- src/hm/Communication.h | 12 ++++++------ src/hm/Heuristic.h | 2 +- src/hm/HeuristicInv.h | 10 +++++++--- src/hm/hmDefines.h | 2 +- src/hm/hmInverter.h | 2 +- src/hm/hmRadio.h | 9 +++++---- src/hm/hmSystem.h | 6 +++--- 7 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 5725f2ec..923bffe1 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -87,7 +87,7 @@ class Communication : public CommQueue<> { mIsRetransmit = false; if(NULL == q->iv->radio) cmdDone(false); // can't communicate while radio is not defined! - mFirstTry = INV_RADIO_TYPE_NRF == q->iv->ivRadioType && q->iv->isAvailable(); + mFirstTry = (INV_RADIO_TYPE_NRF == q->iv->ivRadioType) && (q->iv->isAvailable()); q->iv->mCmd = q->cmd; q->iv->mIsSingleframeReq = false; mFramesExpected = getFramesExpected(q); // function to get expected frame count. @@ -116,7 +116,7 @@ class Communication : public CommQueue<> { //q->iv->radioStatistics.txCnt++; q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout); if(!mIsRetransmit && (q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) - incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); + incrAttempt((q->cmd == AlarmData)? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); mIsRetransmit = false; setAttempt(); @@ -184,7 +184,7 @@ class Communication : public CommQueue<> { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command if(parseFrame(p)) { q->iv->curFrmCnt++; - if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < LIMIT_FAST_IV) + if(!mIsRetransmit && ((p->packet[9] == 0x02) || (p->packet[9] == 0x82)) && (p->millis < LIMIT_FAST_IV)) mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV); } } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command @@ -257,13 +257,13 @@ class Communication : public CommQueue<> { return; } //count missing frames - if(!q->iv->mIsSingleframeReq && q->iv->ivRadioType == INV_RADIO_TYPE_NRF) { // already checked? + if(!q->iv->mIsSingleframeReq && (q->iv->ivRadioType == INV_RADIO_TYPE_NRF)) { // already checked? uint8_t missedFrames = 0; for(uint8_t i = 0; i < q->iv->radio->mFramesExpected; i++) { if(mLocalBuf[i].len == 0) missedFrames++; } - if(missedFrames > 3 || (q->cmd == RealTimeRunData_Debug && missedFrames > 1) || (missedFrames > 1 && missedFrames + 2 > q->attempts)) { + if(missedFrames > 3 || (q->cmd == RealTimeRunData_Debug && missedFrames > 1) || ((missedFrames > 1) && ((missedFrames + 2) > q->attempts))) { if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(String(missedFrames)); @@ -435,7 +435,7 @@ class Communication : public CommQueue<> { } inline bool parseMiFrame(packet_t *p, const queue_s *q) { - if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < LIMIT_FAST_IV_MI) //first frame is fast? + if((!mIsRetransmit && p->packet[9] == 0x00) && (p->millis < LIMIT_FAST_IV_MI)) //first frame is fast? mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV_MI); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 3fb86614..fa4512b5 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index 89099ca8..913732bc 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -26,6 +26,11 @@ class HeuristicInv { testChId = 0; saveOldTestQuality = -6; lastRxFragments = 0; + + rxSpeeds[0] = false; + rxSpeeds[1] = false; + rxSpeedCnt[0] = 0; + rxSpeedCnt[1] = 0; } bool isTxAtMax(void) const { @@ -42,9 +47,8 @@ class HeuristicInv { uint8_t testChId = 0; int8_t saveOldTestQuality = -6; uint8_t lastRxFragments = 0; - bool rxSpeeds[2] = {false,false}; // is inverter responding very fast respective fast? - uint8_t rxSpeedCnt[2] = {0,0}; // count how many messages had been received very fast respective fast (10 max) - + bool rxSpeeds[2] = {false, false}; // is inverter responding very fast respective fast? + uint8_t rxSpeedCnt[2] = {0, 0}; // count how many messages had been received very fast respective fast (10 max) }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index f06c06fe..0b42aeae 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -84,7 +84,7 @@ enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; #define DURATION_TXFRAME 85 // timeout parameter for first transmission and first expected frame (time to first channel switch from tx start!) (ms) #define DURATION_LISTEN_MIN 5 // time to stay at least on a listening channel (ms) #define DURATION_PAUSE_LASTFR 45 // how long to pause after last frame (ms) -const uint8_t duration_reserve[2] = {65,115}; +const uint8_t duration_reserve[2] = {65, 115}; #define LIMIT_FAST_IV 85 // time limit to qualify an inverter as very fast answering inverter #define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index e6e22fb7..e4015110 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -464,7 +464,7 @@ class Inverter { status = InverterStatus::OFF; actPowerLimit = 0xffff; // power limit will be read once inverter becomes available alarmMesIndex = 0; - if(ivRadioType == INV_RADIO_TYPE_NRF) { + if(INV_RADIO_TYPE_NRF == ivRadioType) { heuristics.clear(); #ifdef DYNAMIC_OFFSET rxOffset = ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d1dd42d5..ca96a333 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -328,12 +328,13 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received if(mLastIv->mIsSingleframeReq) // we only expect one frame here... isRetransmitAnswer = true; + if(isLastPackage) setExpectedFrames(p.packet[9] - ALL_FRAMES); #ifdef DYNAMIC_OFFSET - if(p.packet[9] == 1 && p.millis < DURATION_ONEFRAME) + if((p.packet[9] == 1) && (p.millis < DURATION_ONEFRAME)) mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS; - else if(mNRFloopChannels && mLastIv->rxOffset > RF_CHANNELS) { // unsure setting? + else if(mNRFloopChannels && (mLastIv->rxOffset > RF_CHANNELS)) { // unsure setting? mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset mNRFloopChannels = false; } @@ -346,7 +347,7 @@ class HmRadio : public Radio { else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && isLastPackage = true; // response from dev control command #ifdef DYNAMIC_OFFSET - if(p.packet[9] == 0x00 && p.millis < DURATION_ONEFRAME) + if((p.packet[9] == 0x00) && (p.millis < DURATION_ONEFRAME)) mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS; #endif } @@ -408,7 +409,7 @@ class HmRadio : public Radio { mNrf24->stopListening(); mNrf24->flush_rx(); - if(!isRetransmit && mTxRetries != mTxRetriesNext) { + if(!isRetransmit && (mTxRetries != mTxRetriesNext)) { mNrf24->setRetries(3, mTxRetriesNext); mTxRetries = mTxRetriesNext; } diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index aa5d7492..aa2910e5 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -96,10 +96,10 @@ class HmSystem { DPRINTLN(DBG_WARN, F("MI Inverter, has some restrictions!")); #ifdef DYNAMIC_OFFSET - iv->rxOffset = iv->ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting + iv->rxOffset = (iv->ivGen == IV_HM) ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting #else - iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2; - iv->rxOffset = iv->ivGen == IV_HM ? 3 : 2; + iv->rxOffset = ((iv->ivGen == IV_HM) && (iv->type == INV_TYPE_4CH)) ? 3 : 2; + iv->rxOffset = (iv->ivGen == IV_HM) ? 3 : 2; #endif cb(iv); From f89fd66dbf3951513475bb1eb03f8a92a9736c00 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 31 Jan 2024 22:46:41 +0100 Subject: [PATCH 21/79] 0.8.69 * merge PR: Dynamic retries, pendular first rx chan #1394 --- src/CHANGES.md | 3 ++ src/defines.h | 4 +-- src/hm/hmInverter.h | 69 ++++++++++++++++++--------------------------- src/web/lang.json | 2 +- 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f690b192..4de7afa4 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.69 - 2024-01-31 +* merge PR: Dynamic retries, pendular first rx chan #1394 + ## 0.8.68 - 2024-01-29 * fix HMS / HMT startup * added `flush_rx` to NRF on TX diff --git a/src/defines.h b/src/defines.h index 442008ff..a4a1d6bd 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 68 +#define VERSION_PATCH 69 //------------------------------------- typedef struct { @@ -22,8 +22,6 @@ typedef struct { int8_t rssi; uint8_t packet[MAX_RF_PAYLOAD_SIZE]; uint16_t millis; - uint8_t arc; - uint8_t plos; } packet_t; typedef enum { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index e4015110..1ceed42e 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -190,44 +190,37 @@ class Inverter { mDevControlRequest = false; } else if (IV_MI != ivGen) { // HM / HMS / HMT mGetLossInterval++; - if(mNextLive) - cb(RealTimeRunData_Debug, false); // get live data - else { - if(INV_RADIO_TYPE_NRF == ivRadioType) { - // get live data until quality reaches maximum - if(!heuristics.isTxAtMax()) { - cb(RealTimeRunData_Debug, false); // get live data - return; - } - } - - if(actPowerLimit == 0xffff) { - cb(SystemConfigPara, false); // power limit info - cb(RealTimeRunData_Debug, false); - } else if(InitDataState != devControlCmd) { - cb(devControlCmd, false); // custom command which was received by API - devControlCmd = InitDataState; - mGetLossInterval = 1; - } else if(0 == getFwVersion()) { - cb(InverterDevInform_All, false); // get firmware version + if(INV_RADIO_TYPE_NRF == ivRadioType) { + // get live data until quality reaches maximum + if(!heuristics.isTxAtMax()) { cb(RealTimeRunData_Debug, false); // get live data + return; } - else if(0 == getHwVersion()) { - cb(InverterDevInform_Simple, false); // get hardware version - cb(RealTimeRunData_Debug, false); // get live data - } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { - cb(AlarmData, false); // get last alarms - cb(RealTimeRunData_Debug, false); // get live data - } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile - cb(GridOnProFilePara, false); - cb(RealTimeRunData_Debug, false); // get live data - } else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate - mGetLossInterval = 1; - cb(RealTimeRunData_Debug, false); // get live data - cb(GetLossRate, false); - } else - cb(RealTimeRunData_Debug, false); // get live data } + + if(actPowerLimit == 0xffff) { + cb(SystemConfigPara, false); // power limit info + } else if(InitDataState != devControlCmd) { + cb(devControlCmd, false); // custom command which was received by API + devControlCmd = InitDataState; + mGetLossInterval = 1; + return; + } else if(0 == getFwVersion()) { + cb(InverterDevInform_All, false); // get firmware version + } else if(0 == getHwVersion()) { + cb(InverterDevInform_Simple, false); // get hardware version + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { + cb(AlarmData, false); // get last alarms + } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile + cb(GridOnProFilePara, false); + } else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate + mGetLossInterval = 1; + cb(RealTimeRunData_Debug, false); // get live data + cb(GetLossRate, false); + return; + } + + cb(RealTimeRunData_Debug, false); // get live data } else { // MI cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); mGetLossInterval++; @@ -279,21 +272,18 @@ class Inverter { } const char *getFieldName(uint8_t pos, record_t<> *rec) { - DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getFieldName")); if(NULL != rec) return fields[rec->assign[pos].fieldId]; return notAvail; } const char *getUnit(uint8_t pos, record_t<> *rec) { - DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getUnit")); if(NULL != rec) return units[rec->assign[pos].unitId]; return notAvail; } uint8_t getChannel(uint8_t pos, record_t<> *rec) { - DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getChannel")); if(NULL != rec) return rec->assign[pos].ch; return 0; @@ -350,7 +340,6 @@ class Inverter { } if(rec == &recordMeas) { - mNextLive = false; // live data received DPRINTLN(DBG_VERBOSE, "add real time"); // get last alarm message index and save it in the inverter object if (getPosByChFld(0, FLD_EVT, rec) == pos) { @@ -363,7 +352,6 @@ class Inverter { } } else { - mNextLive = true; if (rec->assign == InfoAssignment) { DPRINTLN(DBG_DEBUG, "add info"); // eg. fw version ... @@ -868,7 +856,6 @@ class Inverter { uint8_t mGridLen = 0; uint8_t mGridProfile[MAX_GRID_LENGTH]; uint8_t mAlarmNxtWrPos = 0; // indicates the position in array (rolling buffer) - bool mNextLive = true; // first read live data after booting up then version etc. public: uint16_t mDtuRxCnt = 0; diff --git a/src/web/lang.json b/src/web/lang.json index d083ddff..1617658a 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -1396,7 +1396,7 @@ { "token": "CMD_RECEIVED_WAIT_ACK", "en": "received command, waiting for inverter acknowledge ...", - "de": "Befehl erhalten, warte auf Bestäigung von Wechselrichter ..." + "de": "Befehl erhalten, warte auf Bestäigung vom Wechselrichter ..." }, { "token": "COMMAND_RECEIVED", From ae799b4c2130c8b12c6b96994bd2238ec7695657 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 1 Feb 2024 21:38:07 +0100 Subject: [PATCH 22/79] 0.8.70 * prevent sending commands to inverter which isn't active #1387 --- .github/workflows/compile_development.yml | 12 ++++----- src/CHANGES.md | 3 +++ src/hm/Communication.h | 1 - src/hm/hmInverter.h | 31 +++++++++++------------ 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 7eaf9b34..67fa6f0a 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'lumapu/ahoy' && github.ref_name == 'development03' continue-on-error: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 build-en: needs: check @@ -32,7 +32,7 @@ jobs: - opendtufusion - opendtufusion-ethernet steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: benjlevesque/short-sha@v2.1 id: short-sha with: @@ -53,7 +53,7 @@ jobs: key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - name: Setup Python - uses: actions/setup-python@v4.3.0 + uses: actions/setup-python@v5 with: python-version: "3.x" @@ -92,7 +92,7 @@ jobs: - opendtufusion-de - opendtufusion-ethernet-de steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: benjlevesque/short-sha@v2.1 id: short-sha with: @@ -113,7 +113,7 @@ jobs: key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - name: Setup Python - uses: actions/setup-python@v4.3.0 + uses: actions/setup-python@v5 with: python-version: "3.x" @@ -138,7 +138,7 @@ jobs: needs: [build-en, build-de] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 #- name: Copy boot_app0.bin # run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin diff --git a/src/CHANGES.md b/src/CHANGES.md index 4de7afa4..4b6eda8e 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.70 - 2024-02-01 +* prevent sending commands to inverter which isn't active #1387 + ## 0.8.69 - 2024-01-31 * merge PR: Dynamic retries, pendular first rx chan #1394 diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 923bffe1..4895d2e7 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -681,7 +681,6 @@ class Communication : public CommQueue<> { for (uint8_t i = 0; i < 5; i++) { q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); } - q->iv->isConnected = true; if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("HW_VER is ")); diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 1ceed42e..a5276880 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -130,7 +130,6 @@ class Inverter { record_t recordHwInfo; // structure for simple (hardware) info values record_t recordConfig; // structure for system config values record_t recordAlarm; // structure for alarm values - bool isConnected; // shows if inverter was successfully identified (fw version and hardware info) InverterStatus status; // indicates the current inverter status std::array lastAlarm; // holds last 10 alarms uint8_t rxOffset; // holds the default channel offset between tx and rx channel (nRF only) @@ -166,7 +165,6 @@ class Inverter { mDevControlRequest = false; devControlCmd = InitDataState; alarmMesIndex = 0; - isConnected = false; status = InverterStatus::OFF; alarmCnt = 0; alarmLastId = 0; @@ -186,7 +184,10 @@ class Inverter { void tickSend(std::function cb) { if(mDevControlRequest) { - cb(devControlCmd, true); + if(InverterStatus::PRODUCING == status) + cb(devControlCmd, true); + else + DPRINTLN(DBG_WARN, F("Inverter is not avail")); mDevControlRequest = false; } else if (IV_MI != ivGen) { // HM / HMS / HMT mGetLossInterval++; @@ -262,8 +263,7 @@ class Inverter { break; } return (pos >= rec->length) ? 0xff : pos; - } - else + } else return 0xff; } @@ -290,18 +290,18 @@ class Inverter { } bool setDevControlRequest(uint8_t cmd) { - if(isConnected) { + if(InverterStatus::PRODUCING == status) { mDevControlRequest = true; devControlCmd = cmd; //app->triggerTickSend(); // done in RestApi.h, because of "chicken-and-egg problem ;-)" } - return isConnected; + return (InverterStatus::PRODUCING == status); } bool setDevCommand(uint8_t cmd) { - if(isConnected) + if(InverterStatus::PRODUCING == status) devControlCmd = cmd; - return isConnected; + return (InverterStatus::PRODUCING == status); } void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { @@ -318,6 +318,7 @@ class Inverter { val <<= 8; val |= buf[ptr]; } while(++ptr != end); + if ((FLD_T == rec->assign[pos].fieldId) || (FLD_Q == rec->assign[pos].fieldId) || (FLD_PF == rec->assign[pos].fieldId)) { // temperature, Qvar, and power factor are a signed values rec->record[pos] = ((REC_TYP)((int16_t)val)) / (REC_TYP)(div); @@ -350,12 +351,10 @@ class Inverter { DBGPRINTLN(String(alarmMesIndex)); } } - } - else { + } else { if (rec->assign == InfoAssignment) { DPRINTLN(DBG_DEBUG, "add info"); // eg. fw version ... - isConnected = true; } else if (rec->assign == SimpleInfoAssignment) { DPRINTLN(DBG_DEBUG, "add simple info"); // eg. hw version ... @@ -371,8 +370,7 @@ class Inverter { } else DPRINTLN(DBG_WARN, F("add with unknown assignment")); } - } - else + } else DPRINTLN(DBG_ERROR, F("addValue: assignment not found with cmd 0x")); // update status state-machine @@ -396,12 +394,12 @@ class Inverter { if((rec->assign[pos].ch == channel) && (rec->assign[pos].fieldId == fieldId)) break; } + if(pos >= rec->length) return 0; return rec->record[pos]; - } - else + } else return 0; } @@ -477,6 +475,7 @@ class Inverter { else if(InverterStatus::PRODUCING == status) status = InverterStatus::WAS_PRODUCING; } + return producing; } From 4d7362fa6b1b1538933d476344036274523db748 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 1 Feb 2024 23:27:54 +0100 Subject: [PATCH 23/79] 0.8.70 - 2024-02-01 * prevent sending commands to inverter which isn't active #1387 * protect commands from popup in `/live` if password is set #1199 --- src/CHANGES.md | 1 + src/app.cpp | 5 ++- src/app.h | 22 +++++++++- src/appInterface.h | 6 ++- src/defines.h | 2 +- src/utils/spiPatcher.cpp | 4 +- src/utils/spiPatcher.h | 4 +- src/web/Protection.cpp | 7 +++ src/web/Protection.h | 93 ++++++++++++++++++++++++++++++++++++++++ src/web/RestApi.h | 15 +++++-- src/web/lang.h | 6 +++ src/web/web.h | 49 +++------------------ 12 files changed, 156 insertions(+), 58 deletions(-) create mode 100644 src/web/Protection.cpp create mode 100644 src/web/Protection.h diff --git a/src/CHANGES.md b/src/CHANGES.md index 4b6eda8e..9835873c 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,7 @@ ## 0.8.70 - 2024-02-01 * prevent sending commands to inverter which isn't active #1387 +* protect commands from popup in `/live` if password is set #1199 ## 0.8.69 - 2024-01-31 * merge PR: Dynamic retries, pendular first rx chan #1394 diff --git a/src/app.cpp b/src/app.cpp index a14a8811..8b770989 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -97,9 +97,8 @@ void app::setup() { esp_task_wdt_reset(); mWeb.setup(this, &mSys, mConfig); - mWeb.setProtection(strlen(mConfig->sys.adminPwd) != 0); - mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig); + mProtection = Protection::getInstance(mConfig->sys.adminPwd); #ifdef ENABLE_SYSLOG mDbgSyslog.setup(mConfig); // be sure to init after mWeb.setup (webSerial uses also debug callback) @@ -182,6 +181,8 @@ void app::onNetwork(bool gotIp) { void app::regularTickers(void) { DPRINTLN(DBG_DEBUG, F("regularTickers")); everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc"); + everySec([this]() { mProtection->tickSecond(); }, "prot"); + // Plugins #if defined(PLUGIN_DISPLAY) if (DISP_TYPE_T0_NONE != mConfig->plugin.display.type) diff --git a/src/app.h b/src/app.h index ccf46297..b44d3781 100644 --- a/src/app.h +++ b/src/app.h @@ -30,6 +30,7 @@ #include "utils/scheduler.h" #include "utils/syslog.h" #include "web/RestApi.h" +#include "web/Protection.h" #if defined(ENABLE_HISTORY) #include "plugins/history.h" #endif /*ENABLE_HISTORY*/ @@ -246,8 +247,24 @@ class app : public IApp, public ah::Scheduler { #endif } - bool getProtection(AsyncWebServerRequest *request) { - return mWeb.isProtected(request); + void lock(void) override { + mProtection->lock(); + } + + void unlock(const char *clientIp) override { + mProtection->unlock(clientIp); + } + + void resetLockTimeout(void) override { + mProtection->resetLockTimeout(); + } + + bool isProtected(void) const override { + return mProtection->isProtected(); + } + + bool isProtected(const char *clientIp) const override { + return mProtection->isProtected(clientIp); } bool getNrfEnabled(void) { @@ -387,6 +404,7 @@ class app : public IApp, public ah::Scheduler { #endif /* defined(ETHERNET) */ WebType mWeb; RestApiType mApi; + Protection *mProtection; #ifdef ENABLE_SYSLOG DbgSyslog mDbgSyslog; #endif diff --git a/src/appInterface.h b/src/appInterface.h index f98fb0cb..9930c51e 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -61,7 +61,11 @@ class IApp { virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0; - virtual bool getProtection(AsyncWebServerRequest *request) = 0; + virtual void lock(void) = 0; + virtual void unlock(const char *clientIp) = 0; + virtual void resetLockTimeout(void) = 0; + virtual bool isProtected(void) const = 0; + virtual bool isProtected(const char *clientIp) const = 0; virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0; virtual uint16_t getHistoryMaxDay() = 0; diff --git a/src/defines.h b/src/defines.h index a4a1d6bd..6d350add 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 69 +#define VERSION_PATCH 70 //------------------------------------- typedef struct { diff --git a/src/utils/spiPatcher.cpp b/src/utils/spiPatcher.cpp index 0470b476..3b7b5681 100644 --- a/src/utils/spiPatcher.cpp +++ b/src/utils/spiPatcher.cpp @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// 2024 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #if defined(ESP32) diff --git a/src/utils/spiPatcher.h b/src/utils/spiPatcher.h index 14cb138c..2f8ce616 100644 --- a/src/utils/spiPatcher.h +++ b/src/utils/spiPatcher.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// 2024 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __SPI_PATCHER_H__ diff --git a/src/web/Protection.cpp b/src/web/Protection.cpp new file mode 100644 index 00000000..b822fb6a --- /dev/null +++ b/src/web/Protection.cpp @@ -0,0 +1,7 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#include "Protection.h" +Protection *Protection::mInstance = nullptr; diff --git a/src/web/Protection.h b/src/web/Protection.h new file mode 100644 index 00000000..44926752 --- /dev/null +++ b/src/web/Protection.h @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------------- +// 2024 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __PROTECTION_H__ +#define __PROTECTION_H__ +#pragma once + +#include +#include + +#include "../config/config.h" +#include "../utils/helper.h" + +class Protection { + protected: + Protection(const char *pwd) { + mPwd = pwd; + mLogoutTimeout = 0; + mLoginIp.fill(0); + + // no password set - unlock + if(pwd[0] == '\0') + mProtected = false; + } + + public: + Protection(Protection &other) = delete; + void operator=(const Protection &) = delete; + + static Protection* getInstance(const char *pwd) { + if(nullptr == mInstance) + mInstance = new Protection(pwd); + return mInstance; + } + + void tickSecond() { + // auto logout + if(0 != mLogoutTimeout) { + if (0 == --mLogoutTimeout) { + if(mPwd[0] == '\0') + mProtected = true; + } + } + } + + void lock(void) { + mProtected = true; + mLoginIp.fill(0); + } + + void unlock(const char *clientIp) { + mProtected = false; + ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); + } + + void resetLockTimeout(void) { + mLogoutTimeout = LOGOUT_TIMEOUT; + } + + bool isProtected(void) const { + return mProtected; + } + + bool isProtected(const char *clientIp) const { + if(mProtected) + return true; + + if(mPwd[0] == '\0') + return false; + + uint8_t ip[4]; + ah::ip2Arr(ip, clientIp); + for(uint8_t i = 0; i < 4; i++) { + if(mLoginIp[i] != ip[i]) + return true; + } + + return true; + } + + protected: + static Protection *mInstance; + + private: + const char *mPwd; + bool mProtected = true; + uint16_t mLogoutTimeout = LOGOUT_TIMEOUT; + std::array mLoginIp; +}; + +#endif /*__PROTECTION_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index ccdc8747..5438566c 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -68,7 +68,7 @@ class RestApi { DynamicJsonDocument json(128); JsonObject dummy = json.as(); if(obj[F("path")] == "ctrl") - setCtrl(obj, dummy); + setCtrl(obj, dummy, "api"); else if(obj[F("path")] == "setup") setSetup(obj, dummy); } @@ -168,7 +168,7 @@ class RestApi { if(!err) { String path = request->url().substring(5); if(path == "ctrl") - root[F("success")] = setCtrl(obj, root); + root[F("success")] = setCtrl(obj, root, request->client()->remoteIP().toString().c_str()); else if(path == "setup") root[F("success")] = setSetup(obj, root); else { @@ -263,7 +263,7 @@ class RestApi { obj[F("modules")] = String(mApp->getVersionModules()); obj[F("build")] = String(AUTO_GIT_HASH); obj[F("env")] = String(ENV_NAME); - obj[F("menu_prot")] = mApp->getProtection(request); + obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str()); obj[F("menu_mask")] = (uint16_t)(mConfig->sys.protectionMask ); obj[F("menu_protEn")] = (bool) (strlen(mConfig->sys.adminPwd) > 0); obj[F("cst_lnk")] = String(mConfig->plugin.customLink); @@ -847,7 +847,7 @@ class RestApi { } - bool setCtrl(JsonObject jsonIn, JsonObject jsonOut) { + bool setCtrl(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); bool accepted = true; if(NULL == iv) { @@ -856,6 +856,13 @@ class RestApi { } jsonOut[F("id")] = jsonIn[F("id")]; + if(strncmp("api", clientIP, 3) != 0) { + if(mApp->isProtected(clientIP)) { + jsonOut[F("error")] = F(INV_IS_PROTECTED); + return false; + } + } + if(F("power") == jsonIn[F("cmd")]) accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff); else if(F("restart") == jsonIn[F("cmd")]) diff --git a/src/web/lang.h b/src/web/lang.h index e55493eb..6cddbc12 100644 --- a/src/web/lang.h +++ b/src/web/lang.h @@ -36,6 +36,12 @@ #define UNKNOWN_CMD "unknown cmd: '" #endif +#ifdef LANG_DE + #define INV_IS_PROTECTED "nicht angemeldet, Kommando nicht möglich!" +#else /*LANG_EN*/ + #define INV_IS_PROTECTED "not logged in, command not possible!" +#endif + #ifdef LANG_DE #define INV_DOES_NOT_ACCEPT_LIMIT_AT_MOMENT "Leistungsbegrenzung / Ansteuerung aktuell nicht möglich" #else /*LANG_EN*/ diff --git a/src/web/web.h b/src/web/web.h index 6de9c877..01e48f74 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -47,9 +47,6 @@ template class Web { public: Web(void) : mWeb(80), mEvts("/events") { - mProtected = true; - mLogoutTimeout = 0; - memset(mSerialBuf, 0, WEB_SERIAL_BUF_SIZE); mSerialBufFill = 0; mSerialAddTime = true; @@ -110,16 +107,6 @@ class Web { } void tickSecond() { - if (0 != mLogoutTimeout) { - mLogoutTimeout -= 1; - if (0 == mLogoutTimeout) { - if (strlen(mConfig->sys.adminPwd) > 0) - mProtected = true; - } - - DPRINTLN(DBG_DEBUG, "auto logout in " + String(mLogoutTimeout)); - } - if (mSerialClientConnnected) { if (mSerialBufFill > 0) { mEvts.send(mSerialBuf, "serial", millis()); @@ -133,27 +120,6 @@ class Web { return &mWeb; } - void setProtection(bool protect) { - mProtected = protect; - } - - bool isProtected(AsyncWebServerRequest *request) { - bool prot; - prot = mProtected; - if(!prot) { - if(strlen(mConfig->sys.adminPwd) > 0) { - uint8_t ip[4]; - ah::ip2Arr(ip, request->client()->remoteIP().toString().c_str()); - for(uint8_t i = 0; i < 4; i++) { - if(mLoginIp[i] != ip[i]) - prot = true; - } - } - } - - return prot; - } - void showUpdate2(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { if (!index) { Serial.printf("Update Start: %s\n", filename.c_str()); @@ -264,7 +230,7 @@ class Web { } void checkProtection(AsyncWebServerRequest *request) { - if(isProtected(request)) { + if(mApp->isProtected(request->client()->remoteIP().toString().c_str())) { checkRedirect(request); return; } @@ -351,8 +317,7 @@ class Web { if (request->args() > 0) { if (String(request->arg("pwd")) == String(mConfig->sys.adminPwd)) { - mProtected = false; - ah::ip2Arr(mLoginIp, request->client()->remoteIP().toString().c_str()); + mApp->unlock(request->client()->remoteIP().toString().c_str()); request->redirect("/"); } } @@ -366,8 +331,7 @@ class Web { DPRINTLN(DBG_VERBOSE, F("onLogout")); checkProtection(request); - - mProtected = true; + mApp->lock(); AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); response->addHeader(F("Content-Encoding"), "gzip"); @@ -390,7 +354,6 @@ class Web { void onCss(AsyncWebServerRequest *request) { DPRINTLN(DBG_VERBOSE, F("onCss")); - mLogoutTimeout = LOGOUT_TIMEOUT; AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/css"), style_css, style_css_len); response->addHeader(F("Content-Encoding"), "gzip"); if(request->hasParam("v")) { @@ -424,6 +387,7 @@ class Web { AsyncWebServerResponse *response = request->beginResponse_P(200, favicon_type, favicon_ico, favicon_ico_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); + mApp->resetLockTimeout(); } void showNotFound(AsyncWebServerRequest *request) { @@ -495,7 +459,7 @@ class Web { // protection if (request->arg("adminpwd") != "{PWD}") { request->arg("adminpwd").toCharArray(mConfig->sys.adminPwd, PWD_LEN); - mProtected = (strlen(mConfig->sys.adminPwd) > 0); + mApp->lock(); } mConfig->sys.protectionMask = 0x0000; for (uint8_t i = 0; i < 7; i++) { @@ -945,9 +909,6 @@ class Web { #endif AsyncWebServer mWeb; AsyncEventSource mEvts; - bool mProtected; - uint32_t mLogoutTimeout; - uint8_t mLoginIp[4]; IApp *mApp; HMSYSTEM *mSys; From 9065ff5b9852d574118ab7639c8dccef04d78a72 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 1 Feb 2024 23:45:21 +0100 Subject: [PATCH 24/79] 0.8.70 * fix login * fix github actions Node.js 16 warnings --- .github/workflows/compile_development.yml | 12 ++++++------ src/web/Protection.h | 11 +++++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 67fa6f0a..4b5a0e1a 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -33,13 +33,13 @@ jobs: - opendtufusion-ethernet steps: - uses: actions/checkout@v4 - - uses: benjlevesque/short-sha@v2.1 + - uses: benjlevesque/short-sha@v2.2 id: short-sha with: length: 7 - name: Cache Pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} @@ -47,7 +47,7 @@ jobs: ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} @@ -93,13 +93,13 @@ jobs: - opendtufusion-ethernet-de steps: - uses: actions/checkout@v4 - - uses: benjlevesque/short-sha@v2.1 + - uses: benjlevesque/short-sha@v2.2 id: short-sha with: length: 7 - name: Cache Pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} @@ -107,7 +107,7 @@ jobs: ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} diff --git a/src/web/Protection.h b/src/web/Protection.h index 44926752..d0c73a9e 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -51,6 +51,7 @@ class Protection { } void unlock(const char *clientIp) { + mLogoutTimeout = LOGOUT_TIMEOUT; mProtected = false; ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); } @@ -70,14 +71,16 @@ class Protection { if(mPwd[0] == '\0') return false; - uint8_t ip[4]; - ah::ip2Arr(ip, clientIp); + std::array ip; + ah::ip2Arr(static_cast(ip.data()), clientIp); for(uint8_t i = 0; i < 4; i++) { - if(mLoginIp[i] != ip[i]) + if(mLoginIp[i] != ip[i]) { + DPRINTLN(DBG_INFO, "ip nicht gleich!"); return true; + } } - return true; + return false; } protected: From 91e816e9413f5c3750d2ae0dbfea6f425e57d45f Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 1 Feb 2024 23:46:39 +0100 Subject: [PATCH 25/79] 0.8.70 --- src/web/Protection.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/web/Protection.h b/src/web/Protection.h index d0c73a9e..710ba8b3 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -74,10 +74,8 @@ class Protection { std::array ip; ah::ip2Arr(static_cast(ip.data()), clientIp); for(uint8_t i = 0; i < 4; i++) { - if(mLoginIp[i] != ip[i]) { - DPRINTLN(DBG_INFO, "ip nicht gleich!"); + if(mLoginIp[i] != ip[i]) return true; - } } return false; From d9696dc70427fb1e7b56c94bbffe9cce45624fd9 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 3 Feb 2024 23:31:17 +0100 Subject: [PATCH 26/79] 0.8.71 * fix heuristics reset * fix CMT missing frames problem * removed inverter gap setting * removed add to total (MqTT) inverter setting * fixed sending commands to inverters which are soft turned off * save settings before they are exported #1395 --- src/CHANGES.md | 8 ++++++++ src/app.cpp | 2 +- src/appInterface.h | 2 +- src/config/config.h | 2 +- src/config/settings.h | 16 ---------------- src/defines.h | 2 +- src/hm/Communication.h | 10 ++-------- src/hm/hmInverter.h | 19 ++++++++----------- src/hms/hmsRadio.h | 4 +++- src/publisher/pubMqttIvData.h | 30 ++++++++++++++---------------- src/web/RestApi.h | 6 +++--- src/web/html/setup.html | 14 +------------- src/web/lang.json | 10 ---------- src/web/web.h | 1 - 14 files changed, 43 insertions(+), 83 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 9835873c..863b6fba 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,13 @@ # Development Changes +## 0.8.71 - 2024-02-03 +* fix heuristics reset +* fix CMT missing frames problem +* removed inverter gap setting +* removed add to total (MqTT) inverter setting +* fixed sending commands to inverters which are soft turned off +* save settings before they are exported #1395 + ## 0.8.70 - 2024-02-01 * prevent sending commands to inverter which isn't active #1387 * protect commands from popup in `/live` if password is set #1199 diff --git a/src/app.cpp b/src/app.cpp index 8b770989..4f49d93b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -64,7 +64,7 @@ void app::setup() { esp_task_wdt_reset(); - mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, &mConfig->inst.gapMs); + mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace); mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); #if defined(ENABLE_MQTT) mCommunication.addPowerLimitAckListener([this] (Inverter<> *iv) { mMqtt.setPowerLimitAck(iv); }); diff --git a/src/appInterface.h b/src/appInterface.h index 9930c51e..6703b5bf 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -18,7 +18,7 @@ class IApp { public: virtual ~IApp() {} - virtual bool saveSettings(bool stopFs) = 0; + virtual bool saveSettings(bool reboot) = 0; virtual void initInverter(uint8_t id) = 0; virtual bool readSettings(const char *path) = 0; virtual bool eraseSettings(bool eraseWifi) = 0; diff --git a/src/config/config.h b/src/config/config.h index a633f3af..9e59f146 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -215,7 +215,7 @@ #define INVERTER_OFF_THRES_SEC 15*60 // threshold of minimum power on which the inverter is marked as inactive -#define INACT_PWR_THRESH 1 +#define INACT_PWR_THRESH 0 // Timezone #define TIMEZONE 1 diff --git a/src/config/settings.h b/src/config/settings.h index e074d5b1..ec9712ea 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -147,7 +147,6 @@ typedef struct { uint8_t frequency; uint8_t powerLevel; bool disNightCom; // disable night communication - bool add2Total; // add values to total values - useful if one inverter is on battery to turn off } cfgIv_t; typedef struct { @@ -161,7 +160,6 @@ typedef struct { bool rstMaxValsMidNight; bool startWithoutTime; float yieldEffiency; - uint16_t gapMs; bool readGrid; } cfgInst_t; @@ -452,14 +450,12 @@ class settings { mCfg.inst.startWithoutTime = false; mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 1.0f; - mCfg.inst.gapMs = 1; mCfg.inst.readGrid = true; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) mCfg.inst.iv[i].disNightCom = false; - mCfg.inst.iv[i].add2Total = true; } mCfg.led.led[0] = DEF_LED0; @@ -491,20 +487,15 @@ class settings { } if(mCfg.configVersion < 2) { mCfg.inst.iv[i].disNightCom = false; - mCfg.inst.iv[i].add2Total = true; } if(mCfg.configVersion < 3) { mCfg.serial.printWholeTrace = false; } - if(mCfg.configVersion < 4) { - mCfg.inst.gapMs = 500; - } if(mCfg.configVersion < 5) { mCfg.inst.sendInterval = SEND_INTERVAL; mCfg.serial.printWholeTrace = false; } if(mCfg.configVersion < 6) { - mCfg.inst.gapMs = 500; mCfg.inst.readGrid = true; } if(mCfg.configVersion < 7) { @@ -513,9 +504,6 @@ class settings { if(mCfg.configVersion < 8) { mCfg.sun.offsetSecEvening = mCfg.sun.offsetSecMorning; } - if(mCfg.configVersion < 9) { - mCfg.inst.gapMs = 1; - } if(mCfg.configVersion < 10) { mCfg.sys.region = 0; // Europe mCfg.sys.timezone = 1; @@ -768,7 +756,6 @@ class settings { obj[F("strtWthtTime")] = (bool)mCfg.inst.startWithoutTime; obj[F("rstMaxMidNight")] = (bool)mCfg.inst.rstMaxValsMidNight; obj[F("yldEff")] = mCfg.inst.yieldEffiency; - obj[F("gap")] = mCfg.inst.gapMs; obj[F("rdGrid")] = (bool)mCfg.inst.readGrid; } else { @@ -780,7 +767,6 @@ class settings { getVal(obj, F("strtWthtTime"), &mCfg.inst.startWithoutTime); getVal(obj, F("rstMaxMidNight"), &mCfg.inst.rstMaxValsMidNight); getVal(obj, F("yldEff"), &mCfg.inst.yieldEffiency); - getVal(obj, F("gap"), &mCfg.inst.gapMs); getVal(obj, F("rdGrid"), &mCfg.inst.readGrid); if(mCfg.inst.yieldEffiency < 0.5) @@ -809,7 +795,6 @@ class settings { obj[F("freq")] = cfg->frequency; obj[F("pa")] = cfg->powerLevel; obj[F("dis")] = cfg->disNightCom; - obj[F("add")] = cfg->add2Total; for(uint8_t i = 0; i < 6; i++) { obj[F("yield")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; @@ -822,7 +807,6 @@ class settings { getVal(obj, F("freq"), &cfg->frequency); getVal(obj, F("pa"), &cfg->powerLevel); getVal(obj, F("dis"), &cfg->disNightCom); - getVal(obj, F("add"), &cfg->add2Total); uint8_t size = 4; if(obj.containsKey(F("pwr"))) size = obj[F("pwr")].size(); diff --git a/src/defines.h b/src/defines.h index 6d350add..6fbc5ff1 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 70 +#define VERSION_PATCH 71 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 4895d2e7..4350eac7 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -20,12 +20,11 @@ typedef std::function *)> alarmListenerType; class Communication : public CommQueue<> { public: - void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint16_t *inverterGap) { + void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace) { mTimestamp = timestamp; mPrivacyMode = privacyMode; mSerialDebug = serialDebug; mPrintWholeTrace = printWholeTrace; - mInverterGap = inverterGap; } void addImportant(Inverter<> *iv, uint8_t cmd) { @@ -524,10 +523,6 @@ class Communication : public CommQueue<> { return; } - /*DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(q->cmd);*/ - memset(mPayload, 0, MAX_BUFFER); int8_t rssi = -127; uint8_t len = 0; @@ -623,7 +618,7 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFail++; // got no complete payload else q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mWaitTime.startTimeMonitor(*mInverterGap); + mWaitTime.startTimeMonitor(1); // maybe remove, side effects unknown bool keep = false; if(q->isDevControl) @@ -1025,7 +1020,6 @@ class Communication : public CommQueue<> { States mState = States::RESET; uint32_t *mTimestamp; bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; - uint16_t *mInverterGap; TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) std::array mLocalBuf; bool mFirstTry = false; // see, if we should do a second try diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index a5276880..d9db0b7f 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -184,7 +184,7 @@ class Inverter { void tickSend(std::function cb) { if(mDevControlRequest) { - if(InverterStatus::PRODUCING == status) + if(InverterStatus::OFF != status) cb(devControlCmd, true); else DPRINTLN(DBG_WARN, F("Inverter is not avail")); @@ -447,17 +447,14 @@ class Inverter { status = InverterStatus::STARTING; } else { if((*timestamp - recordMeas.ts) > INVERTER_OFF_THRES_SEC) { - status = InverterStatus::OFF; - actPowerLimit = 0xffff; // power limit will be read once inverter becomes available - alarmMesIndex = 0; - if(INV_RADIO_TYPE_NRF == ivRadioType) { - heuristics.clear(); - #ifdef DYNAMIC_OFFSET - rxOffset = ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting - #endif + if(status != InverterStatus::OFF) { + status = InverterStatus::OFF; + actPowerLimit = 0xffff; // power limit will be read once inverter becomes available + alarmMesIndex = 0; + if(INV_RADIO_TYPE_NRF == ivRadioType) + heuristics.clear(); } - } - else + } else status = InverterStatus::WAS_ON; } diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index ae9fd369..dd9af3ac 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -176,8 +176,10 @@ class CmtRadio : public Radio { if(CmtStatus::SUCCESS == status) mBufCtrl.push(p); - if(p.packet[9] > ALL_FRAMES) // indicates last frame + if(p.packet[9] > ALL_FRAMES) { // indicates last frame + setExpectedFrames(p.packet[9] - ALL_FRAMES); mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? + } // optionally instead: // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... } diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index a096ebc6..64f72e1e 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -149,23 +149,21 @@ class PubMqttIvData { // calculate total values for RealTimeRunData_Debug if (CH0 == rec->assign[mPos].ch) { if(mIv->getStatus() != InverterStatus::OFF) { - if(mIv->config->add2Total) { - mTotalFound = true; - switch (rec->assign[mPos].fieldId) { - case FLD_PAC: - mTotal[0] += mIv->getValue(mPos, rec); - break; - case FLD_YT: - mTotal[1] += mIv->getValue(mPos, rec); - break; - case FLD_YD: { - mTotal[2] += mIv->getValue(mPos, rec); - break; - } - case FLD_PDC: - mTotal[3] += mIv->getValue(mPos, rec); - break; + mTotalFound = true; + switch (rec->assign[mPos].fieldId) { + case FLD_PAC: + mTotal[0] += mIv->getValue(mPos, rec); + break; + case FLD_YT: + mTotal[1] += mIv->getValue(mPos, rec); + break; + case FLD_YD: { + mTotal[2] += mIv->getValue(mPos, rec); + break; } + case FLD_PDC: + mTotal[3] += mIv->getValue(mPos, rec); + break; } } else mAllTotalFound = false; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 5438566c..b2041ee7 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -216,6 +216,9 @@ class RestApi { void onDwnldSetup(AsyncWebServerRequest *request) { AsyncWebServerResponse *response; + // save settings to have latest firmware changes in export + mApp->saveSettings(false); + File fp = LittleFS.open("/settings.json", "r"); if(!fp) { DPRINTLN(DBG_ERROR, F("failed to load settings")); @@ -459,7 +462,6 @@ class RestApi { obj2[F("channels")] = iv->channels; obj2[F("freq")] = iv->config->frequency; obj2[F("disnightcom")] = (bool)iv->config->disNightCom; - obj2[F("add2total")] = (bool)iv->config->add2Total; if(0xff == iv->config->powerLevel) { if((IV_HMT == iv->ivGen) || (IV_HMS == iv->ivGen)) obj2[F("pa")] = 30; // 20dBm @@ -483,7 +485,6 @@ class RestApi { obj[F("rdGrid")] = (bool)mConfig->inst.readGrid; obj[F("rstMaxMid")] = (bool)mConfig->inst.rstMaxValsMidNight; obj[F("yldEff")] = mConfig->inst.yieldEffiency; - obj[F("gap")] = mConfig->inst.gapMs; } void getInverter(JsonObject obj, uint8_t id) { @@ -936,7 +937,6 @@ class RestApi { iv->config->frequency = jsonIn[F("freq")]; iv->config->powerLevel = jsonIn[F("pa")]; iv->config->disNightCom = jsonIn[F("disnightcom")]; - iv->config->add2Total = jsonIn[F("add2total")]; mApp->saveSettings(false); // without reboot } else { jsonOut[F("error")] = F(UNKNOWN_CMD); diff --git a/src/web/html/setup.html b/src/web/html/setup.html index d4f245ef..dec62830 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -149,10 +149,6 @@
{#INTERVAL} [s]
-
-
{#INV_GAP} [ms]
-
-
{#INV_RESET_MIDNIGHT}
@@ -630,7 +626,7 @@ } function ivGlob(obj) { - for(var i of [["invInterval", "interval"], ["yldEff", "yldEff"], ["invGap", "gap"]]) + for(var i of [["invInterval", "interval"], ["yldEff", "yldEff"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; for(var i of ["Mid", "ComStop", "NotAvail", "MaxMid"]) document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i]; @@ -715,7 +711,6 @@ add.ch_yield_cor = []; add.freq = 12; add.pa = 30; - add.add2total = true; var e = document.getElementById("inverter"); e.innerHTML = ""; // remove all childs @@ -746,10 +741,8 @@ var cbEn = ml("input", {name: "enable", type: "checkbox"}, null); var cbDisNightCom = ml("input", {name: "disnightcom", type: "checkbox"}, null); - var cbAddTotal = ml("input", {name: "add2total", type: "checkbox"}, null); cbEn.checked = (obj.enabled); cbDisNightCom.checked = (obj.disnightcom); - cbAddTotal.checked = (obj.add2total); var ser = ml("input", {name: "ser", class: "text", type: "number", max: 138999999999, value: obj.serial}, null); var html = ml("div", {}, [ @@ -798,10 +791,6 @@ ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-10"}, "{#INV_PAUSE_DURING_NIGHT}"), ml("div", {class: "col-2"}, cbDisNightCom) - ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-10"}, "{#INV_INCLUDE_MQTT_SUM}"), - ml("div", {class: "col-2"}, cbAddTotal) ]) ]), ml("div", {class: "row mt-5"}, [ @@ -867,7 +856,6 @@ o.pa = document.getElementsByName("cmtpa")[0].value; o.freq = document.getElementsByName("freq")[0].value; o.disnightcom = document.getElementsByName("disnightcom")[0].checked; - o.add2total = document.getElementsByName("add2total")[0].checked; getAjax("/api/setup", cb, "POST", JSON.stringify(o)); } diff --git a/src/web/lang.json b/src/web/lang.json index 1617658a..92f046a5 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -288,11 +288,6 @@ "en": "Interval", "de": "Intervall" }, - { - "token": "INV_GAP", - "en": "Communication Gap", - "de": "Kommunikationslücke" - }, { "token": "INV_RESET_MIDNIGHT", "en": "Reset values and YieldDay at midnight", @@ -663,11 +658,6 @@ "en": "Pause communication during night (lat. and lon. need to be set)", "de": "Kommunikation während der Nacht pausieren (Breiten- und Längengrad müssen gesetzt sein" }, - { - "token": "INV_INCLUDE_MQTT_SUM", - "en": "Include inverter to sum of total (should be checked by default, MqTT only)", - "de": "Wechselrichter in Liste der aufzuaddierenden Wechselrichter aufnehmen (nur MqTT)" - }, { "token": "BTN_SAVE", "en": "save", diff --git a/src/web/web.h b/src/web/web.h index 01e48f74..77a059cb 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -488,7 +488,6 @@ class Web { mConfig->inst.readGrid = (request->arg("rdGrid") == "on"); mConfig->inst.rstMaxValsMidNight = (request->arg("invRstMaxMid") == "on"); mConfig->inst.yieldEffiency = (request->arg("yldEff")).toFloat(); - mConfig->inst.gapMs = (request->arg("invGap")).toInt(); // pinout From 80d07ae6fee47d27b86526873b77087a2159e906 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 4 Feb 2024 00:19:26 +0100 Subject: [PATCH 27/79] 0.8.71 * fix autologin bug if no password is set * translated `/serial` --- src/CHANGES.md | 2 ++ src/web/Protection.h | 2 +- src/web/RestApi.h | 4 +++- src/web/html/serial.html | 10 +++++----- src/web/lang.json | 30 ++++++++++++++++++++++++++++++ src/web/web.h | 1 - 6 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 863b6fba..b661b8d2 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -7,6 +7,8 @@ * removed add to total (MqTT) inverter setting * fixed sending commands to inverters which are soft turned off * save settings before they are exported #1395 +* fix autologin bug if no password is set +* translated `/serial` ## 0.8.70 - 2024-02-01 * prevent sending commands to inverter which isn't active #1387 diff --git a/src/web/Protection.h b/src/web/Protection.h index 710ba8b3..0c7b8379 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -39,7 +39,7 @@ class Protection { // auto logout if(0 != mLogoutTimeout) { if (0 == --mLogoutTimeout) { - if(mPwd[0] == '\0') + if(mPwd[0] != '\0') mProtected = true; } } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index b2041ee7..e6760390 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -259,6 +259,8 @@ class RestApi { } void getGeneric(AsyncWebServerRequest *request, JsonObject obj) { + mApp->resetLockTimeout(); + obj[F("wifi_rssi")] = (WiFi.status() != WL_CONNECTED) ? 0 : WiFi.RSSI(); obj[F("ts_uptime")] = mApp->getUptime(); obj[F("ts_now")] = mApp->getTimestamp(); @@ -268,7 +270,7 @@ class RestApi { obj[F("env")] = String(ENV_NAME); obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str()); obj[F("menu_mask")] = (uint16_t)(mConfig->sys.protectionMask ); - obj[F("menu_protEn")] = (bool) (strlen(mConfig->sys.adminPwd) > 0); + obj[F("menu_protEn")] = (bool) (mConfig->sys.adminPwd[0] != '\0'); obj[F("cst_lnk")] = String(mConfig->plugin.customLink); obj[F("cst_lnk_txt")] = String(mConfig->plugin.customLinkText); obj[F("region")] = mConfig->sys.region; diff --git a/src/web/html/serial.html b/src/web/html/serial.html index 25940eb0..83e614c8 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -12,12 +12,12 @@
-
console active:
-
Uptime:
+
{#CONSOLE_ACTIVE}:
+
{#UPTIME}:
- - - + + +
diff --git a/src/web/lang.json b/src/web/lang.json index 92f046a5..78c7d653 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -865,6 +865,36 @@ } ] }, + { + "name": "serial.html", + "list": [ + { + "token": "BTN_CLEAR", + "en": "clear", + "de": "l&ouuml;schen" + }, + { + "token": "BTN_AUTOSCROLL", + "en": "autoscroll", + "de": "automatisch scrollen" + }, + { + "token": "BTN_COPY", + "en": "copy", + "de": "kopieren" + }, + { + "token": "CONSOLE_ACTIVE", + "en": "console active", + "de": "Konsole aktiv" + }, + { + "token": "UPTIME", + "en": "uptime", + "de": "Laufzeit" + } + ] + }, { "name": "index.html", "list": [ diff --git a/src/web/web.h b/src/web/web.h index 77a059cb..0ffd0594 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -387,7 +387,6 @@ class Web { AsyncWebServerResponse *response = request->beginResponse_P(200, favicon_type, favicon_ico, favicon_ico_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); - mApp->resetLockTimeout(); } void showNotFound(AsyncWebServerRequest *request) { From 2e94f2844137dcac147adebafe2c5acf5d6721a0 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 4 Feb 2024 00:24:44 +0100 Subject: [PATCH 28/79] 0.8.71 * removed "yield day" history --- src/CHANGES.md | 1 + src/plugins/history.h | 13 +++++++------ src/web/RestApi.h | 20 -------------------- src/web/html/history.html | 22 ---------------------- 4 files changed, 8 insertions(+), 48 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index b661b8d2..4a2e91f6 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -9,6 +9,7 @@ * save settings before they are exported #1395 * fix autologin bug if no password is set * translated `/serial` +* removed "yield day" history ## 0.8.70 - 2024-02-01 * prevent sending commands to inverter which isn't active #1387 diff --git a/src/plugins/history.h b/src/plugins/history.h index da57800f..7a938284 100644 --- a/src/plugins/history.h +++ b/src/plugins/history.h @@ -52,8 +52,8 @@ class HistoryData { mCurPwr.reset(); mCurPwr.refreshCycle = mConfig->inst.sendInterval; - mYieldDay.reset(); - mYieldDay.refreshCycle = 60; + //mYieldDay.reset(); + //mYieldDay.refreshCycle = 60; } void tickerSecond() { @@ -80,7 +80,7 @@ class HistoryData { mMaximumDay = roundf(maxPwr); } - if((++mYieldDay.loopCnt % mYieldDay.refreshCycle) == 0) { + /*if((++mYieldDay.loopCnt % mYieldDay.refreshCycle) == 0) { if (*mTs > mApp->getSunset()) { if ((!mDayStored) && (yldDay > 0)) { addValue(&mYieldDay, roundf(yldDay)); @@ -88,11 +88,12 @@ class HistoryData { } } else if (*mTs > mApp->getSunrise()) mDayStored = false; - } + }*/ } uint16_t valueAt(HistoryStorageType type, uint16_t i) { - storage_t *s = (HistoryStorageType::POWER == type) ? &mCurPwr : &mYieldDay; + //storage_t *s = (HistoryStorageType::POWER == type) ? &mCurPwr : &mYieldDay; + storage_t *s = &mCurPwr; uint16_t idx = (s->dispIdx + i) % HISTORY_DATA_ARR_LENGTH; return s->data[idx]; } @@ -119,7 +120,7 @@ class HistoryData { uint32_t *mTs; storage_t mCurPwr; - storage_t mYieldDay; + //storage_t mYieldDay; bool mDayStored = false; uint16_t mMaximumDay = 0; }; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index e6760390..240a18f2 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -107,7 +107,6 @@ class RestApi { #endif /* !defined(ETHERNET) */ else if(path == "live") getLive(request,root); else if (path == "powerHistory") getPowerHistory(request, root); - else if (path == "yieldDayHistory") getYieldDayHistory(request, root); else { if(path.substring(0, 12) == "inverter/id/") getInverter(root, request->url().substring(17).toInt()); @@ -208,7 +207,6 @@ class RestApi { ep[F("live")] = url + F("live"); #if defined(ENABLE_HISTORY) ep[F("powerHistory")] = url + F("powerHistory"); - ep[F("yieldDayHistory")] = url + F("yieldDayHistory"); #endif } @@ -832,24 +830,6 @@ class RestApi { #endif /*ENABLE_HISTORY*/ } - void getYieldDayHistory(AsyncWebServerRequest *request, JsonObject obj) { - getGeneric(request, obj.createNestedObject(F("generic"))); - #if defined(ENABLE_HISTORY) - obj[F("refresh")] = 86400; // 1 day - uint16_t max = 0; - for (uint16_t fld = 0; fld < HISTORY_DATA_ARR_LENGTH; fld++) { - uint16_t value = mApp->getHistoryValue((uint8_t)HistoryStorageType::YIELD, fld); - obj[F("value")][fld] = value; - if (value > max) - max = value; - } - obj[F("max")] = max; - #else - obj[F("refresh")] = 86400; // 1 day - #endif /*ENABLE_HISTORY*/ - } - - bool setCtrl(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); bool accepted = true; diff --git a/src/web/html/history.html b/src/web/html/history.html index 975a02ed..b553a19f 100644 --- a/src/web/html/history.html +++ b/src/web/html/history.html @@ -20,14 +20,6 @@ {#MAXIMUM}: W. {#UPDATED} {#SECONDS}

-

{#TOTAL_YIELD_PER_DAY}

-
-
-

- {#MAXIMUM}: Wh
- {#UPDATED} {#SECONDS} -

-
{#HTML_FOOTER} @@ -94,20 +86,6 @@ if (pwrExeOnce) { pwrExeOnce = false; window.setInterval("getAjax('/api/powerHistory', parsePowerHistory)", mRefresh * 1000); - - setTimeout(() => { - getAjax("/api/yieldDayHistory", parseYieldDayHistory); - } , 20); - } - } - function parseYieldDayHistory(obj) { - if (null != obj) { - parseNav(obj.generic); - parseHistory(obj, "yd", ydExeOnce) - } - if (ydExeOnce) { - ydExeOnce = false; - window.setInterval("getAjax('/api/yieldDayHistory', parseYieldDayHistory)", mRefresh * 500); } } From 883aefbe643ce04c6fe45882479f560ecd33db16 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 4 Feb 2024 00:31:39 +0100 Subject: [PATCH 29/79] 0.8.71 * fix html --- src/web/html/history.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/web/html/history.html b/src/web/html/history.html index b553a19f..7e317b59 100644 --- a/src/web/html/history.html +++ b/src/web/html/history.html @@ -79,6 +79,7 @@ function parsePowerHistory(obj){ if (null != obj) { + parseNav(obj.generic); parseHistory(obj,"pwr", pwrExeOnce) document.getElementById("pwrLast").innerHTML = mLastValue document.getElementById("pwrMaxDay").innerHTML = obj.maxDay From 14c5a7ad3227c3701ecaef8b2dea8bea13dfbd9d Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 4 Feb 2024 13:21:02 +0100 Subject: [PATCH 30/79] 0.8.72 * fixed translation #1403 * fixed sending commands to inverters which are soft turned off #1397 * reduce switchChannel command for HMS (only each 5th cycle it will be send now) --- src/CHANGES.md | 5 +++++ src/defines.h | 2 +- src/hm/hmInverter.h | 9 ++++----- src/hms/hmsRadio.h | 12 ++++++++++-- src/web/RestApi.h | 12 +++++++----- src/web/lang.json | 2 +- 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 4a2e91f6..82a6ed45 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.72 - 2024-02-03 +* fixed translation #1403 +* fixed sending commands to inverters which are soft turned off #1397 +* reduce switchChannel command for HMS (only each 5th cycle it will be send now) + ## 0.8.71 - 2024-02-03 * fix heuristics reset * fix CMT missing frames problem diff --git a/src/defines.h b/src/defines.h index 6fbc5ff1..f0ec528d 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 71 +#define VERSION_PATCH 72 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index d9db0b7f..b62e985a 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -152,7 +152,6 @@ class Inverter { static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup - //static IApp *app; // pointer to app interface public: @@ -290,18 +289,18 @@ class Inverter { } bool setDevControlRequest(uint8_t cmd) { - if(InverterStatus::PRODUCING == status) { + if(InverterStatus::OFF != status) { mDevControlRequest = true; devControlCmd = cmd; //app->triggerTickSend(); // done in RestApi.h, because of "chicken-and-egg problem ;-)" } - return (InverterStatus::PRODUCING == status); + return (InverterStatus::OFF != status); } bool setDevCommand(uint8_t cmd) { - if(InverterStatus::PRODUCING == status) + if(InverterStatus::OFF != status) devControlCmd = cmd; - return (InverterStatus::PRODUCING == status); + return (InverterStatus::OFF != status); } void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index dd9af3ac..0fa1b6ab 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -9,6 +9,8 @@ #include "cmt2300a.h" #include "../hm/radio.h" +#define CMT_SWITCH_CHANNEL_CYCLE 5 + template class CmtRadio : public Radio { typedef Cmt2300a CmtType; @@ -151,6 +153,10 @@ class CmtRadio : public Radio { } inline void sendSwitchChCmd(Inverter<> *iv, uint8_t ch) { + if(CMT_SWITCH_CHANNEL_CYCLE > ++mSwitchCycle) + return; + mSwitchCycle = 0; + /** ch: * 0x00: 860.00 MHz * 0x01: 860.25 MHz @@ -172,9 +178,10 @@ class CmtRadio : public Radio { inline void getRx(void) { packet_t p; p.millis = millis() - mMillis; - CmtStatus status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); - if(CmtStatus::SUCCESS == status) + if(CmtStatus::SUCCESS == mCmt.getRx(p.packet, &p.len, 28, &p.rssi)) { + mSwitchCycle = 0; mBufCtrl.push(p); + } if(p.packet[9] > ALL_FRAMES) { // indicates last frame setExpectedFrames(p.packet[9] - ALL_FRAMES); @@ -188,6 +195,7 @@ class CmtRadio : public Radio { bool mCmtAvail = false; bool mRqstGetRx = false; uint32_t mMillis; + uint8_t mSwitchCycle = 0; }; #endif /*__HMS_RADIO_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 240a18f2..564d6c62 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -68,7 +68,7 @@ class RestApi { DynamicJsonDocument json(128); JsonObject dummy = json.as(); if(obj[F("path")] == "ctrl") - setCtrl(obj, dummy, "api"); + setCtrl(obj, dummy, "*"); else if(obj[F("path")] == "setup") setSetup(obj, dummy); } @@ -839,10 +839,12 @@ class RestApi { } jsonOut[F("id")] = jsonIn[F("id")]; - if(strncmp("api", clientIP, 3) != 0) { - if(mApp->isProtected(clientIP)) { - jsonOut[F("error")] = F(INV_IS_PROTECTED); - return false; + if(mConfig->sys.adminPwd[0] != '\0') { + if(strncmp("*", clientIP, 1) != 0) { // no call from API (MqTT) + if(mApp->isProtected(clientIP)) { + jsonOut[F("error")] = F(INV_IS_PROTECTED); + return false; + } } } diff --git a/src/web/lang.json b/src/web/lang.json index 78c7d653..689fbb06 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -871,7 +871,7 @@ { "token": "BTN_CLEAR", "en": "clear", - "de": "l&ouuml;schen" + "de": "löschen" }, { "token": "BTN_AUTOSCROLL", From 6b5435a2467bb1ba745d40213f1b7e4d0db359e6 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 4 Feb 2024 21:26:48 +0100 Subject: [PATCH 31/79] 0.8.73 * fix nullpointer during communication #1401 * added `max_power` to MqTT total values #1375 --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/hm/Communication.h | 33 ++++++++++++++++----------------- src/publisher/pubMqttIvData.h | 13 ++++++++++--- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 82a6ed45..813f1708 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.73 - 2024-02-03 +* fix nullpointer during communication #1401 +* added `max_power` to MqTT total values #1375 + ## 0.8.72 - 2024-02-03 * fixed translation #1403 * fixed sending commands to inverters which are soft turned off #1397 diff --git a/src/defines.h b/src/defines.h index f0ec528d..b71a1d25 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 72 +#define VERSION_PATCH 73 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 4350eac7..d1521f81 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -295,12 +295,14 @@ class Communication : public CommQueue<> { return; } - compilePayload(q); + if(compilePayload(q)) { + if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) + (mCbPayload)(q->cmd, q->iv); - if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) - (mCbPayload)(q->cmd, q->iv); + closeRequest(q, true); + } else + closeRequest(q, false); - closeRequest(q, true); break; } } @@ -498,7 +500,7 @@ class Communication : public CommQueue<> { return accepted; } - inline void compilePayload(const queue_s *q) { + inline bool compilePayload(const queue_s *q) { uint16_t crc = 0xffff, crcRcv = 0x0000; for(uint8_t i = 0; i < mMaxFrameId; i++) { if(i == (mMaxFrameId - 1)) { @@ -514,13 +516,12 @@ class Communication : public CommQueue<> { DBGPRINT(F("CRC Error ")); if(q->attempts == 0) { DBGPRINTLN(F("-> Fail")); - closeRequest(q, false); } else DBGPRINTLN(F("-> complete retransmit")); mCompleteRetry = true; mState = States::RESET; - return; + return false; } memset(mPayload, 0, MAX_BUFFER); @@ -530,7 +531,7 @@ class Communication : public CommQueue<> { for(uint8_t i = 0; i < mMaxFrameId; i++) { if(mLocalBuf[i].len + len > MAX_BUFFER) { DPRINTLN(DBG_ERROR, F("payload buffer to small!")); - return; + return true; } memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); len += mLocalBuf[i].len; @@ -552,19 +553,18 @@ class Communication : public CommQueue<> { if(GridOnProFilePara == q->cmd) { q->iv->addGridProfile(mPayload, len); - return; + return true; } record_t<> *rec = q->iv->getRecordStruct(q->cmd); if(NULL == rec) { if(GetLossRate == q->cmd) { q->iv->parseGetLossRate(mPayload, len); - return; - } else { + return true; + } else DPRINTLN(DBG_ERROR, F("record is NULL!")); - closeRequest(q, false); - } - return; + + return false; } if((rec->pyldLen != len) && (0 != rec->pyldLen)) { if(*mSerialDebug) { @@ -572,10 +572,8 @@ class Communication : public CommQueue<> { DBGPRINT(String(rec->pyldLen)); DBGPRINTLN(F(" bytes")); } - /*q->iv->radioStatistics.rxFail++;*/ - closeRequest(q, false); - return; + return false; } rec->ts = q->ts; @@ -597,6 +595,7 @@ class Communication : public CommQueue<> { yield(); } } + return true; } void sendRetransmit(const queue_s *q, uint8_t i) { diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 64f72e1e..cfed38b9 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -78,7 +78,7 @@ class PubMqttIvData { if((RealTimeRunData_Debug != mCmd) || !mRTRDataHasBeenSent) { // send RealTimeRunData only once mSendTotals = (RealTimeRunData_Debug == mCmd); - memset(mTotal, 0, sizeof(float) * 4); + memset(mTotal, 0, sizeof(float) * 5); mState = FIND_NXT_IV; } else mSendList->pop(); @@ -164,6 +164,9 @@ class PubMqttIvData { case FLD_PDC: mTotal[3] += mIv->getValue(mPos, rec); break; + case FLD_MP: + mTotal[4] += mIv->getValue(mPos, rec); + break; } } else mAllTotalFound = false; @@ -204,7 +207,7 @@ class PubMqttIvData { void stateSendTotals() { uint8_t fieldId; mRTRDataHasBeenSent = true; - if(mPos < 4) { + if(mPos < 5) { bool retained = true; switch (mPos) { default: @@ -230,6 +233,10 @@ class PubMqttIvData { fieldId = FLD_PDC; retained = false; break; + case 4: + fieldId = FLD_MP; + retained = false; + break; } snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); snprintf(mVal, 40, "%g", ah::round3(mTotal[mPos])); @@ -251,7 +258,7 @@ class PubMqttIvData { uint8_t mCmd; uint8_t mLastIvId; bool mSendTotals, mTotalFound, mAllTotalFound, mSendTotalYd; - float mTotal[4], mYldTotalStore; + float mTotal[5], mYldTotalStore; Inverter<> *mIv, *mIvSend; uint8_t mPos; From 3740a09d2a04e46da340d98cb3479a54a55b0f61 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 5 Feb 2024 23:58:52 +0100 Subject: [PATCH 32/79] 0.8.74 * reduced cppcheck linter warnings significantly --- src/CHANGES.md | 3 + src/app.cpp | 15 ++- src/app.h | 100 ++++++++--------- src/config/settings.h | 7 +- src/defines.h | 2 +- src/hm/CommQueue.h | 2 +- src/hm/Communication.h | 39 ++++--- src/hm/Heuristic.h | 7 +- src/hm/hmDefines.h | 2 +- src/hm/hmInverter.h | 141 ++++++++++------------- src/hm/hmRadio.h | 27 +++-- src/hm/hmSystem.h | 14 +-- src/hm/nrfHal.h | 2 +- src/hm/radio.h | 8 +- src/hms/cmt2300a.h | 15 +-- src/hms/cmtHal.h | 2 +- src/hms/esp32_3wSpi.h | 7 +- src/hms/hmsRadio.h | 25 ++--- src/plugins/Display/Display.h | 11 +- src/plugins/Display/Display_Mono.h | 12 +- src/plugins/history.h | 33 ++---- src/publisher/pubMqtt.h | 172 +++++++++++++++-------------- src/publisher/pubMqttIvData.h | 2 +- src/publisher/pubSerial.h | 12 +- src/utils/improv.h | 16 +-- src/utils/scheduler.h | 16 ++- src/utils/spiPatcher.h | 2 +- src/utils/timemonitor.h | 6 +- src/web/RestApi.h | 24 ++-- src/web/web.h | 48 ++++---- src/wifi/ahoywifi.h | 16 +-- 31 files changed, 375 insertions(+), 413 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 813f1708..f0491335 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.74 - 2024-02-05 +* reduced cppcheck linter warnings significantly + ## 0.8.73 - 2024-02-03 * fix nullpointer during communication #1401 * added `max_power` to MqTT total values #1375 diff --git a/src/app.cpp b/src/app.cpp index 4f49d93b..d9b0f933 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -13,7 +13,10 @@ //----------------------------------------------------------------------------- -app::app() : ah::Scheduler {} {} +app::app() : ah::Scheduler {} { + memset(mVersion, 0, sizeof(char) * 12); + memset(mVersionModules, 0, sizeof(char) * 12); +} //----------------------------------------------------------------------------- @@ -228,7 +231,6 @@ void app::updateNtp(void) { onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); if (mConfig->sys.schedReboot) { - uint32_t localTime = gTimezone.toLocal(mTimestamp); uint32_t rebootTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86410); // reboot 10 secs after midnght if (rebootTrig <= mTimestamp) { //necessary for times other than midnight to prevent reboot loop rebootTrig += 86400; @@ -301,9 +303,8 @@ void app::tickIVCommunication(void) { bool zeroValues = false; uint32_t nxtTrig = 0; - Inverter<> *iv; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { - iv = mSys.getInverterByPos(i); + Inverter<> *iv = mSys.getInverterByPos(i); if(NULL == iv) continue; @@ -390,10 +391,9 @@ void app::tickMidnight(void) { // clear max values if(mConfig->inst.rstMaxValsMidNight) { - uint8_t pos; record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); for(uint8_t i = 0; i <= iv->channels; i++) { - pos = iv->getPosByChFld(i, FLD_MP, rec); + uint8_t pos = iv->getPosByChFld(i, FLD_MP, rec); iv->setValue(pos, rec, 0.0f); } } @@ -592,9 +592,8 @@ void app::updateLed(void) { uint8_t led_on = (mConfig->led.high_active) ? (mConfig->led.luminance) : (255-mConfig->led.luminance); if (mConfig->led.led[0] != DEF_PIN_OFF) { - Inverter<> *iv; for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { - iv = mSys.getInverterByPos(id); + Inverter<> *iv = mSys.getInverterByPos(id); if (NULL != iv) { if (iv->isProducing()) { // turn on when at least one inverter is producing diff --git a/src/app.h b/src/app.h index b44d3781..60be4d1d 100644 --- a/src/app.h +++ b/src/app.h @@ -90,7 +90,7 @@ class app : public IApp, public ah::Scheduler { void handleIntr(void) { mNrfRadio.handleIntr(); } - void* getRadioObj(bool nrf) { + void* getRadioObj(bool nrf) override { if(nrf) return (void*)&mNrfRadio; else { @@ -108,19 +108,19 @@ class app : public IApp, public ah::Scheduler { } #endif - uint32_t getUptime() { + uint32_t getUptime() override { return Scheduler::getUptime(); } - uint32_t getTimestamp() { + uint32_t getTimestamp() override { return Scheduler::mTimestamp; } - uint64_t getTimestampMs() { + uint64_t getTimestampMs() override { return ((uint64_t)Scheduler::mTimestamp * 1000) + ((uint64_t)millis() - (uint64_t)Scheduler::mTsMillis) % 1000; } - bool saveSettings(bool reboot) { + bool saveSettings(bool reboot) override { mShowRebootRequest = true; // only message on index, no reboot mSavePending = true; mSaveReboot = reboot; @@ -131,7 +131,7 @@ class app : public IApp, public ah::Scheduler { return true; } - void initInverter(uint8_t id) { + void initInverter(uint8_t id) override { mSys.addInverter(id, [this](Inverter<> *iv) { if((IV_MI == iv->ivGen) || (IV_HM == iv->ivGen)) iv->radio = &mNrfRadio; @@ -142,7 +142,7 @@ class app : public IApp, public ah::Scheduler { }); } - bool readSettings(const char *path) { + bool readSettings(const char *path) override { return mSettings.readSettings(path); } @@ -150,80 +150,80 @@ class app : public IApp, public ah::Scheduler { return mSettings.eraseSettings(eraseWifi); } - bool getSavePending() { + bool getSavePending() override { return mSavePending; } - bool getLastSaveSucceed() { + bool getLastSaveSucceed() override { return mSettings.getLastSaveSucceed(); } - bool getShouldReboot() { + bool getShouldReboot() override { return mSaveReboot; } #if !defined(ETHERNET) - void scanAvailNetworks() { + void scanAvailNetworks() override { mWifi.scanAvailNetworks(); } - bool getAvailNetworks(JsonObject obj) { + bool getAvailNetworks(JsonObject obj) override { return mWifi.getAvailNetworks(obj); } - void setupStation(void) { + void setupStation(void) override { mWifi.setupStation(); } - void setStopApAllowedMode(bool allowed) { + void setStopApAllowedMode(bool allowed) override { mWifi.setStopApAllowedMode(allowed); } - String getStationIp(void) { + String getStationIp(void) override { return mWifi.getStationIp(); } - bool getWasInCh12to14(void) const { + bool getWasInCh12to14(void) const override { return mWifi.getWasInCh12to14(); } #endif /* !defined(ETHERNET) */ - void setRebootFlag() { + void setRebootFlag() override { once(std::bind(&app::tickReboot, this), 3, "rboot"); } - const char *getVersion() { + const char *getVersion() override { return mVersion; } - const char *getVersionModules() { + const char *getVersionModules() override { return mVersionModules; } - uint32_t getSunrise() { + uint32_t getSunrise() override { return mSunrise; } - uint32_t getSunset() { + uint32_t getSunset() override { return mSunset; } - bool getSettingsValid() { + bool getSettingsValid() override { return mSettings.getValid(); } - bool getRebootRequestState() { + bool getRebootRequestState() override { return mShowRebootRequest; } - void setMqttDiscoveryFlag() { + void setMqttDiscoveryFlag() override { #if defined(ENABLE_MQTT) once(std::bind(&PubMqttType::sendDiscoveryConfig, &mMqtt), 1, "disCf"); #endif } - bool getMqttIsConnected() { + bool getMqttIsConnected() override { #if defined(ENABLE_MQTT) return mMqtt.isConnected(); #else @@ -231,7 +231,7 @@ class app : public IApp, public ah::Scheduler { #endif } - uint32_t getMqttTxCnt() { + uint32_t getMqttTxCnt() override { #if defined(ENABLE_MQTT) return mMqtt.getTxCnt(); #else @@ -239,7 +239,7 @@ class app : public IApp, public ah::Scheduler { #endif } - uint32_t getMqttRxCnt() { + uint32_t getMqttRxCnt() override { #if defined(ENABLE_MQTT) return mMqtt.getRxCnt(); #else @@ -267,11 +267,11 @@ class app : public IApp, public ah::Scheduler { return mProtection->isProtected(clientIp); } - bool getNrfEnabled(void) { + bool getNrfEnabled(void) override { return mConfig->nrf.enabled; } - bool getCmtEnabled(void) { + bool getCmtEnabled(void) override { return mConfig->cmt.enabled; } @@ -283,19 +283,19 @@ class app : public IApp, public ah::Scheduler { return mConfig->cmt.pinIrq; } - uint32_t getTimezoneOffset() { + uint32_t getTimezoneOffset() override { return mApi.getTimezoneOffset(); } - void getSchedulerInfo(uint8_t *max) { + void getSchedulerInfo(uint8_t *max) override { getStat(max); } - void getSchedulerNames(void) { + void getSchedulerNames(void) override { printSchedulers(); } - void setTimestamp(uint32_t newTime) { + void setTimestamp(uint32_t newTime) override { DPRINT(DBG_DEBUG, F("setTimestamp: ")); DBGPRINTLN(String(newTime)); if(0 == newTime) @@ -310,7 +310,7 @@ class app : public IApp, public ah::Scheduler { Scheduler::setTimestamp(newTime); } - uint16_t getHistoryValue(uint8_t type, uint16_t i) { + uint16_t getHistoryValue(uint8_t type, uint16_t i) override { #if defined(ENABLE_HISTORY) return mHistory.valueAt((HistoryStorageType)type, i); #else @@ -318,7 +318,7 @@ class app : public IApp, public ah::Scheduler { #endif } - uint16_t getHistoryMaxDay() { + uint16_t getHistoryMaxDay() override { #if defined(ENABLE_HISTORY) return mHistory.getMaximumDay(); #else @@ -372,11 +372,11 @@ class app : public IApp, public ah::Scheduler { void tickNtpUpdate(void); #if defined(ETHERNET) void onNtpUpdate(bool gotTime); - bool mNtpReceived; + bool mNtpReceived = false; #endif /* defined(ETHERNET) */ void updateNtp(void); - void triggerTickSend() { + void triggerTickSend() override { once(std::bind(&app::tickSend, this), 0, "tSend"); } @@ -395,7 +395,7 @@ class app : public IApp, public ah::Scheduler { HmRadio<> mNrfRadio; Communication mCommunication; - bool mShowRebootRequest; + bool mShowRebootRequest = false; #if defined(ETHERNET) ahoyeth mEth; @@ -404,7 +404,7 @@ class app : public IApp, public ah::Scheduler { #endif /* defined(ETHERNET) */ WebType mWeb; RestApiType mApi; - Protection *mProtection; + Protection *mProtection = nullptr; #ifdef ENABLE_SYSLOG DbgSyslog mDbgSyslog; #endif @@ -421,26 +421,26 @@ class app : public IApp, public ah::Scheduler { char mVersion[12]; char mVersionModules[12]; settings mSettings; - settings_t *mConfig; - bool mSavePending; - bool mSaveReboot; + settings_t *mConfig = nullptr; + bool mSavePending = false; + bool mSaveReboot = false; - uint8_t mSendLastIvId; - bool mSendFirst; - bool mAllIvNotAvail; + uint8_t mSendLastIvId = 0; + bool mSendFirst = false; + bool mAllIvNotAvail = false; - bool mNetworkConnected; + bool mNetworkConnected = false; // mqtt #if defined(ENABLE_MQTT) PubMqttType mMqtt; #endif /*ENABLE_MQTT*/ - bool mMqttReconnect; - bool mMqttEnabled; + bool mMqttReconnect = false; + bool mMqttEnabled = false; // sun - int32_t mCalculatedTimezoneOffset; - uint32_t mSunrise, mSunset; + int32_t mCalculatedTimezoneOffset = 0; + uint32_t mSunrise = 0, mSunset = 0; // plugins #if defined(PLUGIN_DISPLAY) diff --git a/src/config/settings.h b/src/config/settings.h index ec9712ea..0cb9ed4e 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -13,6 +13,7 @@ #include #include +#include #include #include "../defines.h" @@ -206,7 +207,7 @@ typedef struct { class settings { public: settings() { - mLastSaveSucceed = false; + std::fill(reinterpret_cast(&mCfg), reinterpret_cast(&mCfg) + sizeof(mCfg), 0); } void setup() { @@ -377,7 +378,7 @@ class settings { memcpy(&tmp, &mCfg.sys, sizeof(cfgSys_t)); } // erase all settings and reset to default - memset(&mCfg, 0, sizeof(settings_t)); + std::fill(reinterpret_cast(&mCfg), reinterpret_cast(&mCfg) + sizeof(mCfg), 0); mCfg.sys.protectionMask = DEF_PROT_INDEX | DEF_PROT_LIVE | DEF_PROT_SERIAL | DEF_PROT_SETUP | DEF_PROT_UPDATE | DEF_PROT_SYSTEM | DEF_PROT_API | DEF_PROT_MQTT | DEF_PROT_HISTORY; mCfg.sys.darkMode = false; @@ -847,7 +848,7 @@ class settings { #endif settings_t mCfg; - bool mLastSaveSucceed; + bool mLastSaveSucceed = 0; }; #endif /*__SETTINGS_H__*/ diff --git a/src/defines.h b/src/defines.h index b71a1d25..bc9d2452 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 73 +#define VERSION_PATCH 74 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index acbe9a35..328309ac 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -91,7 +91,7 @@ class CommQueue { inc(&mRdPtr); } - void setTs(uint32_t *ts) { + void setTs(const uint32_t *ts) { mQueue[mRdPtr].ts = *ts; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index d1521f81..326fb57e 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -6,6 +6,7 @@ #ifndef __COMMUNICATION_H__ #define __COMMUNICATION_H__ +#include #include "CommQueue.h" #include #include "../utils/crc.h" @@ -194,8 +195,8 @@ class Communication : public CommQueue<> { q->iv->radio->mBufCtrl.pop(); return; // don't wait for empty buffer } else if(IV_MI == q->iv->ivGen) { - if(parseMiFrame(p, q)) - q->iv->curFrmCnt++; + parseMiFrame(p, q); + q->iv->curFrmCnt++; } } //else -> serial does not match @@ -385,7 +386,7 @@ class Communication : public CommQueue<> { } } - inline bool validateIvSerial(uint8_t buf[], Inverter<> *iv) { + inline bool validateIvSerial(const uint8_t buf[], Inverter<> *iv) { uint8_t tmp[4]; CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); for(uint8_t i = 0; i < 4; i++) { @@ -435,7 +436,7 @@ class Communication : public CommQueue<> { return true; } - inline bool parseMiFrame(packet_t *p, const queue_s *q) { + inline void parseMiFrame(packet_t *p, const queue_s *q) { if((!mIsRetransmit && p->packet[9] == 0x00) && (p->millis < LIMIT_FAST_IV_MI)) //first frame is fast? mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV_MI); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) @@ -458,11 +459,9 @@ class Communication : public CommQueue<> { rec->ts = q->ts; miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); } - - return true; } - inline bool parseDevCtrl(packet_t *p, const queue_s *q) { + inline bool parseDevCtrl(const packet_t *p, const queue_s *q) { switch(p->packet[12]) { case ActivePowerContr: if(p->packet[13] != 0x00) @@ -524,7 +523,7 @@ class Communication : public CommQueue<> { return false; } - memset(mPayload, 0, MAX_BUFFER); + mPayload.fill(0); int8_t rssi = -127; uint8_t len = 0; @@ -547,19 +546,19 @@ class Communication : public CommQueue<> { DBGPRINT(String(len)); if(*mPrintWholeTrace) { DBGPRINT(F("): ")); - ah::dumpBuf(mPayload, len); + ah::dumpBuf(mPayload.data(), len); } else DBGPRINTLN(F(")")); if(GridOnProFilePara == q->cmd) { - q->iv->addGridProfile(mPayload, len); + q->iv->addGridProfile(mPayload.data(), len); return true; } record_t<> *rec = q->iv->getRecordStruct(q->cmd); if(NULL == rec) { if(GetLossRate == q->cmd) { - q->iv->parseGetLossRate(mPayload, len); + q->iv->parseGetLossRate(mPayload.data(), len); return true; } else DPRINTLN(DBG_ERROR, F("record is NULL!")); @@ -578,7 +577,7 @@ class Communication : public CommQueue<> { rec->ts = q->ts; for (uint8_t i = 0; i < rec->length; i++) { - q->iv->addValue(i, mPayload, rec); + q->iv->addValue(i, mPayload.data(), rec); } rec->mqttSentStatus = MqttSentStatus::NEW_DATA; @@ -588,7 +587,7 @@ class Communication : public CommQueue<> { if(AlarmData == q->cmd) { uint8_t i = 0; while(1) { - if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) + if(0 == q->iv->parseAlarmLog(i++, mPayload.data(), len)) break; if (NULL != mCbAlarm) (mCbAlarm)(q->iv); @@ -670,7 +669,7 @@ class Communication : public CommQueue<> { }; */ - if ( p->packet[9] == 0x00 ) {//first frame + if ( p->packet[9] == 0x00 ) { //first frame //FLD_FW_VERSION for (uint8_t i = 0; i < 5; i++) { q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); @@ -680,7 +679,7 @@ class Communication : public CommQueue<> { DBGPRINT(F("HW_VER is ")); DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); } - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = q->ts; q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); q->iv->miMultiParts +=4; @@ -894,7 +893,7 @@ class Communication : public CommQueue<> { statusMi = 8310; //trick? } - uint16_t prntsts = statusMi == 3 ? 1 : statusMi; + uint16_t prntsts = (statusMi == 3) ? 1 : statusMi; bool stsok = true; if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? q->iv->alarmCnt = 1; // minimum... @@ -1017,17 +1016,17 @@ class Communication : public CommQueue<> { private: States mState = States::RESET; - uint32_t *mTimestamp; - bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; + uint32_t *mTimestamp = nullptr; + bool *mPrivacyMode = nullptr, *mSerialDebug = nullptr, *mPrintWholeTrace = nullptr; TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) std::array mLocalBuf; bool mFirstTry = false; // see, if we should do a second try bool mCompleteRetry = false; // remember if we did request a complete retransmission bool mIsRetransmit = false; // we already had waited one complete cycle - uint8_t mMaxFrameId; + uint8_t mMaxFrameId = 0; uint8_t mFramesExpected = 12; // 0x8c was highest last frame for alarm data uint16_t mTimeout = 0; // calculating that once should be ok - uint8_t mPayload[MAX_BUFFER]; + std::array mPayload; payloadListenerType mCbPayload = NULL; powerLimitAckListenerType mCbPwrAck = NULL; alarmListenerType mCbAlarm = NULL; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index fa4512b5..2a36bc78 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -157,7 +157,7 @@ class Heuristic { DBGPRINTLN(String(iv->config->powerLevel)); } - uint8_t getIvRetries(Inverter<> *iv) { + uint8_t getIvRetries(const Inverter<> *iv) const { if(iv->heuristics.rxSpeeds[0]) return RETRIES_VERYFAST_IV; if(iv->heuristics.rxSpeeds[1]) @@ -200,7 +200,7 @@ class Heuristic { } private: - bool isNewTxCh(HeuristicInv *ih) { + bool isNewTxCh(const HeuristicInv *ih) const { return ih->txRfChId != ih->lastBestTxChId; } @@ -222,9 +222,6 @@ class Heuristic { } return 3; // standard } - - private: - uint8_t mChList[5] = {03, 23, 40, 61, 75}; }; diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 0b42aeae..8fc4f71f 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -76,7 +76,7 @@ enum {CMD_CALC = 0xffff}; enum {CH0 = 0, CH1, CH2, CH3, CH4, CH5, CH6}; enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; -enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; +enum {INV_RADIO_TYPE_UNKNOWN = 0, INV_RADIO_TYPE_NRF, INV_RADIO_TYPE_CMT}; #define DURATION_ONEFRAME 50 // timeout parameter for each expected frame (ms) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b62e985a..275fce2c 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -81,12 +81,12 @@ enum class InverterStatus : uint8_t { template struct record_t { - byteAssign_t* assign; // assignment of bytes in payload - uint8_t length; // length of the assignment list - T *record; // data pointer - uint32_t ts; // timestamp of last received payload - uint8_t pyldLen; // expected payload length for plausibility check - MqttSentStatus mqttSentStatus; // indicates the current MqTT sent status + byteAssign_t* assign = nullptr; // assignment of bytes in payload + uint8_t length = 0; // length of the assignment list + T *record = nullptr; // data pointer + uint32_t ts = 0; // timestamp of last received payload + uint8_t pyldLen = 0; // expected payload length for plausibility check + MqttSentStatus mqttSentStatus = MqttSentStatus:: NEW_DATA; // indicates the current MqTT sent status }; struct alarm_t { @@ -113,42 +113,42 @@ const calcFunc_t calcFunctions[] = { template class Inverter { public: - uint8_t ivGen; // generation of inverter (HM / MI) - uint8_t ivRadioType; // refers to used radio (nRF24 / CMT) - cfgIv_t *config; // stored settings - uint8_t id; // unique id - uint8_t type; // integer which refers to inverter type - uint16_t alarmMesIndex; // Last recorded Alarm Message Index - uint16_t powerLimit[2]; // limit power output (multiplied by 10) - float actPowerLimit; // actual power limit - bool powerLimitAck; // acknowledged power limit (default: false) - uint8_t devControlCmd; // carries the requested cmd - serial_u radioId; // id converted to modbus - uint8_t channels; // number of PV channels (1-4) - record_t recordMeas; // structure for measured values - record_t recordInfo; // structure for info values - record_t recordHwInfo; // structure for simple (hardware) info values - record_t recordConfig; // structure for system config values - record_t recordAlarm; // structure for alarm values - InverterStatus status; // indicates the current inverter status - std::array lastAlarm; // holds last 10 alarms - uint8_t rxOffset; // holds the default channel offset between tx and rx channel (nRF only) - int8_t rssi; // RSSI - uint16_t alarmCnt; // counts the total number of occurred alarms - uint16_t alarmLastId; // lastId which was received - uint8_t mCmd; // holds the command to send - bool mGotFragment; // shows if inverter has sent at least one fragment - uint8_t miMultiParts; // helper info for MI multiframe msgs - uint8_t outstandingFrames; // helper info to count difference between expected and received frames - uint8_t curFrmCnt; // count received frames in current loop - bool mGotLastMsg; // shows if inverter has already finished transmission cycle - bool mIsSingleframeReq; // indicates this is a missing single frame request - Radio *radio; // pointer to associated radio class - statistics_t radioStatistics; // information about transmitted, failed, ... packets - HeuristicInv heuristics; // heuristic information / logic - uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime - bool commEnabled; // 'pause night communication' sets this field to false - uint32_t tsMaxAcPower; // holds the timestamp when the MaxAC power was seen + uint8_t ivGen = IV_UNKNOWN; // generation of inverter (HM / MI) + uint8_t ivRadioType = INV_RADIO_TYPE_UNKNOWN; // refers to used radio (nRF24 / CMT) + cfgIv_t *config = nullptr; // stored settings + uint8_t id = 0; // unique id + uint8_t type = INV_TYPE_1CH; // integer which refers to inverter type + uint16_t alarmMesIndex = 0; // Last recorded Alarm Message Index + uint16_t powerLimit[2] = {0xffff, AbsolutNonPersistent}; // limit power output (multiplied by 10) + float actPowerLimit = -1; // actual power limit + bool powerLimitAck = false; // acknowledged power limit + uint8_t devControlCmd = InitDataState; // carries the requested cmd + serial_u radioId; // id converted to modbus + uint8_t channels = 1; // number of PV channels (1-4) + record_t recordMeas; // structure for measured values + record_t recordInfo; // structure for info values + record_t recordHwInfo; // structure for simple (hardware) info values + record_t recordConfig; // structure for system config values + record_t recordAlarm; // structure for alarm values + InverterStatus status = InverterStatus::OFF; // indicates the current inverter status + std::array lastAlarm; // holds last 10 alarms + uint8_t rxOffset = 0; // holds the default channel offset between tx and rx channel (nRF only) + int8_t rssi = 0; // RSSI + uint16_t alarmCnt = 0; // counts the total number of occurred alarms + uint16_t alarmLastId = 0; // lastId which was received + uint8_t mCmd = InitDataState; // holds the command to send + bool mGotFragment = false; // shows if inverter has sent at least one fragment + uint8_t miMultiParts = 0; // helper info for MI multiframe msgs + uint8_t outstandingFrames = 0; // helper info to count difference between expected and received frames + uint8_t curFrmCnt = 0; // count received frames in current loop + bool mGotLastMsg = false; // shows if inverter has already finished transmission cycle + bool mIsSingleframeReq = false; // indicates this is a missing single frame request + Radio *radio = nullptr; // pointer to associated radio class + statistics_t radioStatistics; // information about transmitted, failed, ... packets + HeuristicInv heuristics; // heuristic information / logic + uint8_t curCmtFreq = 0; // current used CMT frequency, used to check if freq. was changed during runtime + uint32_t tsMaxAcPower = 0; // holds the timestamp when the MaxAC power was seen + bool commEnabled = true; // 'pause night communication' sets this field to false static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -156,29 +156,10 @@ class Inverter { public: Inverter() { - ivGen = IV_HM; - powerLimit[0] = 0xffff; // 6553.5 W Limit -> unlimited - powerLimit[1] = AbsolutNonPersistent; // default power limit setting - powerLimitAck = false; - actPowerLimit = 0xffff; // init feedback from inverter to -1 - mDevControlRequest = false; - devControlCmd = InitDataState; - alarmMesIndex = 0; - status = InverterStatus::OFF; - alarmCnt = 0; - alarmLastId = 0; - rssi = -127; - miMultiParts = 0; - mGotLastMsg = false; - mCmd = InitDataState; - mIsSingleframeReq = false; - radio = NULL; - commEnabled = true; - tsMaxAcPower = 0; - memset(&radioStatistics, 0, sizeof(statistics_t)); memset(mOffYD, 0, sizeof(float) * 6); memset(mLastYD, 0, sizeof(float) * 6); + mGridProfile.fill(0); } void tickSend(std::function cb) { @@ -255,8 +236,8 @@ class Inverter { uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId, record_t<> *rec) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getPosByChFld")); - uint8_t pos = 0; if(NULL != rec) { + uint8_t pos = 0; for(; pos < rec->length; pos++) { if((rec->assign[pos].ch == channel) && (rec->assign[pos].fieldId == fieldId)) break; @@ -303,7 +284,7 @@ class Inverter { return (InverterStatus::OFF != status); } - void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { + void addValue(uint8_t pos, const uint8_t buf[], record_t<> *rec) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:addValue")); if(NULL != rec) { uint8_t ptr = rec->assign[pos].start; @@ -387,8 +368,8 @@ class Inverter { } REC_TYP getChannelFieldValue(uint8_t channel, uint8_t fieldId, record_t<> *rec) { - uint8_t pos = 0; if(NULL != rec) { + uint8_t pos = 0; for(; pos < rec->length; pos++) { if((rec->assign[pos].ch == channel) && (rec->assign[pos].fieldId == fieldId)) break; @@ -529,11 +510,11 @@ class Inverter { if (INV_TYPE_1CH == type) { if((IV_HM == ivGen) || (IV_MI == ivGen)) { rec->length = (uint8_t)(HM1CH_LIST_LEN); - rec->assign = (byteAssign_t *)hm1chAssignment; + rec->assign = reinterpret_cast(const_cast(hm1chAssignment)); rec->pyldLen = HM1CH_PAYLOAD_LEN; } else if(IV_HMS == ivGen) { rec->length = (uint8_t)(HMS1CH_LIST_LEN); - rec->assign = (byteAssign_t *)hms1chAssignment; + rec->assign = reinterpret_cast(const_cast(hms1chAssignment)); rec->pyldLen = HMS1CH_PAYLOAD_LEN; } channels = 1; @@ -541,11 +522,11 @@ class Inverter { else if (INV_TYPE_2CH == type) { if((IV_HM == ivGen) || (IV_MI == ivGen)) { rec->length = (uint8_t)(HM2CH_LIST_LEN); - rec->assign = (byteAssign_t *)hm2chAssignment; + rec->assign = reinterpret_cast(const_cast(hm2chAssignment)); rec->pyldLen = HM2CH_PAYLOAD_LEN; } else if(IV_HMS == ivGen) { rec->length = (uint8_t)(HMS2CH_LIST_LEN); - rec->assign = (byteAssign_t *)hms2chAssignment; + rec->assign = reinterpret_cast(const_cast(hms2chAssignment)); rec->pyldLen = HMS2CH_PAYLOAD_LEN; } channels = 2; @@ -553,18 +534,18 @@ class Inverter { else if (INV_TYPE_4CH == type) { if((IV_HM == ivGen) || (IV_MI == ivGen)) { rec->length = (uint8_t)(HM4CH_LIST_LEN); - rec->assign = (byteAssign_t *)hm4chAssignment; + rec->assign = reinterpret_cast(const_cast(hm4chAssignment)); rec->pyldLen = HM4CH_PAYLOAD_LEN; } else if(IV_HMS == ivGen) { rec->length = (uint8_t)(HMS4CH_LIST_LEN); - rec->assign = (byteAssign_t *)hms4chAssignment; + rec->assign = reinterpret_cast(const_cast(hms4chAssignment)); rec->pyldLen = HMS4CH_PAYLOAD_LEN; } channels = 4; } else if (INV_TYPE_6CH == type) { rec->length = (uint8_t)(HMT6CH_LIST_LEN); - rec->assign = (byteAssign_t *)hmt6chAssignment; + rec->assign = reinterpret_cast(const_cast(hmt6chAssignment)); rec->pyldLen = HMT6CH_PAYLOAD_LEN; channels = 6; } @@ -577,22 +558,22 @@ class Inverter { break; case InverterDevInform_All: rec->length = (uint8_t)(HMINFO_LIST_LEN); - rec->assign = (byteAssign_t *)InfoAssignment; + rec->assign = reinterpret_cast(const_cast(InfoAssignment)); rec->pyldLen = HMINFO_PAYLOAD_LEN; break; case InverterDevInform_Simple: rec->length = (uint8_t)(HMSIMPLE_INFO_LIST_LEN); - rec->assign = (byteAssign_t *)SimpleInfoAssignment; + rec->assign = reinterpret_cast(const_cast(SimpleInfoAssignment)); rec->pyldLen = HMSIMPLE_INFO_PAYLOAD_LEN; break; case SystemConfigPara: rec->length = (uint8_t)(HMSYSTEM_LIST_LEN); - rec->assign = (byteAssign_t *)SystemConfigParaAssignment; + rec->assign = reinterpret_cast(const_cast(SystemConfigParaAssignment)); rec->pyldLen = HMSYSTEM_PAYLOAD_LEN; break; case AlarmData: rec->length = (uint8_t)(HMALARMDATA_LIST_LEN); - rec->assign = (byteAssign_t *)AlarmDataAssignment; + rec->assign = reinterpret_cast(const_cast(AlarmDataAssignment)); rec->pyldLen = HMALARMDATA_PAYLOAD_LEN; break; default: @@ -616,7 +597,7 @@ class Inverter { memset(mLastYD, 0, sizeof(float) * 6); } - bool parseGetLossRate(uint8_t pyld[], uint8_t len) { + bool parseGetLossRate(const uint8_t pyld[], uint8_t len) { if (len == HMGETLOSSRATE_PAYLOAD_LEN) { uint16_t rxCnt = (pyld[0] << 8) + pyld[1]; uint16_t txCnt = (pyld[2] << 8) + pyld[3]; @@ -815,7 +796,7 @@ class Inverter { void addGridProfile(uint8_t buf[], uint8_t length) { mGridLen = (length > MAX_GRID_LENGTH) ? MAX_GRID_LENGTH : length; - std::copy(buf, &buf[mGridLen], mGridProfile); + std::copy(buf, &buf[mGridLen], mGridProfile.data()); } String getGridProfile(void) { @@ -847,9 +828,9 @@ class Inverter { private: float mOffYD[6], mLastYD[6]; - bool mDevControlRequest; // true if change needed + bool mDevControlRequest = false; // true if change needed uint8_t mGridLen = 0; - uint8_t mGridProfile[MAX_GRID_LENGTH]; + std::array mGridProfile; uint8_t mAlarmNxtWrPos = 0; // indicates the position in array (rolling buffer) public: diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ca96a333..aef4f49d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -52,7 +52,7 @@ class HmRadio : public Radio { mPrintWholeTrace = printWholeTrace; generateDtuSn(); - DTU_RADIO_ID = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; + mDtuRadioId = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; #ifdef ESP32 #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) @@ -85,7 +85,7 @@ class HmRadio : public Radio { mNrf24->enableDynamicPayloads(); mNrf24->setCRCLength(RF24_CRC_16); mNrf24->setAddressWidth(5); - mNrf24->openReadingPipe(1, reinterpret_cast(&DTU_RADIO_ID)); + mNrf24->openReadingPipe(1, reinterpret_cast(&mDtuRadioId)); mNrf24->maskIRQ(false, false, false); // enable all receiving interrupts mNrf24->setPALevel(1); // low is default @@ -99,7 +99,7 @@ class HmRadio : public Radio { } // returns true if communication is active - bool loop(void) { + bool loop(void) override { if (!mIrqRcvd && !mNRFisInRX) return false; // first quick check => nothing to do at all here @@ -198,11 +198,11 @@ class HmRadio : public Radio { return false; } - bool isChipConnected(void) const { + bool isChipConnected(void) const override { return mNrf24->isChipConnected(); } - void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { + void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) override { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("sendControlPacket cmd: ")); DBGHEXLN(cmd); @@ -423,15 +423,15 @@ class HmRadio : public Radio { mNRFisInRX = false; } - uint64_t getIvId(Inverter<> *iv) const { + uint64_t getIvId(Inverter<> *iv) const override { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) const { + uint8_t getIvGen(Inverter<> *iv) const override { return iv->ivGen; } - inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { + inline bool checkIvSerial(const uint8_t buf[], Inverter<> *iv) { for(uint8_t i = 1; i < 5; i++) { if(buf[i] != iv->radioId.b[i]) return false; @@ -439,14 +439,14 @@ class HmRadio : public Radio { return true; } - uint64_t DTU_RADIO_ID; - uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz + uint64_t mDtuRadioId = 0ULL; + const uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz uint8_t mTxChIdx = 0; uint8_t mRxChIdx = 0; - uint8_t tempRxChIdx = mRxChIdx; + uint8_t tempRxChIdx = 0; bool mGotLastMsg = false; - uint32_t mMillis; - bool tx_ok, tx_fail, rx_ready = false; + uint32_t mMillis = 0; + bool tx_ok = false, tx_fail = false, rx_ready = false; unsigned long mTimeslotStart = 0; unsigned long mLastIrqTime = 0; bool mNRFloopChannels = false; @@ -454,7 +454,6 @@ class HmRadio : public Radio { bool isRxInit = true; bool mRxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; - //uint8_t mTxSetupTime = 0; uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); std::unique_ptr mSpi; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index aa2910e5..0266a948 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -98,35 +98,33 @@ class HmSystem { #ifdef DYNAMIC_OFFSET iv->rxOffset = (iv->ivGen == IV_HM) ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting #else - iv->rxOffset = ((iv->ivGen == IV_HM) && (iv->type == INV_TYPE_4CH)) ? 3 : 2; + //iv->rxOffset = ((iv->ivGen == IV_HM) && (iv->type == INV_TYPE_4CH)) ? 3 : 2; iv->rxOffset = (iv->ivGen == IV_HM) ? 3 : 2; #endif cb(iv); } - INVERTERTYPE *findInverter(uint8_t buf[]) { - DPRINTLN(DBG_VERBOSE, F("hmSystem.h:findInverter")); - INVERTERTYPE *p; + INVERTERTYPE *findInverter(const uint8_t buf[]) { for(uint8_t i = 0; i < MAX_INVERTER; i++) { - p = &mInverter[i]; + INVERTERTYPE *p = &mInverter[i]; if((p->config->serial.b[3] == buf[0]) && (p->config->serial.b[2] == buf[1]) && (p->config->serial.b[1] == buf[2]) && (p->config->serial.b[0] == buf[3])) return p; } - return NULL; + return nullptr; } INVERTERTYPE *getInverterByPos(uint8_t pos, bool check = true) { DPRINTLN(DBG_VERBOSE, F("hmSystem.h:getInverterByPos")); if(pos >= MAX_INVERTER) - return NULL; + return nullptr; else if((mInverter[pos].config->serial.u64 != 0ULL) || (false == check)) return &mInverter[pos]; else - return NULL; + return nullptr; } uint8_t getNumInverters(void) { diff --git a/src/hm/nrfHal.h b/src/hm/nrfHal.h index 0532a524..b9265626 100644 --- a/src/hm/nrfHal.h +++ b/src/hm/nrfHal.h @@ -142,7 +142,7 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle { } uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t len) override { - uint8_t data[NRF_MAX_TRANSFER_SZ]; + uint8_t data[NRF_MAX_TRANSFER_SZ + 1]; data[0] = cmd; if(len > NRF_MAX_TRANSFER_SZ) len = NRF_MAX_TRANSFER_SZ; diff --git a/src/hm/radio.h b/src/hm/radio.h index 7bbb42bc..db694b54 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -11,6 +11,7 @@ #define ALL_FRAMES 0x80 #define SINGLE_FRAME 0x81 +#include #include "../utils/dbg.h" #include "../utils/crc.h" #include "../utils/timemonitor.h" @@ -119,9 +120,8 @@ class Radio { #endif mDtuSn = 0; - uint8_t t; for(int i = 0; i < (7 << 2); i += 4) { - t = (chipID >> i) & 0x0f; + uint8_t t = (chipID >> i) & 0x0f; if(t > 0x09) t -= 6; mDtuSn |= (t << i); @@ -132,8 +132,8 @@ class Radio { uint32_t mDtuSn; - volatile bool mIrqRcvd; - bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace; + std::atomic mIrqRcvd; + bool *mSerialDebug = nullptr, *mPrivacyMode = nullptr, *mPrintWholeTrace = nullptr; uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; }; diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index e6456f5b..23911b15 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -529,7 +529,8 @@ class Cmt2300a { return false; } - inline bool switchDtuFreq(const uint32_t freqKhz) { + // maybe used in future + /*inline bool switchDtuFreq(const uint32_t freqKhz) { uint8_t toCh = freq2Chan(freqKhz); if(0xff == toCh) return false; @@ -537,7 +538,7 @@ class Cmt2300a { switchChannel(toCh); return true; - } + }*/ inline uint8_t getChipStatus(void) { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; @@ -549,11 +550,11 @@ class Cmt2300a { #else esp32_3wSpi mSpi; #endif - uint8_t mCnt; - bool mTxPending; - bool mInRxMode; - uint8_t mCusIntFlag; - uint8_t mRqstCh, mCurCh; + uint8_t mCnt = 0; + bool mTxPending = false; + bool mInRxMode = false; + uint8_t mCusIntFlag = 0; + uint8_t mRqstCh = 0, mCurCh = 0; RegionCfg mRegionCfg = RegionCfg::EUROPE; }; diff --git a/src/hms/cmtHal.h b/src/hms/cmtHal.h index 768b8da5..a4bec587 100644 --- a/src/hms/cmtHal.h +++ b/src/hms/cmtHal.h @@ -89,7 +89,7 @@ class cmtHal : public SpiPatcherHandle { } uint8_t readReg(uint8_t addr) { - uint8_t data; + uint8_t data = 0; request_spi(); diff --git a/src/hms/esp32_3wSpi.h b/src/hms/esp32_3wSpi.h index c562671a..a0366b23 100644 --- a/src/hms/esp32_3wSpi.h +++ b/src/hms/esp32_3wSpi.h @@ -10,6 +10,7 @@ #if defined(ESP32) #include "driver/spi_master.h" #include "esp_rom_gpio.h" // for esp_rom_gpio_connect_out_signal +#include "../config/config.h" #define SPI_CLK 1 * 1000 * 1000 // 1MHz @@ -104,7 +105,7 @@ class esp32_3wSpi { if(!mInitialized) return 0; - uint8_t rx_data; + uint8_t rx_data = 0; spi_transaction_t t = { .cmd = 0, .addr = (uint64_t)(~addr), @@ -121,7 +122,7 @@ class esp32_3wSpi { return rx_data; } - void writeFifo(uint8_t buf[], uint8_t len) { + void writeFifo(const uint8_t buf[], uint8_t len) { if(!mInitialized) return; uint8_t tx_data; @@ -144,7 +145,7 @@ class esp32_3wSpi { void readFifo(uint8_t buf[], uint8_t *len, uint8_t maxlen) { if(!mInitialized) return; - uint8_t rx_data; + uint8_t rx_data = 0; spi_transaction_t t = { .length = 8, diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 0fa1b6ab..66e312d7 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -15,10 +15,6 @@ template class CmtRadio : public Radio { typedef Cmt2300a CmtType; public: - CmtRadio() { - mDtuSn = DTU_SN; - } - void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, uint8_t region = 0, bool genDtuSn = true) { mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb); reset(genDtuSn, static_cast(region)); @@ -27,7 +23,7 @@ class CmtRadio : public Radio { mPrintWholeTrace = printWholeTrace; } - bool loop() { + bool loop() override { mCmt.loop(); if((!mIrqRcvd) && (!mRqstGetRx)) return false; @@ -39,11 +35,11 @@ class CmtRadio : public Radio { return false; } - bool isChipConnected(void) const { + bool isChipConnected(void) const override { return mCmtAvail; } - void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { + void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) override { DPRINT(DBG_INFO, F("sendControlPacket cmd: ")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); @@ -61,14 +57,14 @@ class CmtRadio : public Radio { sendPacket(iv, cnt, isRetransmit); } - bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { + bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) override { uint8_t fromCh = mCmt.freq2Chan(fromkHz); uint8_t toCh = mCmt.freq2Chan(tokHz); return switchFrequencyCh(iv, fromCh, toCh); } - bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { + bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) override { if((0xff == fromCh) || (0xff == toCh)) return false; @@ -92,7 +88,7 @@ class CmtRadio : public Radio { private: - void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { + void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) override { // inverters have maybe different settings regarding frequency if(mCmt.getCurrentChannel() != iv->config->frequency) mCmt.switchChannel(iv->config->frequency); @@ -129,11 +125,11 @@ class CmtRadio : public Radio { iv->mDtuTxCnt++; } - uint64_t getIvId(Inverter<> *iv) const { + uint64_t getIvId(Inverter<> *iv) const override { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) const { + uint8_t getIvGen(Inverter<> *iv) const override { return iv->ivGen; } @@ -180,6 +176,7 @@ class CmtRadio : public Radio { p.millis = millis() - mMillis; if(CmtStatus::SUCCESS == mCmt.getRx(p.packet, &p.len, 28, &p.rssi)) { mSwitchCycle = 0; + p.ch = 0; // not used for CMT inverters mBufCtrl.push(p); } @@ -187,14 +184,12 @@ class CmtRadio : public Radio { setExpectedFrames(p.packet[9] - ALL_FRAMES); mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? } - // optionally instead: - // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... } CmtType mCmt; bool mCmtAvail = false; bool mRqstGetRx = false; - uint32_t mMillis; + uint32_t mMillis = 0; uint8_t mSwitchCycle = 0; }; diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 862e452b..c59a56b6 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -192,15 +192,14 @@ class Display { if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF)) { #if defined(ESP8266) if (mCfg->pirPin == A0) - return((analogRead(A0) >= 512)); + return (analogRead(A0) >= 512); else - return(digitalRead(mCfg->pirPin)); + return digitalRead(mCfg->pirPin); #elif defined(ESP32) - return(digitalRead(mCfg->pirPin)); + return digitalRead(mCfg->pirPin); #endif - } - else - return(false); + } else + return false; } // approximate RSSI in dB by invQuality levels from heuristic function (very unscientific but better than nothing :-) ) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 2c1fc935..e855eeb9 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -24,8 +24,6 @@ class DisplayMono { public: - DisplayMono() {}; - virtual void init(DisplayData *displayData) = 0; virtual void config(display_t *cfg) = 0; virtual void disp(void) = 0; @@ -289,11 +287,11 @@ class DisplayMono { DispSwitchState mDispSwitchState = DispSwitchState::TEXT; uint16_t mDispWidth; - uint8_t mExtra; + uint8_t mExtra = 0; int8_t mPixelshift=0; char mFmtText[DISP_FMT_TEXT_LEN]; - uint8_t mLineXOffsets[5] = {}; - uint8_t mLineYOffsets[5] = {}; + uint8_t mLineXOffsets[5] = {0, 0, 0, 0, 0}; + uint8_t mLineYOffsets[5] = {0, 0, 0, 0, 0}; uint8_t mPgWidth = 0; @@ -308,8 +306,8 @@ class DisplayMono { uint32_t mPgLastTime = 0; PowerGraphState mPgState = PowerGraphState::NO_TIME_SYNC; - uint16_t mDispHeight; - uint8_t mLuminance; + uint16_t mDispHeight = 0; + uint8_t mLuminance = 0; TimeMonitor mDisplayTime = TimeMonitor(1000 * DISP_DEFAULT_TIMEOUT, true); TimeMonitor mDispSwitchTime = TimeMonitor(); diff --git a/src/plugins/history.h b/src/plugins/history.h index 7a938284..7e415675 100644 --- a/src/plugins/history.h +++ b/src/plugins/history.h @@ -24,23 +24,15 @@ template class HistoryData { private: struct storage_t { - uint16_t refreshCycle; - uint16_t loopCnt; - uint16_t listIdx; // index for next Element to write into WattArr - uint16_t dispIdx; // index for 1st Element to display from WattArr - bool wrapped; + uint16_t refreshCycle = 0; + uint16_t loopCnt = 0; + uint16_t listIdx = 0; // index for next Element to write into WattArr + uint16_t dispIdx = 0; // index for 1st Element to display from WattArr + bool wrapped = false; // ring buffer for watt history std::array data; - void reset() { - loopCnt = 0; - listIdx = 0; - dispIdx = 0; - wrapped = false; - for(uint16_t i = 0; i < (HISTORY_DATA_ARR_LENGTH + 1); i++) { - data[i] = 0; - } - } + storage_t() { data.fill(0); } }; public: @@ -50,9 +42,7 @@ class HistoryData { mConfig = config; mTs = ts; - mCurPwr.reset(); mCurPwr.refreshCycle = mConfig->inst.sendInterval; - //mYieldDay.reset(); //mYieldDay.refreshCycle = 60; } @@ -113,14 +103,13 @@ class HistoryData { } private: - IApp *mApp; - HMSYSTEM *mSys; - settings *mSettings; - settings_t *mConfig; - uint32_t *mTs; + IApp *mApp = nullptr; + HMSYSTEM *mSys = nullptr; + settings *mSettings = nullptr; + settings_t *mConfig = nullptr; + uint32_t *mTs = nullptr; storage_t mCurPwr; - //storage_t mYieldDay; bool mDayStored = false; uint16_t mMaximumDay = 0; }; diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 865c76b5..7799b6d2 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -15,6 +15,7 @@ #include #endif +#include #include "../utils/dbg.h" #include "../config/config.h" #include @@ -38,12 +39,15 @@ template class PubMqtt { public: PubMqtt() { - mRxCnt = 0; - mTxCnt = 0; - mSubscriptionCb = NULL; - memset(mLastIvState, (uint8_t)InverterStatus::OFF, MAX_NUM_INVERTERS); - memset(mIvLastRTRpub, 0, MAX_NUM_INVERTERS * 4); - mLastAnyAvail = false; + mLastIvState.fill(InverterStatus::OFF); + mIvLastRTRpub.fill(0); + + mVal.fill(0); + mTopic.fill(0); + mSubTopic.fill(0); + mClientId.fill(0); + mLwtTopic.fill(0); + mSendAlarm.fill(false); } ~PubMqtt() { } @@ -63,16 +67,16 @@ class PubMqtt { }); mDiscovery.running = false; - snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic); + snprintf(mLwtTopic.data(), mLwtTopic.size(), "%s/mqtt", mCfgMqtt->topic); if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0)) mClient.setCredentials(mCfgMqtt->user, mCfgMqtt->pwd); if(strlen(mCfgMqtt->clientId) > 0) - snprintf(mClientId, 23, "%s", mCfgMqtt->clientId); + snprintf(mClientId.data(), mClientId.size(), "%s", mCfgMqtt->clientId); else { - snprintf(mClientId, 23, "%s-", mDevName); - uint8_t pos = strlen(mClientId); + snprintf(mClientId.data(), mClientId.size(), "%s-", mDevName); + uint8_t pos = strlen(mClientId.data()); mClientId[pos++] = WiFi.macAddress().substring( 9, 10).c_str()[0]; mClientId[pos++] = WiFi.macAddress().substring(10, 11).c_str()[0]; mClientId[pos++] = WiFi.macAddress().substring(12, 13).c_str()[0]; @@ -82,9 +86,9 @@ class PubMqtt { mClientId[pos++] = '\0'; } - mClient.setClientId(mClientId); + mClient.setClientId(mClientId.data()); mClient.setServer(mCfgMqtt->broker, mCfgMqtt->port); - mClient.setWill(mLwtTopic, QOS_0, true, mqttStr[MQTT_STR_LWT_NOT_CONN]); + mClient.setWill(mLwtTopic.data(), QOS_0, true, mqttStr[MQTT_STR_LWT_NOT_CONN]); mClient.onConnect(std::bind(&PubMqtt::onConnect, this, std::placeholders::_1)); mClient.onDisconnect(std::bind(&PubMqtt::onDisconnect, this, std::placeholders::_1)); mClient.onMessage(std::bind(&PubMqtt::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)); @@ -125,8 +129,8 @@ class PubMqtt { } void tickerMinute() { - snprintf(mVal, 40, "%d", (*mUptime)); - publish(subtopics[MQTT_UPTIME], mVal); + snprintf(mVal.data(), mVal.size(), "%u", (*mUptime)); + publish(subtopics[MQTT_UPTIME], mVal.data()); publish(subtopics[MQTT_RSSI], String(WiFi.RSSI()).c_str()); publish(subtopics[MQTT_FREE_HEAP], String(ESP.getFreeHeap()).c_str()); #ifndef ESP32 @@ -143,18 +147,17 @@ class PubMqtt { publish(subtopics[MQTT_COMM_START], String(sunrise + offsM).c_str(), true); publish(subtopics[MQTT_COMM_STOP], String(sunset + offsE).c_str(), true); - Inverter<> *iv; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - iv = mSys->getInverterByPos(i); + Inverter<> *iv = mSys->getInverterByPos(i); if(NULL == iv) continue; - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/dis_night_comm", iv->config->name); - publish(mSubTopic, ((iv->commEnabled) ? dict[STR_TRUE] : dict[STR_FALSE]), true); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/dis_night_comm", iv->config->name); + publish(mSubTopic.data(), ((iv->commEnabled) ? dict[STR_TRUE] : dict[STR_FALSE]), true); } - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "comm_disabled"); - publish(mSubTopic, (((*mUtcTimestamp > (sunset + offsE)) || (*mUtcTimestamp < (sunrise + offsM))) ? dict[STR_TRUE] : dict[STR_FALSE]), true); + snprintf(mSubTopic.data(), mSubTopic.size(), "comm_disabled"); + publish(mSubTopic.data(), (((*mUtcTimestamp > (sunset + offsE)) || (*mUtcTimestamp < (sunrise + offsM))) ? dict[STR_TRUE] : dict[STR_FALSE]), true); return true; } @@ -176,9 +179,9 @@ class PubMqtt { void tickerMidnight() { // set Total YieldDay to zero - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "total/%s", fields[FLD_YD]); - snprintf(mVal, 2, "0"); - publish(mSubTopic, mVal, true); + snprintf(mSubTopic.data(), mSubTopic.size(), "total/%s", fields[FLD_YD]); + snprintf(mVal.data(), mVal.size(), "0"); + publish(mSubTopic.data(), mVal.data(), true); } void payloadEventListener(uint8_t cmd, Inverter<> *iv) { @@ -197,11 +200,11 @@ class PubMqtt { return; if(addTopic) - snprintf(mTopic, MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1, "%s/%s", mCfgMqtt->topic, subTopic); + snprintf(mTopic.data(), mTopic.size(), "%s/%s", mCfgMqtt->topic, subTopic); else - snprintf(mTopic, MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1, "%s", subTopic); + snprintf(mTopic.data(), mTopic.size(), "%s", subTopic); - mClient.publish(mTopic, qos, retained, payload); + mClient.publish(mTopic.data(), qos, retained, payload); yield(); mTxCnt++; } @@ -238,8 +241,8 @@ class PubMqtt { void setPowerLimitAck(Inverter<> *iv) { if (NULL != iv) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); - publish(mSubTopic, "true", true, true, QOS_2); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); + publish(mSubTopic.data(), "true", true, true, QOS_2); } } @@ -255,15 +258,15 @@ class PubMqtt { publish(subtopics[MQTT_IP_ADDR], WiFi.localIP().toString().c_str(), true); #endif tickerMinute(); - publish(mLwtTopic, mqttStr[MQTT_STR_LWT_CONN], true, false); + publish(mLwtTopic.data(), mqttStr[MQTT_STR_LWT_CONN], true, false); for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - snprintf(mVal, 20, "ctrl/limit/%d", i); - subscribe(mVal, QOS_2); - snprintf(mVal, 20, "ctrl/restart/%d", i); - subscribe(mVal); - snprintf(mVal, 20, "ctrl/power/%d", i); - subscribe(mVal); + snprintf(mVal.data(), mVal.size(), "ctrl/limit/%d", i); + subscribe(mVal.data(), QOS_2); + snprintf(mVal.data(), mVal.size(), "ctrl/restart/%d", i); + subscribe(mVal.data()); + snprintf(mVal.data(), mVal.size(), "ctrl/power/%d", i); + subscribe(mVal.data()); } subscribe(subscr[MQTT_SUBS_SET_TIME]); } @@ -359,11 +362,9 @@ class PubMqtt { } void discoveryConfigLoop(void) { - char topic[64], name[32], uniq_id[32], buf[350]; DynamicJsonDocument doc(256); - uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC}; - const char* unitTotal[4] = {"W", "kWh", "Wh", "W"}; + constexpr static uint8_t fldTotal[] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC}; String node_id = String(mDevName) + "_TOTAL"; bool total = (mDiscovery.lastIvId == MAX_NUM_INVERTERS); @@ -392,32 +393,37 @@ class PubMqtt { doc[F("mf")] = F("Hoymiles"); JsonObject deviceObj = doc.as(); // deviceObj is only pointer!? + std::array topic; + std::array name; + std::array uniq_id; + std::array buf; const char *devCls, *stateCls; if (!total) { if (rec->assign[mDiscovery.sub].ch == CH0) - snprintf(name, 32, "%s", iv->getFieldName(mDiscovery.sub, rec)); + snprintf(name.data(), name.size(), "%s", iv->getFieldName(mDiscovery.sub, rec)); else - snprintf(name, 32, "CH%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); - snprintf(topic, 64, "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); - snprintf(uniq_id, 32, "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(name.data(), name.size(), "CH%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(topic.data(), name.size(), "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(uniq_id.data(), uniq_id.size(), "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); devCls = getFieldDeviceClass(rec->assign[mDiscovery.sub].fieldId); stateCls = getFieldStateClass(rec->assign[mDiscovery.sub].fieldId); } else { // total values - snprintf(name, 32, "Total %s", fields[fldTotal[mDiscovery.sub]]); - snprintf(topic, 64, "/%s", fields[fldTotal[mDiscovery.sub]]); - snprintf(uniq_id, 32, "total_%s", fields[fldTotal[mDiscovery.sub]]); + snprintf(name.data(), name.size(), "Total %s", fields[fldTotal[mDiscovery.sub]]); + snprintf(topic.data(), topic.size(), "/%s", fields[fldTotal[mDiscovery.sub]]); + snprintf(uniq_id.data(), uniq_id.size(), "total_%s", fields[fldTotal[mDiscovery.sub]]); devCls = getFieldDeviceClass(fldTotal[mDiscovery.sub]); stateCls = getFieldStateClass(fldTotal[mDiscovery.sub]); } DynamicJsonDocument doc2(512); + constexpr static char* unitTotal[] = {"W", "kWh", "Wh", "W"}; doc2[F("name")] = name; - doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic); + doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic.data()); doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(mDiscovery.sub, rec)) : (unitTotal[mDiscovery.sub])); - doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id; + doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id.data(); doc2[F("dev")] = deviceObj; if (!(String(stateCls) == String("total_increasing"))) doc2[F("exp_aft")] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!? @@ -427,13 +433,13 @@ class PubMqtt { doc2[F("stat_cla")] = String(stateCls); if (!total) - snprintf(topic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(topic.data(), topic.size(), "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); else // total values - snprintf(topic, 64, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); + snprintf(topic.data(), topic.size(), "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); size_t size = measureJson(doc2) + 1; - memset(buf, 0, size); - serializeJson(doc2, buf, size); - publish(topic, buf, true, false); + buf.fill(0); + serializeJson(doc2, buf.data(), size); + publish(topic.data(), buf.data(), true, false); if(++mDiscovery.sub == ((!total) ? (rec->length) : 4)) { mDiscovery.sub = 0; @@ -503,15 +509,15 @@ class PubMqtt { mLastIvState[id] = status; changed = true; - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/available", iv->config->name); - snprintf(mVal, 40, "%d", (uint8_t)status); - publish(mSubTopic, mVal, true); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/available", iv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", (uint8_t)status); + publish(mSubTopic.data(), mVal.data(), true); } } if(changed) { - snprintf(mVal, 32, "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); - publish("status", mVal, true); + snprintf(mVal.data(), mVal.size(), "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); + publish("status", mVal.data(), true); } return anyAvail; @@ -533,19 +539,19 @@ class PubMqtt { mSendAlarm[i] = false; - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/cnt", iv->config->name); - snprintf(mVal, 40, "%d", iv->alarmCnt); - publish(mSubTopic, mVal, false); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/alarm/cnt", iv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", iv->alarmCnt); + publish(mSubTopic.data(), mVal.data(), false); for(uint8_t j = 0; j < 10; j++) { if(0 != iv->lastAlarm[j].code) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d", iv->config->name, j); - snprintf(mVal, 100, "{\"code\":%d,\"str\":\"%s\",\"start\":%d,\"end\":%d}", + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/alarm/%d", iv->config->name, j); + snprintf(mVal.data(), mVal.size(), "{\"code\":%d,\"str\":\"%s\",\"start\":%d,\"end\":%d}", iv->lastAlarm[j].code, iv->getAlarmStr(iv->lastAlarm[j].code).c_str(), iv->lastAlarm[j].start + lastMidnight, iv->lastAlarm[j].end + lastMidnight); - publish(mSubTopic, mVal, false); + publish(mSubTopic.data(), mVal.data(), false); yield(); } } @@ -575,9 +581,9 @@ class PubMqtt { } } - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); - snprintf(mVal, 40, "%g", ah::round3(iv->getValue(i, rec))); - publish(mSubTopic, mVal, retained); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); + snprintf(mVal.data(), mVal.size(), "%g", ah::round3(iv->getValue(i, rec))); + publish(mSubTopic.data(), mVal.data(), retained); yield(); } @@ -597,33 +603,33 @@ class PubMqtt { } espMqttClient mClient; - cfgMqtt_t *mCfgMqtt; + cfgMqtt_t *mCfgMqtt = nullptr; #if defined(ESP8266) WiFiEventHandler mHWifiCon, mHWifiDiscon; #endif - HMSYSTEM *mSys; + HMSYSTEM *mSys = nullptr; PubMqttIvData mSendIvData; - uint32_t *mUtcTimestamp, *mUptime; - uint32_t mRxCnt, mTxCnt; + uint32_t *mUtcTimestamp = nullptr, *mUptime = nullptr; + uint32_t mRxCnt = 0, mTxCnt = 0; std::queue mSendList; - std::array mSendAlarm{}; - subscriptionCb mSubscriptionCb; - bool mLastAnyAvail; - InverterStatus mLastIvState[MAX_NUM_INVERTERS]; - uint32_t mIvLastRTRpub[MAX_NUM_INVERTERS]; - uint16_t mIntervalTimeout; + std::array mSendAlarm; + subscriptionCb mSubscriptionCb = nullptr; + bool mLastAnyAvail = false; + std::array mLastIvState; + std::array mIvLastRTRpub; + uint16_t mIntervalTimeout = 0; // last will topic and payload must be available through lifetime of 'espMqttClient' - char mLwtTopic[MQTT_TOPIC_LEN+5]; - const char *mDevName, *mVersion; - char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT + std::array mLwtTopic; + const char *mDevName = nullptr, *mVersion = nullptr; + std::array mClientId; // number of chars is limited to 23 up to v3.1 of MQTT // global buffer for mqtt topic. Used when publishing mqtt messages. - char mTopic[MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1]; - char mSubTopic[32 + MAX_NAME_LENGTH + 1]; - char mVal[100]; - discovery_t mDiscovery; + std::array mTopic; + std::array mSubTopic; + std::array mVal; + discovery_t mDiscovery = {true, 0, 0, 0}; }; #endif /*ENABLE_MQTT*/ diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index cfed38b9..4405d037 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -205,9 +205,9 @@ class PubMqttIvData { } void stateSendTotals() { - uint8_t fieldId; mRTRDataHasBeenSent = true; if(mPos < 5) { + uint8_t fieldId; bool retained = true; switch (mPos) { default: diff --git a/src/publisher/pubSerial.h b/src/publisher/pubSerial.h index 34dc64f2..9ac24593 100644 --- a/src/publisher/pubSerial.h +++ b/src/publisher/pubSerial.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- -// 2022 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// 2024 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __PUB_SERIAL_H__ @@ -13,8 +13,6 @@ template class PubSerial { public: - PubSerial() {} - void setup(settings_t *cfg, HMSYSTEM *sys, uint32_t *utcTs) { mCfg = cfg; mSys = sys; @@ -46,9 +44,9 @@ class PubSerial { } private: - settings_t *mCfg; - HMSYSTEM *mSys; - uint32_t *mUtcTimestamp; + settings_t *mCfg = nullptr; + HMSYSTEM *mSys = nullptr; + uint32_t *mUtcTimestamp = nullptr; }; diff --git a/src/utils/improv.h b/src/utils/improv.h index d5a9ae74..32bc403c 100644 --- a/src/utils/improv.h +++ b/src/utils/improv.h @@ -10,6 +10,7 @@ #include #include "dbg.h" #include "AsyncJson.h" +#include "../appInterface.h" // https://www.improv-wifi.com/serial/ // https://github.com/jnthas/improv-wifi-demo/blob/main/src/esp32-wifiimprov/esp32-wifiimprov.ino @@ -78,7 +79,7 @@ class Improv { DBGPRINTLN(""); } - inline uint8_t buildChecksum(uint8_t buf[], uint8_t len) { + inline uint8_t buildChecksum(const uint8_t buf[], uint8_t len) { uint8_t calc = 0; for(uint8_t i = 0; i < len; i++) { calc += buf[i]; @@ -86,7 +87,7 @@ class Improv { return calc; } - inline bool checkChecksum(uint8_t buf[], uint8_t len) { + inline bool checkChecksum(const uint8_t buf[], uint8_t len) { /*DHEX(buf[len], false); DBGPRINT(F(" == "), false); DBGHEXLN(buildChecksum(buf, len), false);*/ @@ -97,7 +98,7 @@ class Improv { if(len < 11) return false; - if(0 != strncmp((char*)buf, "IMPROV", 6)) + if(0 != strncmp(reinterpret_cast(buf), "IMPROV", 6)) return false; // version check (only version 1 is supported!) @@ -199,7 +200,7 @@ class Improv { dumpBuf(buf, len); } - void parsePayload(uint8_t type, uint8_t buf[], uint8_t len) { + void parsePayload(uint8_t type, const uint8_t buf[], uint8_t len) { if(TYPE_RPC == type) { if(GET_CURRENT_STATE == buf[0]) { setDebugEn(false); @@ -212,9 +213,10 @@ class Improv { } } - IApp *mApp; - const char *mDevName, *mVersion; - bool mScanRunning; + IApp *mApp = nullptr; + const char *mDevName = nullptr; + const char *mVersion = nullptr; + bool mScanRunning = false; }; #endif diff --git a/src/utils/scheduler.h b/src/utils/scheduler.h index 751550df..16009778 100644 --- a/src/utils/scheduler.h +++ b/src/utils/scheduler.h @@ -7,6 +7,7 @@ #define __SCHEDULER_H__ #include +#include #include "dbg.h" namespace ah { @@ -28,8 +29,6 @@ namespace ah { class Scheduler { public: - Scheduler() {} - void setup(bool directStart) { mUptime = 0; mTimestamp = (directStart) ? 1 : 0; @@ -93,8 +92,7 @@ namespace ah { } inline void resetTicker(void) { - for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) - mTickerInUse[i] = false; + mTickerInUse.fill(false); } void getStat(uint8_t *max) { @@ -159,11 +157,11 @@ namespace ah { } } - sP mTicker[MAX_NUM_TICKER]; - bool mTickerInUse[MAX_NUM_TICKER]; - uint32_t mMillis, mPrevMillis, mDiff; - uint8_t mDiffSeconds; - uint8_t mMax; + std::array mTicker; + std::array mTickerInUse; + uint32_t mMillis = 0, mPrevMillis = 0, mDiff = 0; + uint8_t mDiffSeconds = 0; + uint8_t mMax = 0; }; } diff --git a/src/utils/spiPatcher.h b/src/utils/spiPatcher.h index 2f8ce616..210b2a09 100644 --- a/src/utils/spiPatcher.h +++ b/src/utils/spiPatcher.h @@ -16,7 +16,7 @@ class SpiPatcher { protected: - SpiPatcher(spi_host_device_t dev) : + explicit SpiPatcher(spi_host_device_t dev) : mHostDevice(dev), mCurHandle(nullptr) { // Use binary semaphore instead of mutex for performance reasons mutex = xSemaphoreCreateBinaryStatic(&mutex_buffer); diff --git a/src/utils/timemonitor.h b/src/utils/timemonitor.h index 9f99cc92..18ab51d9 100644 --- a/src/utils/timemonitor.h +++ b/src/utils/timemonitor.h @@ -22,14 +22,14 @@ class TimeMonitor { /** * A constructor for creating a TimeMonitor object */ - TimeMonitor(void) {} + TimeMonitor() {} /** * A constructor for initializing a TimeMonitor object * @param timeout timeout in ms * @param start (optional) if true, start TimeMonitor immediately */ - TimeMonitor(uint32_t timeout, bool start = false) { + explicit TimeMonitor(uint32_t timeout, bool start = false) { if (start) startTimeMonitor(timeout); else @@ -80,7 +80,7 @@ class TimeMonitor { * true: TimeMonitor already timed out * false: TimeMonitor still in time or TimeMonitor was stopped */ - bool isTimeout(void) { + bool isTimeout(void) const { if ((mStarted) && ((millis() - mStartTime) >= mTimeout)) return true; else diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 564d6c62..acd085f3 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -141,7 +141,7 @@ class RestApi { #endif } - void onApiPostBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { + void onApiPostBody(AsyncWebServerRequest *request, const uint8_t *data, size_t len, size_t index, size_t total) { DPRINTLN(DBG_VERBOSE, "onApiPostBody"); if(0 == index) { @@ -158,7 +158,7 @@ class RestApi { DynamicJsonDocument json(1000); - DeserializationError err = deserializeJson(json, (const char *)mTmpBuf, mTmpSize); + DeserializationError err = deserializeJson(json, reinterpret_cast(mTmpBuf), mTmpSize); JsonObject obj = json.as(); AsyncJsonResponse* response = new AsyncJsonResponse(false, 200); @@ -930,20 +930,20 @@ class RestApi { return true; } - IApp *mApp; - HMSYSTEM *mSys; - HmRadio<> *mRadioNrf; + IApp *mApp = nullptr; + HMSYSTEM *mSys = nullptr; + HmRadio<> *mRadioNrf = nullptr; #if defined(ESP32) - CmtRadio<> *mRadioCmt; + CmtRadio<> *mRadioCmt = nullptr; #endif - AsyncWebServer *mSrv; - settings_t *mConfig; + AsyncWebServer *mSrv = nullptr; + settings_t *mConfig = nullptr; - uint32_t mTimezoneOffset; - uint32_t mHeapFree, mHeapFreeBlk; - uint8_t mHeapFrag; + uint32_t mTimezoneOffset = 0; + uint32_t mHeapFree = 0, mHeapFreeBlk = 0; + uint8_t mHeapFrag = 0; uint8_t *mTmpBuf = NULL; - uint32_t mTmpSize; + uint32_t mTmpSize = 0; }; #endif /*__WEB_API_H__*/ diff --git a/src/web/web.h b/src/web/web.h index 0ffd0594..a166377f 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -48,9 +48,6 @@ class Web { public: Web(void) : mWeb(80), mEvts("/events") { memset(mSerialBuf, 0, WEB_SERIAL_BUF_SIZE); - mSerialBufFill = 0; - mSerialAddTime = true; - mSerialClientConnnected = false; } void setup(IApp *app, HMSYSTEM *sys, settings_t *config) { @@ -490,9 +487,8 @@ class Web { // pinout - uint8_t pin; for (uint8_t i = 0; i < 16; i++) { - pin = request->arg(String(pinArgNames[i])).toInt(); + uint8_t pin = request->arg(String(pinArgNames[i])).toInt(); switch(i) { case 0: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_NRF_CS_PIN); break; case 1: mConfig->nrf.pinCe = ((pin != 0xff) ? pin : DEF_NRF_CE_PIN); break; @@ -633,8 +629,8 @@ class Web { // NOTE: Grouping for fields with channels and totals is currently not working // TODO: Handle grouping and sorting for independant from channel number // NOTE: Check packetsize for MAX_NUM_INVERTERS. Successfully Tested with 4 Inverters (each with 4 channels) - const char * metricConstPrefix = "ahoy_solar_"; - const char * metricConstInverterFormat = " {inverter=\"%s\"} %d\n"; + const char* metricConstPrefix = "ahoy_solar_"; + const char* metricConstInverterFormat = " {inverter=\"%s\"} %d\n"; typedef enum { metricsStateInverterInfo=0, metricsStateInverterEnabled=1, metricsStateInverterAvailable=2, metricsStateInverterProducing=3, metricsStateInverterPowerLimitRead=4, metricsStateInverterPowerLimitAck=5, @@ -648,7 +644,7 @@ class Web { metricsStateStart, metricsStateEnd } MetricStep_t; - MetricStep_t metricsStep; + MetricStep_t metricsStep = metricsStateInverterInfo; typedef struct { const char *topic; const char *type; @@ -674,9 +670,6 @@ class Web { { "radio_dtu_loss_cnt", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.dtuLoss;} }, { "radio_dtu_sent_cnt", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.dtuSent;} } }; - int metricsInverterId; - uint8_t metricsFieldId; - bool metricDeclared, metricTotalDeclard; void showMetrics(AsyncWebServerRequest *request) { DPRINTLN(DBG_VERBOSE, F("web::showMetrics")); @@ -715,7 +708,7 @@ class Web { snprintf(topic,sizeof(topic),"%swifi_rssi_db{devicename=\"%s\"} %d\n",metricConstPrefix, mConfig->sys.deviceName, WiFi.RSSI()); metrics += String(type) + String(topic); - len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + len = snprintf(reinterpret_cast(buffer), maxLen,"%s",metrics.c_str()); // Next is Inverter information metricsStep = metricsStateInverterInfo; break; @@ -743,7 +736,7 @@ class Web { (String("ahoy_solar_inverter_") + inverterMetrics[metricsStep].topic + inverterMetrics[metricsStep].format).c_str(), inverterMetrics[metricsStep].valueFunc); - len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + len = snprintf(reinterpret_cast(buffer), maxLen, "%s", metrics.c_str()); // ugly hack to increment the enum metricsStep = static_cast( static_cast(metricsStep) + 1); // Prepare Realtime Field loop, which may be startet next @@ -763,7 +756,7 @@ class Web { metrics = "# Info: all realtime fields processed\n"; metricsStep = metricsStateAlarmData; } - len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + len = snprintf(reinterpret_cast(buffer), maxLen, "%s", metrics.c_str()); break; case metricStateRealtimeInverterId: // Iterate over all inverters for this field @@ -837,7 +830,7 @@ class Web { metricsFieldId++; // Process next field Id metricsStep = metricStateRealtimeFieldId; } - len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + len = snprintf(reinterpret_cast(buffer), maxLen, "%s", metrics.c_str()); break; case metricsStateAlarmData: // Alarm Info loop : fit to one packet @@ -861,7 +854,7 @@ class Web { } } } - len = snprintf((char*)buffer,maxLen,"%s",metrics.c_str()); + len = snprintf(reinterpret_cast(buffer), maxLen, "%s", metrics.c_str()); metricsStep = metricsStateEnd; break; @@ -880,10 +873,9 @@ class Web { // Traverse all inverters and collect the metric via valueFunc String inverterMetric(char *buffer, size_t len, const char *format, std::function *iv)> valueFunc) { - Inverter<> *iv; String metric = ""; for (int metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) { - iv = mSys->getInverterByPos(metricsInverterId); + Inverter<> *iv = mSys->getInverterByPos(metricsInverterId); if (NULL != iv) { snprintf(buffer,len,format,iv->config->name, valueFunc(iv)); metric += String(buffer); @@ -904,21 +896,27 @@ class Web { if(shortUnit == "Hz") return {"_hertz", "gauge"}; return {"", "gauge"}; } + + private: + int metricsInverterId = 0; + uint8_t metricsFieldId = 0; + bool metricDeclared = false, metricTotalDeclard = false; #endif + private: AsyncWebServer mWeb; AsyncEventSource mEvts; - IApp *mApp; - HMSYSTEM *mSys; + IApp *mApp = nullptr; + HMSYSTEM *mSys = nullptr; - settings_t *mConfig; + settings_t *mConfig = nullptr; - bool mSerialAddTime; + bool mSerialAddTime = true; char mSerialBuf[WEB_SERIAL_BUF_SIZE]; - uint16_t mSerialBufFill; - bool mSerialClientConnnected; + uint16_t mSerialBufFill = 0; + bool mSerialClientConnnected = false; File mUploadFp; - bool mUploadFail; + bool mUploadFail = false; }; #endif /*__WEB_H__*/ diff --git a/src/wifi/ahoywifi.h b/src/wifi/ahoywifi.h index 709c08c4..d38701aa 100644 --- a/src/wifi/ahoywifi.h +++ b/src/wifi/ahoywifi.h @@ -71,7 +71,7 @@ class ahoywifi { void welcome(String ip, String mode); - settings_t *mConfig = NULL; + settings_t *mConfig = nullptr; appWifiCb mAppWifiCb; DNSServer mDns; @@ -81,15 +81,15 @@ class ahoywifi { WiFiEventHandler wifiConnectHandler, wifiDisconnectHandler, wifiGotIPHandler; #endif - WiFiStatus_t mStaConn; - uint8_t mCnt; - uint32_t *mUtcTimestamp; + WiFiStatus_t mStaConn = DISCONNECTED; + uint8_t mCnt = 0; + uint32_t *mUtcTimestamp = nullptr; - uint8_t mScanCnt; - bool mScanActive; - bool mGotDisconnect; + uint8_t mScanCnt = 0; + bool mScanActive = false; + bool mGotDisconnect = false; std::list mBSSIDList; - bool mStopApAllowed; + bool mStopApAllowed = false; bool mWasInCh12to14 = false; }; From 1f0b15c5beece854c02df929835aa274369762e3 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 6 Feb 2024 00:01:45 +0100 Subject: [PATCH 33/79] 0.8.74 --- .github/workflows/compile_development.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 4b5a0e1a..66dbf74b 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -33,7 +33,7 @@ jobs: - opendtufusion-ethernet steps: - uses: actions/checkout@v4 - - uses: benjlevesque/short-sha@v2.2 + - uses: benjlevesque/short-sha@v3.0 id: short-sha with: length: 7 @@ -93,7 +93,7 @@ jobs: - opendtufusion-ethernet-de steps: - uses: actions/checkout@v4 - - uses: benjlevesque/short-sha@v2.2 + - uses: benjlevesque/short-sha@v3.0 id: short-sha with: length: 7 From 90d4df4b916a1b1c873d305d6529c528ae06f7c3 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 6 Feb 2024 23:04:10 +0100 Subject: [PATCH 34/79] 0.8.75 * fix active power control value #1406, #1409 * update Mqtt lib to version `1.6.0` * take care of null terminator of chars #1410, #1411 --- src/CHANGES.md | 5 ++++ src/defines.h | 2 +- src/hm/hmInverter.h | 2 +- src/platformio.ini | 10 +++---- src/publisher/pubMqtt.h | 64 ++++++++++++++++++++--------------------- src/web/RestApi.h | 2 +- src/web/web.h | 20 ++++++------- 7 files changed, 55 insertions(+), 50 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f0491335..c01127ce 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.75 - 2024-02-06 +* fix active power control value #1406, #1409 +* update Mqtt lib to version `1.6.0` +* take care of null terminator of chars #1410, #1411 + ## 0.8.74 - 2024-02-05 * reduced cppcheck linter warnings significantly diff --git a/src/defines.h b/src/defines.h index bc9d2452..cdbeee42 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 74 +#define VERSION_PATCH 75 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 275fce2c..51cb0d6d 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -120,7 +120,7 @@ class Inverter { uint8_t type = INV_TYPE_1CH; // integer which refers to inverter type uint16_t alarmMesIndex = 0; // Last recorded Alarm Message Index uint16_t powerLimit[2] = {0xffff, AbsolutNonPersistent}; // limit power output (multiplied by 10) - float actPowerLimit = -1; // actual power limit + uint16_t actPowerLimit = 0xffff; // actual power limit bool powerLimitAck = false; // acknowledged power limit uint8_t devControlCmd = InitDataState; // carries the requested cmd serial_u radioId; // id converted to modbus diff --git a/src/platformio.ini b/src/platformio.ini index 9b97e018..f949aa37 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -28,7 +28,7 @@ lib_deps = https://github.com/yubox-node-org/ESPAsyncWebServer https://github.com/nRF24/RF24 @ 1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.5.0 + https://github.com/bertmelis/espMqttClient#v1.6.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 @@ -197,7 +197,7 @@ lib_deps = khoih-prog/AsyncUDP_ESP32_W5500 https://github.com/nRF24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.5.0 + https://github.com/bertmelis/espMqttClient#v1.6.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 @@ -220,7 +220,7 @@ lib_deps = khoih-prog/AsyncUDP_ESP32_W5500 https://github.com/nRF24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.5.0 + https://github.com/bertmelis/espMqttClient#v1.6.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 @@ -414,7 +414,7 @@ lib_deps = khoih-prog/AsyncUDP_ESP32_W5500 https://github.com/nrf24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.5.0 + https://github.com/bertmelis/espMqttClient#v1.6.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 @@ -459,7 +459,7 @@ lib_deps = khoih-prog/AsyncUDP_ESP32_W5500 https://github.com/nrf24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.5.0 + https://github.com/bertmelis/espMqttClient#v1.6.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 7799b6d2..0e10e688 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -67,15 +67,15 @@ class PubMqtt { }); mDiscovery.running = false; - snprintf(mLwtTopic.data(), mLwtTopic.size(), "%s/mqtt", mCfgMqtt->topic); + snprintf(mLwtTopic.data(), mLwtTopic.size() - 1, "%s/mqtt", mCfgMqtt->topic); if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0)) mClient.setCredentials(mCfgMqtt->user, mCfgMqtt->pwd); if(strlen(mCfgMqtt->clientId) > 0) - snprintf(mClientId.data(), mClientId.size(), "%s", mCfgMqtt->clientId); + snprintf(mClientId.data(), mClientId.size() - 1, "%s", mCfgMqtt->clientId); else { - snprintf(mClientId.data(), mClientId.size(), "%s-", mDevName); + snprintf(mClientId.data(), mClientId.size() - 1, "%s-", mDevName); uint8_t pos = strlen(mClientId.data()); mClientId[pos++] = WiFi.macAddress().substring( 9, 10).c_str()[0]; mClientId[pos++] = WiFi.macAddress().substring(10, 11).c_str()[0]; @@ -129,7 +129,7 @@ class PubMqtt { } void tickerMinute() { - snprintf(mVal.data(), mVal.size(), "%u", (*mUptime)); + snprintf(mVal.data(), mVal.size() - 1, "%u", (*mUptime)); publish(subtopics[MQTT_UPTIME], mVal.data()); publish(subtopics[MQTT_RSSI], String(WiFi.RSSI()).c_str()); publish(subtopics[MQTT_FREE_HEAP], String(ESP.getFreeHeap()).c_str()); @@ -152,11 +152,11 @@ class PubMqtt { if(NULL == iv) continue; - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/dis_night_comm", iv->config->name); + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/dis_night_comm", iv->config->name); publish(mSubTopic.data(), ((iv->commEnabled) ? dict[STR_TRUE] : dict[STR_FALSE]), true); } - snprintf(mSubTopic.data(), mSubTopic.size(), "comm_disabled"); + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "comm_disabled"); publish(mSubTopic.data(), (((*mUtcTimestamp > (sunset + offsE)) || (*mUtcTimestamp < (sunrise + offsM))) ? dict[STR_TRUE] : dict[STR_FALSE]), true); return true; @@ -179,8 +179,8 @@ class PubMqtt { void tickerMidnight() { // set Total YieldDay to zero - snprintf(mSubTopic.data(), mSubTopic.size(), "total/%s", fields[FLD_YD]); - snprintf(mVal.data(), mVal.size(), "0"); + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "total/%s", fields[FLD_YD]); + snprintf(mVal.data(), mVal.size() - 1, "0"); publish(mSubTopic.data(), mVal.data(), true); } @@ -200,9 +200,9 @@ class PubMqtt { return; if(addTopic) - snprintf(mTopic.data(), mTopic.size(), "%s/%s", mCfgMqtt->topic, subTopic); + snprintf(mTopic.data(), mTopic.size() - 1, "%s/%s", mCfgMqtt->topic, subTopic); else - snprintf(mTopic.data(), mTopic.size(), "%s", subTopic); + snprintf(mTopic.data(), mTopic.size() - 1, "%s", subTopic); mClient.publish(mTopic.data(), qos, retained, payload); yield(); @@ -241,7 +241,7 @@ class PubMqtt { void setPowerLimitAck(Inverter<> *iv) { if (NULL != iv) { - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); publish(mSubTopic.data(), "true", true, true, QOS_2); } } @@ -261,11 +261,11 @@ class PubMqtt { publish(mLwtTopic.data(), mqttStr[MQTT_STR_LWT_CONN], true, false); for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - snprintf(mVal.data(), mVal.size(), "ctrl/limit/%d", i); + snprintf(mVal.data(), mVal.size() - 1, "ctrl/limit/%d", i); subscribe(mVal.data(), QOS_2); - snprintf(mVal.data(), mVal.size(), "ctrl/restart/%d", i); + snprintf(mVal.data(), mVal.size() - 1, "ctrl/restart/%d", i); subscribe(mVal.data()); - snprintf(mVal.data(), mVal.size(), "ctrl/power/%d", i); + snprintf(mVal.data(), mVal.size() - 1, "ctrl/power/%d", i); subscribe(mVal.data()); } subscribe(subscr[MQTT_SUBS_SET_TIME]); @@ -400,20 +400,20 @@ class PubMqtt { const char *devCls, *stateCls; if (!total) { if (rec->assign[mDiscovery.sub].ch == CH0) - snprintf(name.data(), name.size(), "%s", iv->getFieldName(mDiscovery.sub, rec)); + snprintf(name.data(), name.size() - 1, "%s", iv->getFieldName(mDiscovery.sub, rec)); else - snprintf(name.data(), name.size(), "CH%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); - snprintf(topic.data(), name.size(), "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); - snprintf(uniq_id.data(), uniq_id.size(), "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(name.data(), name.size() - 1, "CH%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(topic.data(), name.size() - 1, "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(uniq_id.data(), uniq_id.size() - 1, "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); devCls = getFieldDeviceClass(rec->assign[mDiscovery.sub].fieldId); stateCls = getFieldStateClass(rec->assign[mDiscovery.sub].fieldId); } else { // total values - snprintf(name.data(), name.size(), "Total %s", fields[fldTotal[mDiscovery.sub]]); - snprintf(topic.data(), topic.size(), "/%s", fields[fldTotal[mDiscovery.sub]]); - snprintf(uniq_id.data(), uniq_id.size(), "total_%s", fields[fldTotal[mDiscovery.sub]]); + snprintf(name.data(), name.size() - 1, "Total %s", fields[fldTotal[mDiscovery.sub]]); + snprintf(topic.data(), topic.size() - 1, "/%s", fields[fldTotal[mDiscovery.sub]]); + snprintf(uniq_id.data(), uniq_id.size() - 1, "total_%s", fields[fldTotal[mDiscovery.sub]]); devCls = getFieldDeviceClass(fldTotal[mDiscovery.sub]); stateCls = getFieldStateClass(fldTotal[mDiscovery.sub]); } @@ -433,9 +433,9 @@ class PubMqtt { doc2[F("stat_cla")] = String(stateCls); if (!total) - snprintf(topic.data(), topic.size(), "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(topic.data(), topic.size() - 1, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); else // total values - snprintf(topic.data(), topic.size(), "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); + snprintf(topic.data(), topic.size() - 1, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); size_t size = measureJson(doc2) + 1; buf.fill(0); serializeJson(doc2, buf.data(), size); @@ -509,14 +509,14 @@ class PubMqtt { mLastIvState[id] = status; changed = true; - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/available", iv->config->name); - snprintf(mVal.data(), mVal.size(), "%d", (uint8_t)status); + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/available", iv->config->name); + snprintf(mVal.data(), mVal.size() - 1, "%d", (uint8_t)status); publish(mSubTopic.data(), mVal.data(), true); } } if(changed) { - snprintf(mVal.data(), mVal.size(), "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); + snprintf(mVal.data(), mVal.size() - 1, "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); publish("status", mVal.data(), true); } @@ -539,14 +539,14 @@ class PubMqtt { mSendAlarm[i] = false; - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/alarm/cnt", iv->config->name); - snprintf(mVal.data(), mVal.size(), "%d", iv->alarmCnt); + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/alarm/cnt", iv->config->name); + snprintf(mVal.data(), mVal.size() - 1, "%d", iv->alarmCnt); publish(mSubTopic.data(), mVal.data(), false); for(uint8_t j = 0; j < 10; j++) { if(0 != iv->lastAlarm[j].code) { - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/alarm/%d", iv->config->name, j); - snprintf(mVal.data(), mVal.size(), "{\"code\":%d,\"str\":\"%s\",\"start\":%d,\"end\":%d}", + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/alarm/%d", iv->config->name, j); + snprintf(mVal.data(), mVal.size() - 1, "{\"code\":%d,\"str\":\"%s\",\"start\":%d,\"end\":%d}", iv->lastAlarm[j].code, iv->getAlarmStr(iv->lastAlarm[j].code).c_str(), iv->lastAlarm[j].start + lastMidnight, @@ -581,8 +581,8 @@ class PubMqtt { } } - snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); - snprintf(mVal.data(), mVal.size(), "%g", ah::round3(iv->getValue(i, rec))); + snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); + snprintf(mVal.data(), mVal.size() - 1, "%g", ah::round3(iv->getValue(i, rec))); publish(mSubTopic.data(), mVal.data(), retained); yield(); diff --git a/src/web/RestApi.h b/src/web/RestApi.h index acd085f3..ce580dd5 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -500,7 +500,7 @@ class RestApi { obj[F("name")] = String(iv->config->name); obj[F("serial")] = String(iv->config->serial.u64, HEX); obj[F("version")] = String(iv->getFwVersion()); - obj[F("power_limit_read")] = ah::round3(iv->actPowerLimit); + obj[F("power_limit_read")] = iv->actPowerLimit; obj[F("power_limit_ack")] = iv->powerLimitAck; obj[F("max_pwr")] = iv->getMaxPower(); obj[F("ts_last_success")] = rec->ts; diff --git a/src/web/web.h b/src/web/web.h index a166377f..c40c817c 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -656,7 +656,7 @@ class Web { { "is_enabled", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->config->enabled;} }, { "is_available", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->isAvailable();} }, { "is_producing", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->isProducing();} }, - { "power_limit_read", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return (int64_t)ah::round3(iv->actPowerLimit);} }, + { "power_limit_read", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->actPowerLimit;} }, { "power_limit_ack", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return (iv->powerLimitAck)?1:0;} }, { "max_power", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->getMaxPower();} }, { "radio_rx_success", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxSuccess;} }, @@ -786,14 +786,14 @@ class Web { char total[7]; if (metricDeclared) { // A declaration and value for channels have been delivered. So declare and deliver a _total metric - strncpy(total, "_total", 6); + snprintf(total, sizeof(total)-1, "_total"); } if (!metricTotalDeclard) { - snprintf(type, sizeof(type), "# TYPE %s%s%s%s %s\n",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str()); + snprintf(type, sizeof(type)-1, "# TYPE %s%s%s%s %s\n",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str()); metrics += type; metricTotalDeclard = true; } - snprintf(topic, sizeof(topic), "%s%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total,iv->config->name); + snprintf(topic, sizeof(topic)-1, "%s%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total,iv->config->name); } else { // Report (non zero) channel value // Use a fallback channel name (ch0, ch1, ...)if non is given by user @@ -801,11 +801,11 @@ class Web { if (iv->config->chName[channel-1][0] != 0) { strncpy(chName, iv->config->chName[channel-1], sizeof(chName)); } else { - snprintf(chName,sizeof(chName),"ch%1d",channel); + snprintf(chName,sizeof(chName)-1,"ch%1d",channel); } - snprintf(topic, sizeof(topic), "%s%s%s{inverter=\"%s\",channel=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,chName); + snprintf(topic, sizeof(topic)-1, "%s%s%s{inverter=\"%s\",channel=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,chName); } - snprintf(val, sizeof(val), " %.3f\n", iv->getValue(metricsChannelId, rec)); + snprintf(val, sizeof(val)-1, " %.3f\n", iv->getValue(metricsChannelId, rec)); metrics += topic; metrics += val; } @@ -835,7 +835,7 @@ class Web { case metricsStateAlarmData: // Alarm Info loop : fit to one packet // Perform grouping on metrics according to Prometheus exposition format specification - snprintf(type, sizeof(type),"# TYPE %s%s gauge\n",metricConstPrefix,fields[FLD_LAST_ALARM_CODE]); + snprintf(type, sizeof(type)-1,"# TYPE %s%s gauge\n",metricConstPrefix,fields[FLD_LAST_ALARM_CODE]); metrics = type; for (metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) { @@ -847,8 +847,8 @@ class Web { alarmChannelId = 0; if (alarmChannelId < rec->length) { std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(alarmChannelId, rec)); - snprintf(topic, sizeof(topic), "%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name); - snprintf(val, sizeof(val), " %.3f\n", iv->getValue(alarmChannelId, rec)); + snprintf(topic, sizeof(topic)-1, "%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name); + snprintf(val, sizeof(val)-1, " %.3f\n", iv->getValue(alarmChannelId, rec)); metrics += topic; metrics += val; } From 716c3da3df6483047754ad154819f70b8ec009b1 Mon Sep 17 00:00:00 2001 From: tictrick <117273857+tictrick@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:36:57 +0100 Subject: [PATCH 35/79] Bugfix: HMT would not start Am Morgen wollten die HMTs nicht starten. --- src/hm/hmSystem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 0266a948..22318347 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -69,6 +69,7 @@ class HmSystem { } else if(iv->config->serial.b[5] == 0x13) { iv->ivGen = IV_HMT; iv->type = INV_TYPE_6CH; + iv->ivRadioType = INV_RADIO_TYPE_CMT; } else if(iv->config->serial.u64 != 0ULL) { DPRINTLN(DBG_ERROR, F("inverter type can't be detected!")); return; From 7c532ca1cc63bfda9a68cfb9b7baf23d1d17f94b Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 7 Feb 2024 22:50:13 +0100 Subject: [PATCH 36/79] 0.8.76 * revert changes from yesterday regarding snprintf and its size #1410, #1411 * reduced cppcheck linter warnings significantly * try to improve ePaper (ghosting) #1107 --- src/CHANGES.md | 5 ++ src/app.cpp | 5 +- src/defines.h | 2 +- src/hm/Communication.h | 14 ++-- src/hm/Heuristic.h | 2 +- src/hm/hmRadio.h | 6 +- src/hm/radio.h | 14 ++-- src/hm/simulator.h | 6 +- src/hms/hmsRadio.h | 7 +- src/plugins/Display/Display.h | 20 +++--- src/plugins/Display/Display_Mono_128X32.h | 6 +- src/plugins/Display/Display_Mono_128X64.h | 39 +++++------- src/plugins/Display/Display_Mono_64X48.h | 6 +- src/plugins/Display/Display_Mono_84X48.h | 27 ++++---- src/plugins/Display/Display_ePaper.cpp | 17 +++-- src/plugins/history.h | 7 +- src/publisher/pubMqtt.h | 78 +++++++++++------------ src/publisher/pubMqttIvData.h | 26 ++++---- src/utils/improv.h | 2 +- src/utils/syslog.cpp | 1 + src/utils/syslog.h | 5 +- src/web/Protection.h | 2 +- src/web/web.h | 25 ++++---- 23 files changed, 164 insertions(+), 158 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index c01127ce..a9301d44 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.76 - 2024-02-07 +* revert changes from yesterday regarding snprintf and its size #1410, #1411 +* reduced cppcheck linter warnings significantly +* try to improve ePaper (ghosting) #1107 + ## 0.8.75 - 2024-02-06 * fix active power control value #1406, #1409 * update Mqtt lib to version `1.6.0` diff --git a/src/app.cpp b/src/app.cpp index d9b0f933..c93be777 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -264,11 +264,10 @@ void app::tickNtpUpdate(void) { #endif if (isOK) { this->updateNtp(); - - nxtTrig = isOK ? (mConfig->ntp.interval * 60) : 60; // depending on NTP update success check again in 12h (depends on setting) or in 1 min + nxtTrig = mConfig->ntp.interval * 60; // check again in 12h // immediately start communicating - if (isOK && mSendFirst) { + if (mSendFirst) { mSendFirst = false; once(std::bind(&app::tickSend, this), 1, "senOn"); } diff --git a/src/defines.h b/src/defines.h index cdbeee42..9ea3834c 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 75 +#define VERSION_PATCH 76 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 326fb57e..21b78405 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -698,7 +698,7 @@ class Communication : public CommQueue<> { byte[23] to byte[26] Matching_APPFW_PN*/ DPRINT(DBG_INFO,F("HW_PartNo ")); DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])); - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = q->ts; q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); rec->mqttSentStatus = MqttSentStatus::NEW_DATA; @@ -899,14 +899,16 @@ class Communication : public CommQueue<> { q->iv->alarmCnt = 1; // minimum... stsok = false; //sth is or was wrong? - if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + if ((q->iv->type != INV_TYPE_1CH) + && ((statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (q->iv->lastAlarm[stschan].code != 1))) ) { q->iv->lastAlarm[stschan+q->iv->type==INV_TYPE_2CH ? 2: 4] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; - } else if ( (q->iv->type == INV_TYPE_1CH) && ( (statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + } else if ((q->iv->type == INV_TYPE_1CH) + && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (q->iv->lastAlarm[stschan].code != 1))) ) { q->iv->lastAlarm[stschan] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); } else if (q->iv->type == INV_TYPE_1CH) @@ -962,7 +964,7 @@ class Communication : public CommQueue<> { iv->radioStatistics.ivLoss = iv->radioStatistics.ivSent - iv->mDtuRxCnt; // this is what we didn't receive iv->radioStatistics.dtuLoss = iv->mIvTxCnt; // this is somehow the requests w/o answers in that periode iv->radioStatistics.dtuSent = iv->mDtuTxCnt; - if (mSerialDebug) { + if (*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN("DTU loss: " + String (iv->radioStatistics.ivLoss) + "/" + diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 2a36bc78..ecf82aa7 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -132,7 +132,7 @@ class Heuristic { ih->lastRxFragments = rxFragments; } - void printStatus(Inverter<> *iv) { + void printStatus(const Inverter<> *iv) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("Radio infos:")); if((IV_HMS != iv->ivGen) && (IV_HMT != iv->ivGen)) { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index aef4f49d..df6a18b4 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -395,9 +395,9 @@ class HmRadio : public Radio { #endif*/ if(*mPrintWholeTrace) { if(*mPrivacyMode) - ah::dumpBuf(mTxBuf, len, 1, 4); + ah::dumpBuf(mTxBuf.data(), len, 1, 4); else - ah::dumpBuf(mTxBuf, len); + ah::dumpBuf(mTxBuf.data(), len); } else { DHEX(mTxBuf[0]); DBGPRINT(F(" ")); @@ -415,7 +415,7 @@ class HmRadio : public Radio { } mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); - mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response + mNrf24->startWrite(mTxBuf.data(), len, false); // false = request ACK response mMillis = millis(); mLastIv = iv; diff --git a/src/hm/radio.h b/src/hm/radio.h index db694b54..31643980 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -11,6 +11,7 @@ #define ALL_FRAMES 0x80 #define SINGLE_FRAME 0x81 +#include #include #include "../utils/dbg.h" #include "../utils/crc.h" @@ -34,6 +35,8 @@ class Radio { virtual std::pair getFreqRangeMhz(void) { return std::make_pair(0, 0); } virtual bool loop(void) = 0; + Radio() : mTxBuf{} {} + void handleIntr(void) { mIrqRcvd = true; mIrqOk = IRQ_OK; @@ -107,7 +110,7 @@ class Radio { mTxBuf[(*len)++] = (crc ) & 0xff; } // crc over all - mTxBuf[*len] = ah::crc8(mTxBuf, *len); + mTxBuf[*len] = ah::crc8(mTxBuf.data(), *len); (*len)++; } @@ -129,12 +132,11 @@ class Radio { mDtuSn |= 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal } - - - uint32_t mDtuSn; - std::atomic mIrqRcvd; + protected: + uint32_t mDtuSn = 0; + std::atomic mIrqRcvd = false; bool *mSerialDebug = nullptr, *mPrivacyMode = nullptr, *mPrintWholeTrace = nullptr; - uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; + std::array mTxBuf; }; #endif /*__RADIO_H__*/ diff --git a/src/hm/simulator.h b/src/hm/simulator.h index 4e06062e..3d0b43d7 100644 --- a/src/hm/simulator.h +++ b/src/hm/simulator.h @@ -118,9 +118,9 @@ class Simulator { } private: - HMSYSTEM *mSys; - uint8_t mIvId; - uint32_t *mTimestamp; + HMSYSTEM *mSys = nullptr; + uint8_t mIvId = 0; + uint32_t *mTimestamp = nullptr; payloadListenerType mCbPayload = nullptr; uint8_t payloadCtrl = 0; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 66e312d7..cb181b0b 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -21,6 +21,7 @@ class CmtRadio : public Radio { mPrivacyMode = privacyMode; mSerialDebug = serialDebug; mPrintWholeTrace = printWholeTrace; + mTxBuf.fill(0); } bool loop() override { @@ -102,9 +103,9 @@ class CmtRadio : public Radio { DBGPRINT(F("Mhz | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) - ah::dumpBuf(mTxBuf, len, 1, 4); + ah::dumpBuf(mTxBuf.data(), len, 1, 4); else - ah::dumpBuf(mTxBuf, len); + ah::dumpBuf(mTxBuf.data(), len); } else { DHEX(mTxBuf[0]); DBGPRINT(F(" ")); @@ -114,7 +115,7 @@ class CmtRadio : public Radio { } } - CmtStatus status = mCmt.tx(mTxBuf, len); + CmtStatus status = mCmt.tx(mTxBuf.data(), len); mMillis = millis(); if(CmtStatus::SUCCESS != status) { DPRINT(DBG_WARN, F("CMT TX failed, code: ")); diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index c59a56b6..b2c88b05 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -223,21 +223,21 @@ class Display { } // private member variables - IApp *mApp; + IApp *mApp = nullptr; DisplayData mDisplayData; - bool mNewPayload; - uint8_t mLoopCnt; - uint32_t *mUtcTs; - display_t *mCfg; - HMSYSTEM *mSys; - RADIO *mHmRadio; - RADIO *mHmsRadio; - uint16_t mRefreshCycle; + bool mNewPayload = false; + uint8_t mLoopCnt = 0; + uint32_t *mUtcTs = nullptr; + display_t *mCfg = nullptr; + HMSYSTEM *mSys = nullptr; + RADIO *mHmRadio = nullptr; + RADIO *mHmsRadio = nullptr; + uint16_t mRefreshCycle = 0; #if defined(ESP32) && !defined(ETHERNET) DisplayEPaper mEpaper; #endif - DisplayMono *mMono; + DisplayMono *mMono = nullptr; }; #endif /*PLUGIN_DISPLAY*/ diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index 3e5a1762..6262e3f6 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -12,11 +12,11 @@ class DisplayMono128X32 : public DisplayMono { mExtra = 0; } - void config(display_t *cfg) { + void config(display_t *cfg) override { mCfg = cfg; } - void init(DisplayData *displayData) { + void init(DisplayData *displayData) override { u8g2_cb_t *rot = (u8g2_cb_t *)((mCfg->rot != 0x00) ? U8G2_R2 : U8G2_R0); monoInit(new U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C(rot, 0xff, mCfg->disp_clk, mCfg->disp_data), displayData); calcLinePositions(); @@ -26,7 +26,7 @@ class DisplayMono128X32 : public DisplayMono { mDisplay->sendBuffer(); } - void disp(void) { + void disp(void) override { mDisplay->clearBuffer(); // calculate current pixelshift for pixelshift screensaver diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 69afae04..c63f0b22 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -13,11 +13,11 @@ class DisplayMono128X64 : public DisplayMono { mExtra = 0; } - void config(display_t *cfg) { + void config(display_t *cfg) override { mCfg = cfg; } - void init(DisplayData *displayData) { + void init(DisplayData *displayData) override { u8g2_cb_t *rot = (u8g2_cb_t *)(( mCfg->rot != 0x00) ? U8G2_R2 : U8G2_R0); switch (mCfg->type) { case DISP_TYPE_T1_SSD1306_128X64: @@ -68,9 +68,7 @@ class DisplayMono128X64 : public DisplayMono { mDisplay->sendBuffer(); } - void disp(void) { - uint8_t pos, sun_pos, moon_pos; - + void disp(void) override { mDisplay->clearBuffer(); // Layout-Test @@ -106,8 +104,8 @@ class DisplayMono128X64 : public DisplayMono { } // print status of inverters else { - sun_pos = -1; - moon_pos = -1; + int8_t sun_pos = -1; + int8_t moon_pos = -1; setLineFont(l_Status); if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); @@ -128,11 +126,11 @@ class DisplayMono128X64 : public DisplayMono { } printText(mFmtText, l_Status, 0xff); - pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; + uint8_t pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy); - if (sun_pos!=-1) + if (sun_pos != -1) mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun symbol - if (moon_pos!=-1) + if (moon_pos != -1) mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol } } @@ -181,12 +179,11 @@ class DisplayMono128X64 : public DisplayMono { // draw dynamic RSSI bars int rssi_bar_height = 9; for (int i = 0; i < 4; i++) { - int radio_rssi_threshold = -60 - i * 10; - int wifi_rssi_threshold = -60 - i * 10; + int rssi_threshold = -60 - i * 10; uint8_t barwidth = std::min(4 - i, 3); - if (mDisplayData->RadioRSSI > radio_rssi_threshold) + if (mDisplayData->RadioRSSI > rssi_threshold) mDisplay->drawBox(widthShrink / 2 + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); - if (mDisplayData->WifiRSSI > wifi_rssi_threshold) + if (mDisplayData->WifiRSSI > rssi_threshold) mDisplay->drawBox(mDispWidth - barwidth - widthShrink / 2 + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); } // draw dynamic antenna and WiFi symbols @@ -223,23 +220,22 @@ class DisplayMono128X64 : public DisplayMono { l_MAX_LINES = 5, }; - uint8_t graph_first_line; - uint8_t graph_last_line; + uint8_t graph_first_line = 0; + uint8_t graph_last_line = 0; const uint8_t pixelShiftRange = 11; // number of pixels to shift from left to right (centered -> must be odd!) - uint8_t widthShrink; + uint8_t widthShrink = 0; void calcLinePositions() { uint8_t yOff = 0; uint8_t i = 0; - uint8_t asc, dsc; do { setLineFont(i); - asc = mDisplay->getAscent(); + uint8_t asc = mDisplay->getAscent(); yOff += asc; mLineYOffsets[i] = yOff; - dsc = mDisplay->getDescent(); + uint8_t dsc = mDisplay->getDescent(); yOff -= dsc; if (l_Time == i) // prevent time and status line to touch yOff++; // -> one pixels space @@ -248,8 +244,7 @@ class DisplayMono128X64 : public DisplayMono { } inline void setLineFont(uint8_t line) { - if ((line == l_TotalPower) || - (line == l_Ahoy)) + if (line == l_TotalPower) // || (line == l_Ahoy) -> l_TotalPower == l_Ahoy == 2 mDisplay->setFont(u8g2_font_ncenB14_tr); else if ((line == l_YieldDay) || (line == l_YieldTotal)) diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 84e40126..7f98cae5 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -12,11 +12,11 @@ class DisplayMono64X48 : public DisplayMono { mExtra = 0; } - void config(display_t *cfg) { + void config(display_t *cfg) override { mCfg = cfg; } - void init(DisplayData *displayData) { + void init(DisplayData *displayData) override { u8g2_cb_t *rot = (u8g2_cb_t *)((mCfg->rot != 0x00) ? U8G2_R2 : U8G2_R0); // Wemos OLed Shield is not defined in u8 lib -> use nearest compatible monoInit(new U8G2_SSD1306_64X48_ER_F_HW_I2C(rot, 0xff, mCfg->disp_clk, mCfg->disp_data), displayData); @@ -28,7 +28,7 @@ class DisplayMono64X48 : public DisplayMono { mDisplay->sendBuffer(); } - void disp(void) { + void disp(void) override { mDisplay->clearBuffer(); // calculate current pixelshift for pixelshift screensaver diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index d3be1f31..b5daacd5 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -12,11 +12,11 @@ class DisplayMono84X48 : public DisplayMono { mExtra = 0; } - void config(display_t *cfg) { + void config(display_t *cfg) override { mCfg = cfg; } - void init(DisplayData *displayData) { + void init(DisplayData *displayData) override { u8g2_cb_t *rot = (u8g2_cb_t *)((mCfg->rot != 0x00) ? U8G2_R2 : U8G2_R0); monoInit(new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, mCfg->disp_clk, mCfg->disp_data, mCfg->disp_cs, mCfg->disp_dc, 0xff), displayData); @@ -55,7 +55,7 @@ class DisplayMono84X48 : public DisplayMono { mDisplay->sendBuffer(); } - void disp(void) { + void disp(void) override { mDisplay->clearBuffer(); // Layout-Test @@ -143,12 +143,11 @@ class DisplayMono84X48 : public DisplayMono { // draw dynamic RSSI bars int rssi_bar_height = 7; for (int i = 0; i < 4; i++) { - int radio_rssi_threshold = -60 - i * 10; - int wifi_rssi_threshold = -60 - i * 10; + int rssi_threshold = -60 - i * 10; uint8_t barwidth = std::min(4 - i, 3); - if (mDisplayData->RadioRSSI > radio_rssi_threshold) + if (mDisplayData->RadioRSSI > rssi_threshold) mDisplay->drawBox(0, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); - if (mDisplayData->WifiRSSI > wifi_rssi_threshold) + if (mDisplayData->WifiRSSI > rssi_threshold) mDisplay->drawBox(mDispWidth - barwidth, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); } @@ -184,30 +183,28 @@ class DisplayMono84X48 : public DisplayMono { l_MAX_LINES = 5, }; - uint8_t graph_first_line; - uint8_t graph_last_line; + uint8_t graph_first_line = 0; + uint8_t graph_last_line = 0; void calcLinePositions() { uint8_t yOff = 0; uint8_t i = 0; - uint8_t asc, dsc; do { setLineFont(i); - asc = mDisplay->getAscent(); + uint8_t asc = mDisplay->getAscent(); yOff += asc; mLineYOffsets[i] = yOff; - dsc = mDisplay->getDescent(); + uint8_t dsc = mDisplay->getDescent(); if (l_TotalPower != i) // power line needs no descent spacing yOff -= dsc; yOff++; // instead lets spend one pixel space between all lines i++; - } while(l_MAX_LINES>i); + } while(l_MAX_LINES > i); } inline void setLineFont(uint8_t line) { - if ((line == l_TotalPower) || - (line == l_Ahoy)) + if (line == l_TotalPower) // || (line == l_Ahoy) -> l_TotalPower == l_Ahoy == 2 mDisplay->setFont(u8g2_font_logisoso16_tr); else mDisplay->setFont(u8g2_font_5x8_symbols_ahoy); diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index fdcec767..087d784b 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -67,7 +67,7 @@ void DisplayEPaper::refreshLoop() { case RefreshStatus::LOGO: _display->fillScreen(GxEPD_BLACK); _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); - _display->display(false); // full update + mSecondCnt = 2; mNextRefreshState = RefreshStatus::PARTITIALS; mRefreshState = RefreshStatus::WAIT; break; @@ -79,11 +79,11 @@ void DisplayEPaper::refreshLoop() { break; case RefreshStatus::WHITE: - if(mSecondCnt == 0) { - _display->fillScreen(GxEPD_WHITE); - mNextRefreshState = RefreshStatus::PARTITIALS; - mRefreshState = RefreshStatus::WAIT; - } + if(0 != mSecondCnt) + break; + _display->fillScreen(GxEPD_WHITE); + mNextRefreshState = RefreshStatus::PARTITIALS; + mRefreshState = RefreshStatus::WAIT; break; case RefreshStatus::WAIT: @@ -92,10 +92,13 @@ void DisplayEPaper::refreshLoop() { break; case RefreshStatus::PARTITIALS: + if(0 != mSecondCnt) + break; headlineIP(); versionFooter(); mSecondCnt = 4; // display Logo time during boot up - mRefreshState = RefreshStatus::DONE; + mNextRefreshState = RefreshStatus::DONE; + mRefreshState = RefreshStatus::WAIT; break; default: // RefreshStatus::DONE diff --git a/src/plugins/history.h b/src/plugins/history.h index 7e415675..5076e295 100644 --- a/src/plugins/history.h +++ b/src/plugins/history.h @@ -47,14 +47,13 @@ class HistoryData { } void tickerSecond() { - Inverter<> *iv; - record_t<> *rec; + ; float curPwr = 0; float maxPwr = 0; float yldDay = -0.1; for (uint8_t i = 0; i < mSys->getNumInverters(); i++) { - iv = mSys->getInverterByPos(i); - rec = iv->getRecordStruct(RealTimeRunData_Debug); + Inverter<> *iv = mSys->getInverterByPos(i); + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); if (iv == NULL) continue; curPwr += iv->getChannelFieldValue(CH0, FLD_PAC, rec); diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 0e10e688..1b9e35ef 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -38,7 +38,7 @@ typedef struct { template class PubMqtt { public: - PubMqtt() { + PubMqtt() : SendIvData() { mLastIvState.fill(InverterStatus::OFF); mIvLastRTRpub.fill(0); @@ -61,21 +61,21 @@ class PubMqtt { mUptime = uptime; mIntervalTimeout = 1; - mSendIvData.setup(sys, utcTs, &mSendList); - mSendIvData.setPublishFunc([this](const char *subTopic, const char *payload, bool retained, uint8_t qos) { + SendIvData.setup(sys, utcTs, &mSendList); + SendIvData.setPublishFunc([this](const char *subTopic, const char *payload, bool retained, uint8_t qos) { publish(subTopic, payload, retained, true, qos); }); mDiscovery.running = false; - snprintf(mLwtTopic.data(), mLwtTopic.size() - 1, "%s/mqtt", mCfgMqtt->topic); + snprintf(mLwtTopic.data(), mLwtTopic.size(), "%s/mqtt", mCfgMqtt->topic); if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0)) mClient.setCredentials(mCfgMqtt->user, mCfgMqtt->pwd); if(strlen(mCfgMqtt->clientId) > 0) - snprintf(mClientId.data(), mClientId.size() - 1, "%s", mCfgMqtt->clientId); + snprintf(mClientId.data(), mClientId.size(), "%s", mCfgMqtt->clientId); else { - snprintf(mClientId.data(), mClientId.size() - 1, "%s-", mDevName); + snprintf(mClientId.data(), mClientId.size(), "%s-", mDevName); uint8_t pos = strlen(mClientId.data()); mClientId[pos++] = WiFi.macAddress().substring( 9, 10).c_str()[0]; mClientId[pos++] = WiFi.macAddress().substring(10, 11).c_str()[0]; @@ -95,7 +95,7 @@ class PubMqtt { } void loop() { - mSendIvData.loop(); + SendIvData.loop(); #if defined(ESP8266) mClient.loop(); @@ -129,7 +129,7 @@ class PubMqtt { } void tickerMinute() { - snprintf(mVal.data(), mVal.size() - 1, "%u", (*mUptime)); + snprintf(mVal.data(), mVal.size(), "%u", (*mUptime)); publish(subtopics[MQTT_UPTIME], mVal.data()); publish(subtopics[MQTT_RSSI], String(WiFi.RSSI()).c_str()); publish(subtopics[MQTT_FREE_HEAP], String(ESP.getFreeHeap()).c_str()); @@ -152,11 +152,11 @@ class PubMqtt { if(NULL == iv) continue; - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/dis_night_comm", iv->config->name); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/dis_night_comm", iv->config->name); publish(mSubTopic.data(), ((iv->commEnabled) ? dict[STR_TRUE] : dict[STR_FALSE]), true); } - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "comm_disabled"); + snprintf(mSubTopic.data(), mSubTopic.size(), "comm_disabled"); publish(mSubTopic.data(), (((*mUtcTimestamp > (sunset + offsE)) || (*mUtcTimestamp < (sunrise + offsM))) ? dict[STR_TRUE] : dict[STR_FALSE]), true); return true; @@ -164,7 +164,7 @@ class PubMqtt { void notAvailChanged(bool allNotAvail) { if(!allNotAvail) - mSendIvData.resetYieldDay(); + SendIvData.resetYieldDay(); } bool tickerComm(bool disabled) { @@ -179,8 +179,8 @@ class PubMqtt { void tickerMidnight() { // set Total YieldDay to zero - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "total/%s", fields[FLD_YD]); - snprintf(mVal.data(), mVal.size() - 1, "0"); + snprintf(mSubTopic.data(), mSubTopic.size(), "total/%s", fields[FLD_YD]); + snprintf(mVal.data(), mVal.size(), "0"); publish(mSubTopic.data(), mVal.data(), true); } @@ -200,9 +200,9 @@ class PubMqtt { return; if(addTopic) - snprintf(mTopic.data(), mTopic.size() - 1, "%s/%s", mCfgMqtt->topic, subTopic); + snprintf(mTopic.data(), mTopic.size(), "%s/%s", mCfgMqtt->topic, subTopic); else - snprintf(mTopic.data(), mTopic.size() - 1, "%s", subTopic); + snprintf(mTopic.data(), mTopic.size(), "%s", subTopic); mClient.publish(mTopic.data(), qos, retained, payload); yield(); @@ -241,7 +241,7 @@ class PubMqtt { void setPowerLimitAck(Inverter<> *iv) { if (NULL != iv) { - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); publish(mSubTopic.data(), "true", true, true, QOS_2); } } @@ -261,11 +261,11 @@ class PubMqtt { publish(mLwtTopic.data(), mqttStr[MQTT_STR_LWT_CONN], true, false); for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - snprintf(mVal.data(), mVal.size() - 1, "ctrl/limit/%d", i); + snprintf(mVal.data(), mVal.size(), "ctrl/limit/%d", i); subscribe(mVal.data(), QOS_2); - snprintf(mVal.data(), mVal.size() - 1, "ctrl/restart/%d", i); + snprintf(mVal.data(), mVal.size(), "ctrl/restart/%d", i); subscribe(mVal.data()); - snprintf(mVal.data(), mVal.size() - 1, "ctrl/power/%d", i); + snprintf(mVal.data(), mVal.size(), "ctrl/power/%d", i); subscribe(mVal.data()); } subscribe(subscr[MQTT_SUBS_SET_TIME]); @@ -400,20 +400,20 @@ class PubMqtt { const char *devCls, *stateCls; if (!total) { if (rec->assign[mDiscovery.sub].ch == CH0) - snprintf(name.data(), name.size() - 1, "%s", iv->getFieldName(mDiscovery.sub, rec)); + snprintf(name.data(), name.size(), "%s", iv->getFieldName(mDiscovery.sub, rec)); else - snprintf(name.data(), name.size() - 1, "CH%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); - snprintf(topic.data(), name.size() - 1, "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); - snprintf(uniq_id.data(), uniq_id.size() - 1, "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(name.data(), name.size(), "CH%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(topic.data(), name.size(), "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(uniq_id.data(), uniq_id.size(), "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); devCls = getFieldDeviceClass(rec->assign[mDiscovery.sub].fieldId); stateCls = getFieldStateClass(rec->assign[mDiscovery.sub].fieldId); } else { // total values - snprintf(name.data(), name.size() - 1, "Total %s", fields[fldTotal[mDiscovery.sub]]); - snprintf(topic.data(), topic.size() - 1, "/%s", fields[fldTotal[mDiscovery.sub]]); - snprintf(uniq_id.data(), uniq_id.size() - 1, "total_%s", fields[fldTotal[mDiscovery.sub]]); + snprintf(name.data(), name.size(), "Total %s", fields[fldTotal[mDiscovery.sub]]); + snprintf(topic.data(), topic.size(), "/%s", fields[fldTotal[mDiscovery.sub]]); + snprintf(uniq_id.data(), uniq_id.size(), "total_%s", fields[fldTotal[mDiscovery.sub]]); devCls = getFieldDeviceClass(fldTotal[mDiscovery.sub]); stateCls = getFieldStateClass(fldTotal[mDiscovery.sub]); } @@ -433,9 +433,9 @@ class PubMqtt { doc2[F("stat_cla")] = String(stateCls); if (!total) - snprintf(topic.data(), topic.size() - 1, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(topic.data(), topic.size(), "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); else // total values - snprintf(topic.data(), topic.size() - 1, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); + snprintf(topic.data(), topic.size(), "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); size_t size = measureJson(doc2) + 1; buf.fill(0); serializeJson(doc2, buf.data(), size); @@ -509,14 +509,14 @@ class PubMqtt { mLastIvState[id] = status; changed = true; - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/available", iv->config->name); - snprintf(mVal.data(), mVal.size() - 1, "%d", (uint8_t)status); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/available", iv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", (uint8_t)status); publish(mSubTopic.data(), mVal.data(), true); } } if(changed) { - snprintf(mVal.data(), mVal.size() - 1, "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); + snprintf(mVal.data(), mVal.size(), "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); publish("status", mVal.data(), true); } @@ -539,14 +539,14 @@ class PubMqtt { mSendAlarm[i] = false; - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/alarm/cnt", iv->config->name); - snprintf(mVal.data(), mVal.size() - 1, "%d", iv->alarmCnt); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/alarm/cnt", iv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", iv->alarmCnt); publish(mSubTopic.data(), mVal.data(), false); for(uint8_t j = 0; j < 10; j++) { if(0 != iv->lastAlarm[j].code) { - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/alarm/%d", iv->config->name, j); - snprintf(mVal.data(), mVal.size() - 1, "{\"code\":%d,\"str\":\"%s\",\"start\":%d,\"end\":%d}", + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/alarm/%d", iv->config->name, j); + snprintf(mVal.data(), mVal.size(), "{\"code\":%d,\"str\":\"%s\",\"start\":%d,\"end\":%d}", iv->lastAlarm[j].code, iv->getAlarmStr(iv->lastAlarm[j].code).c_str(), iv->lastAlarm[j].start + lastMidnight, @@ -581,8 +581,8 @@ class PubMqtt { } } - snprintf(mSubTopic.data(), mSubTopic.size() - 1, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); - snprintf(mVal.data(), mVal.size() - 1, "%g", ah::round3(iv->getValue(i, rec))); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); + snprintf(mVal.data(), mVal.size(), "%g", ah::round3(iv->getValue(i, rec))); publish(mSubTopic.data(), mVal.data(), retained); yield(); @@ -598,7 +598,7 @@ class PubMqtt { if(mSendList.empty()) return; - mSendIvData.start(); + SendIvData.start(); mLastAnyAvail = anyAvail; } @@ -609,7 +609,7 @@ class PubMqtt { #endif HMSYSTEM *mSys = nullptr; - PubMqttIvData mSendIvData; + PubMqttIvData SendIvData; uint32_t *mUtcTimestamp = nullptr, *mUptime = nullptr; uint32_t mRxCnt = 0, mTxCnt = 0; diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 4405d037..5f38768d 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -1,4 +1,4 @@ -//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- // 2024 Ahoy, https://ahoydtu.de // Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -21,6 +21,8 @@ struct sendListCmdIv { template class PubMqttIvData { public: + PubMqttIvData() : mTotal{}, mSubTopic{}, mVal{} {} + void setup(HMSYSTEM *sys, uint32_t *utcTs, std::queue *sendList) { mSys = sys; mUtcTimestamp = utcTs; @@ -249,25 +251,25 @@ class PubMqttIvData { } } - HMSYSTEM *mSys; - uint32_t *mUtcTimestamp; + HMSYSTEM *mSys = nullptr; + uint32_t *mUtcTimestamp = nullptr; pubMqttPublisherType mPublish; - State mState; + State mState = IDLE; StateFunction mTable[NUM_STATES]; - uint8_t mCmd; - uint8_t mLastIvId; - bool mSendTotals, mTotalFound, mAllTotalFound, mSendTotalYd; - float mTotal[5], mYldTotalStore; + uint8_t mCmd = 0; + uint8_t mLastIvId = 0; + bool mSendTotals = false, mTotalFound = false, mAllTotalFound = false, mSendTotalYd = false; + float mTotal[5], mYldTotalStore = 0; - Inverter<> *mIv, *mIvSend; - uint8_t mPos; - bool mRTRDataHasBeenSent; + Inverter<> *mIv = nullptr, *mIvSend = nullptr; + uint8_t mPos = 0; + bool mRTRDataHasBeenSent = false; char mSubTopic[32 + MAX_NAME_LENGTH + 1]; char mVal[140]; - std::queue *mSendList; + std::queue *mSendList = nullptr; }; #endif /*__PUB_MQTT_IV_DATA_H__*/ diff --git a/src/utils/improv.h b/src/utils/improv.h index 32bc403c..20b2bcad 100644 --- a/src/utils/improv.h +++ b/src/utils/improv.h @@ -71,7 +71,7 @@ class Improv { TYPE_RPC_RESPONSE = 0x04 }; - void dumpBuf(uint8_t buf[], uint8_t len) { + void dumpBuf(const uint8_t buf[], uint8_t len) { for(uint8_t i = 0; i < len; i++) { DHEX(buf[i]); DBGPRINT(F(" ")); diff --git a/src/utils/syslog.cpp b/src/utils/syslog.cpp index 9c4bf93b..c251e899 100644 --- a/src/utils/syslog.cpp +++ b/src/utils/syslog.cpp @@ -10,6 +10,7 @@ #define SYSLOG_MAX_PACKET_SIZE 256 +DbgSyslog::DbgSyslog() : mSyslogBuffer{} {} //----------------------------------------------------------------------------- void DbgSyslog::setup(settings_t *config) { diff --git a/src/utils/syslog.h b/src/utils/syslog.h index 37bdc524..ec7f4f6e 100644 --- a/src/utils/syslog.h +++ b/src/utils/syslog.h @@ -36,6 +36,7 @@ class DbgSyslog { public: + DbgSyslog(); void setup (settings_t *config); void syslogCb(String msg); void log(const char *hostname, uint8_t facility, uint8_t severity, char* msg); @@ -43,7 +44,7 @@ class DbgSyslog { private: WiFiUDP mSyslogUdp; IPAddress mSyslogIP; - settings_t *mConfig; + settings_t *mConfig = nullptr; char mSyslogBuffer[SYSLOG_BUF_SIZE+1]; uint16_t mSyslogBufFill = 0; int mSyslogSeverity = PRI_NOTICE; @@ -51,4 +52,4 @@ class DbgSyslog { #endif /*ENABLE_SYSLOG*/ -#endif /*__SYSLOG_H__*/ \ No newline at end of file +#endif /*__SYSLOG_H__*/ diff --git a/src/web/Protection.h b/src/web/Protection.h index 0c7b8379..6b079e82 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -15,7 +15,7 @@ class Protection { protected: - Protection(const char *pwd) { + explicit Protection(const char *pwd) { mPwd = pwd; mLogoutTimeout = 0; mLoginIp.fill(0); diff --git a/src/web/web.h b/src/web/web.h index c40c817c..a85e4b0a 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -684,7 +684,6 @@ class Web { char type[60], topic[100], val[25]; size_t len = 0; int alarmChannelId; - int metricsChannelId; // Perform grouping on metrics according to format specification // Each step must return at least one character. Otherwise the processing of AsyncWebServerResponse stops. @@ -766,7 +765,7 @@ class Web { iv = mSys->getInverterByPos(metricsInverterId); if (NULL != iv) { rec = iv->getRecordStruct(RealTimeRunData_Debug); - for (metricsChannelId=0; metricsChannelId < rec->length;metricsChannelId++) { + for (int metricsChannelId=0; metricsChannelId < rec->length;metricsChannelId++) { uint8_t channel = rec->assign[metricsChannelId].ch; // Try inverter channel (channel 0) or any channel with maxPwr > 0 @@ -786,14 +785,14 @@ class Web { char total[7]; if (metricDeclared) { // A declaration and value for channels have been delivered. So declare and deliver a _total metric - snprintf(total, sizeof(total)-1, "_total"); + snprintf(total, sizeof(total), "_total"); } if (!metricTotalDeclard) { - snprintf(type, sizeof(type)-1, "# TYPE %s%s%s%s %s\n",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str()); + snprintf(type, sizeof(type), "# TYPE %s%s%s%s %s\n",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str()); metrics += type; metricTotalDeclard = true; } - snprintf(topic, sizeof(topic)-1, "%s%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total,iv->config->name); + snprintf(topic, sizeof(topic), "%s%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total,iv->config->name); } else { // Report (non zero) channel value // Use a fallback channel name (ch0, ch1, ...)if non is given by user @@ -801,11 +800,11 @@ class Web { if (iv->config->chName[channel-1][0] != 0) { strncpy(chName, iv->config->chName[channel-1], sizeof(chName)); } else { - snprintf(chName,sizeof(chName)-1,"ch%1d",channel); + snprintf(chName,sizeof(chName),"ch%1d",channel); } - snprintf(topic, sizeof(topic)-1, "%s%s%s{inverter=\"%s\",channel=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,chName); + snprintf(topic, sizeof(topic), "%s%s%s{inverter=\"%s\",channel=\"%s\"}",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,chName); } - snprintf(val, sizeof(val)-1, " %.3f\n", iv->getValue(metricsChannelId, rec)); + snprintf(val, sizeof(val), " %.3f\n", iv->getValue(metricsChannelId, rec)); metrics += topic; metrics += val; } @@ -835,7 +834,7 @@ class Web { case metricsStateAlarmData: // Alarm Info loop : fit to one packet // Perform grouping on metrics according to Prometheus exposition format specification - snprintf(type, sizeof(type)-1,"# TYPE %s%s gauge\n",metricConstPrefix,fields[FLD_LAST_ALARM_CODE]); + snprintf(type, sizeof(type),"# TYPE %s%s gauge\n",metricConstPrefix,fields[FLD_LAST_ALARM_CODE]); metrics = type; for (metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) { @@ -847,8 +846,8 @@ class Web { alarmChannelId = 0; if (alarmChannelId < rec->length) { std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(alarmChannelId, rec)); - snprintf(topic, sizeof(topic)-1, "%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name); - snprintf(val, sizeof(val)-1, " %.3f\n", iv->getValue(alarmChannelId, rec)); + snprintf(topic, sizeof(topic), "%s%s%s{inverter=\"%s\"}",metricConstPrefix, iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name); + snprintf(val, sizeof(val), " %.3f\n", iv->getValue(alarmChannelId, rec)); metrics += topic; metrics += val; } @@ -874,8 +873,8 @@ class Web { // Traverse all inverters and collect the metric via valueFunc String inverterMetric(char *buffer, size_t len, const char *format, std::function *iv)> valueFunc) { String metric = ""; - for (int metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) { - Inverter<> *iv = mSys->getInverterByPos(metricsInverterId); + for (int id = 0; id < mSys->getNumInverters();id++) { + Inverter<> *iv = mSys->getInverterByPos(id); if (NULL != iv) { snprintf(buffer,len,format,iv->config->name, valueFunc(iv)); metric += String(buffer); From d4a4f9cfb6616135d7cdb8a1c6954aa44d102f44 Mon Sep 17 00:00:00 2001 From: tictrick <117273857+tictrick@users.noreply.github.com> Date: Thu, 8 Feb 2024 08:38:11 +0100 Subject: [PATCH 37/79] BugFix: ACK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Funktion startWrite() der RF24 Bibliothek ist ungeeignet für den Empfang von ACKs, da der Verstärker während des Sendens statt in den RX-Modus Ausgeschaltet wird. --- src/hm/hmRadio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index df6a18b4..09500826 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -415,7 +415,7 @@ class HmRadio : public Radio { } mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); - mNrf24->startWrite(mTxBuf.data(), len, false); // false = request ACK response + mNrf24->startFastWrite(mTxBuf.data(), len, false); // false = request ACK response mMillis = millis(); mLastIv = iv; From 15349520d26538cee0dba501ea69b54e7fe8a66f Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 9 Feb 2024 00:05:54 +0100 Subject: [PATCH 38/79] 0.8.77 * merge PR: BugFix: ACK #1414 * fix suspicious if condition #1416 * prepared API token for access, not functional #1415 --- src/CHANGES.md | 5 ++++ src/app.cpp | 2 +- src/app.h | 8 +++++-- src/appInterface.h | 3 ++- src/defines.h | 2 +- src/web/Protection.h | 34 ++++++++++++++++++++++++--- src/web/RestApi.h | 55 ++++++++++++++++++++++++++++++++++---------- src/web/lang.h | 10 ++++++-- src/web/web.h | 2 +- 9 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index a9301d44..b75ba2b3 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.77 - 2024-02-08 +* merge PR: BugFix: ACK #1414 +* fix suspicious if condition #1416 +* prepared API token for access, not functional #1415 + ## 0.8.76 - 2024-02-07 * revert changes from yesterday regarding snprintf and its size #1410, #1411 * reduced cppcheck linter warnings significantly diff --git a/src/app.cpp b/src/app.cpp index c93be777..bee12387 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -239,7 +239,7 @@ void app::updateNtp(void) { } } - if ((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) { + if ((0 == mSunrise) && (0.0 != mConfig->sun.lat) && (0.0 != mConfig->sun.lon)) { mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600; tickCalcSunrise(); } diff --git a/src/app.h b/src/app.h index 60be4d1d..be20f26f 100644 --- a/src/app.h +++ b/src/app.h @@ -251,8 +251,8 @@ class app : public IApp, public ah::Scheduler { mProtection->lock(); } - void unlock(const char *clientIp) override { - mProtection->unlock(clientIp); + char *unlock(const char *clientIp) override { + return mProtection->unlock(clientIp); } void resetLockTimeout(void) override { @@ -267,6 +267,10 @@ class app : public IApp, public ah::Scheduler { return mProtection->isProtected(clientIp); } + bool isProtected(const char *clientIp, const char *token) const override { + return mProtection->isProtected(clientIp, token); + } + bool getNrfEnabled(void) override { return mConfig->nrf.enabled; } diff --git a/src/appInterface.h b/src/appInterface.h index 6703b5bf..937908e2 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -62,10 +62,11 @@ class IApp { virtual uint32_t getMqttTxCnt() = 0; virtual void lock(void) = 0; - virtual void unlock(const char *clientIp) = 0; + virtual char *unlock(const char *clientIp) = 0; virtual void resetLockTimeout(void) = 0; virtual bool isProtected(void) const = 0; virtual bool isProtected(const char *clientIp) const = 0; + virtual bool isProtected(const char *clientIp, const char *token) const = 0; virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0; virtual uint16_t getHistoryMaxDay() = 0; diff --git a/src/defines.h b/src/defines.h index 9ea3834c..46be8dac 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 76 +#define VERSION_PATCH 77 //------------------------------------- typedef struct { diff --git a/src/web/Protection.h b/src/web/Protection.h index 6b079e82..f62f1380 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -19,6 +19,7 @@ class Protection { mPwd = pwd; mLogoutTimeout = 0; mLoginIp.fill(0); + mToken.fill(0); // no password set - unlock if(pwd[0] == '\0') @@ -50,20 +51,34 @@ class Protection { mLoginIp.fill(0); } - void unlock(const char *clientIp) { + char *unlock(const char *clientIp) { mLogoutTimeout = LOGOUT_TIMEOUT; mProtected = false; ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); + genToken(); + + return reinterpret_cast(mToken.data()); } void resetLockTimeout(void) { - mLogoutTimeout = LOGOUT_TIMEOUT; + if(0 != mLogoutTimeout) + mLogoutTimeout = LOGOUT_TIMEOUT; } bool isProtected(void) const { return mProtected; } + bool isProtected(const char *clientIp, const char *token) const { + if(isProtected(clientIp)) + return true; + + if(0 == mToken[0]) // token is zero + return true; + + return (0 != strncmp(token, mToken.data(), 16)); + } + bool isProtected(const char *clientIp) const { if(mProtected) return true; @@ -81,14 +96,27 @@ class Protection { return false; } + private: + void genToken() { + mToken.fill(0); + for(uint8_t i = 0; i < 16; i++) { + mToken[i] = random(1, 35); + if(mToken[i] < 10) + mToken[i] += 0x30; // convert to ascii number 1-9 (zero isn't allowed) + else + mToken[i] += 0x37; // convert to ascii upper case character + } + } + protected: static Protection *mInstance; private: const char *mPwd; bool mProtected = true; - uint16_t mLogoutTimeout = LOGOUT_TIMEOUT; + uint16_t mLogoutTimeout = 0; std::array mLoginIp; + std::array mToken; }; #endif /*__PROTECTION_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index ce580dd5..59b786d7 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -70,7 +70,7 @@ class RestApi { if(obj[F("path")] == "ctrl") setCtrl(obj, dummy, "*"); else if(obj[F("path")] == "setup") - setSetup(obj, dummy); + setSetup(obj, dummy, "*"); } private: @@ -169,7 +169,7 @@ class RestApi { if(path == "ctrl") root[F("success")] = setCtrl(obj, root, request->client()->remoteIP().toString().c_str()); else if(path == "setup") - root[F("success")] = setSetup(obj, root); + root[F("success")] = setSetup(obj, root, request->client()->remoteIP().toString().c_str()); else { root[F("success")] = false; root[F("error")] = F(PATH_NOT_FOUND) + path; @@ -831,23 +831,44 @@ class RestApi { } bool setCtrl(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { - Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); - bool accepted = true; - if(NULL == iv) { - jsonOut[F("error")] = F(INV_INDEX_INVALID) + jsonIn[F("id")].as(); - return false; + if(F("auth") == jsonIn[F("cmd")]) { + if(String(jsonIn["val"]) == String(mConfig->sys.adminPwd)) + jsonOut["token"] = mApp->unlock(clientIP); + else { + jsonOut[F("error")] = F(AUTH_ERROR); + return false; + } + return true; } - jsonOut[F("id")] = jsonIn[F("id")]; - if(mConfig->sys.adminPwd[0] != '\0') { - if(strncmp("*", clientIP, 1) != 0) { // no call from API (MqTT) + /*if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set + if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT + const char* token = jsonIn["token"]; + if(mApp->isProtected(clientIP, token)) { + jsonOut[F("error")] = F(IS_PROTECTED); + jsonOut[F("bla")] = String(token); + return false; + } + } + }*/ + + if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set + if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT if(mApp->isProtected(clientIP)) { - jsonOut[F("error")] = F(INV_IS_PROTECTED); + jsonOut[F("error")] = F(IS_PROTECTED); return false; } } } + Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); + bool accepted = true; + if(NULL == iv) { + jsonOut[F("error")] = F(INV_INDEX_INVALID) + jsonIn[F("id")].as(); + return false; + } + jsonOut[F("id")] = jsonIn[F("id")]; + if(F("power") == jsonIn[F("cmd")]) accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff); else if(F("restart") == jsonIn[F("cmd")]) @@ -882,7 +903,17 @@ class RestApi { return true; } - bool setSetup(JsonObject jsonIn, JsonObject jsonOut) { + bool setSetup(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { + /*if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set + if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT + const char* token = jsonIn["token"]; + if(mApp->isProtected(clientIP, token)) { + jsonOut[F("error")] = F(IS_PROTECTED); + return false; + } + } + }*/ + #if !defined(ETHERNET) if(F("scan_wifi") == jsonIn[F("cmd")]) mApp->scanAvailNetworks(); diff --git a/src/web/lang.h b/src/web/lang.h index 6cddbc12..1e066928 100644 --- a/src/web/lang.h +++ b/src/web/lang.h @@ -30,6 +30,12 @@ #define INV_INDEX_INVALID "inverter index invalid: " #endif +#ifdef LANG_DE + #define AUTH_ERROR "Authentifizierungsfehler" +#else /*LANG_EN*/ + #define AUTH_ERROR "authentication error" +#endif + #ifdef LANG_DE #define UNKNOWN_CMD "unbekanntes Kommando: '" #else /*LANG_EN*/ @@ -37,9 +43,9 @@ #endif #ifdef LANG_DE - #define INV_IS_PROTECTED "nicht angemeldet, Kommando nicht möglich!" + #define IS_PROTECTED "nicht angemeldet, Kommando nicht möglich!" #else /*LANG_EN*/ - #define INV_IS_PROTECTED "not logged in, command not possible!" + #define IS_PROTECTED "not logged in, command not possible!" #endif #ifdef LANG_DE diff --git a/src/web/web.h b/src/web/web.h index a85e4b0a..76503f0b 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -782,7 +782,7 @@ class Web { // report value if (0 == channel) { // Report a _total value if also channel values were reported. Otherwise report without _total - char total[7]; + char total[7] = {0}; if (metricDeclared) { // A declaration and value for channels have been delivered. So declare and deliver a _total metric snprintf(total, sizeof(total), "_total"); From 8b2db4abfa24a9a6d596661860a4bd9dd3e52502 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 9 Feb 2024 00:25:25 +0100 Subject: [PATCH 39/79] 0.8.78 * try to finalize API token protection --- src/CHANGES.md | 3 +++ src/app.h | 12 ++++-------- src/appInterface.h | 5 ++--- src/web/Protection.h | 40 +++++++++++++++++++++------------------- src/web/RestApi.h | 24 +++++++----------------- src/web/web.h | 4 ++-- 6 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index b75ba2b3..ea067bd2 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.78 - 2024-02-09 +* finalized API token access #1415 + ## 0.8.77 - 2024-02-08 * merge PR: BugFix: ACK #1414 * fix suspicious if condition #1416 diff --git a/src/app.h b/src/app.h index be20f26f..1a4e780d 100644 --- a/src/app.h +++ b/src/app.h @@ -251,8 +251,8 @@ class app : public IApp, public ah::Scheduler { mProtection->lock(); } - char *unlock(const char *clientIp) override { - return mProtection->unlock(clientIp); + char *unlock(const char *clientIp, bool loginFromWeb) override { + return mProtection->unlock(clientIp, loginFromWeb); } void resetLockTimeout(void) override { @@ -263,12 +263,8 @@ class app : public IApp, public ah::Scheduler { return mProtection->isProtected(); } - bool isProtected(const char *clientIp) const override { - return mProtection->isProtected(clientIp); - } - - bool isProtected(const char *clientIp, const char *token) const override { - return mProtection->isProtected(clientIp, token); + bool isProtected(const char *token, bool askedFromWeb) const override { + return mProtection->isProtected(token, askedFromWeb); } bool getNrfEnabled(void) override { diff --git a/src/appInterface.h b/src/appInterface.h index 937908e2..f0d2b2a0 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -62,11 +62,10 @@ class IApp { virtual uint32_t getMqttTxCnt() = 0; virtual void lock(void) = 0; - virtual char *unlock(const char *clientIp) = 0; + virtual char *unlock(const char *clientIp, bool loginFromWeb) = 0; virtual void resetLockTimeout(void) = 0; virtual bool isProtected(void) const = 0; - virtual bool isProtected(const char *clientIp) const = 0; - virtual bool isProtected(const char *clientIp, const char *token) const = 0; + virtual bool isProtected(const char *token, bool askedFromWeb) const = 0; virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0; virtual uint16_t getHistoryMaxDay() = 0; diff --git a/src/web/Protection.h b/src/web/Protection.h index f62f1380..b9eeef95 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -40,8 +40,9 @@ class Protection { // auto logout if(0 != mLogoutTimeout) { if (0 == --mLogoutTimeout) { - if(mPwd[0] != '\0') + if(mPwd[0] != '\0') { mProtected = true; + } } } } @@ -49,13 +50,17 @@ class Protection { void lock(void) { mProtected = true; mLoginIp.fill(0); + mToken.fill(0); } - char *unlock(const char *clientIp) { + char *unlock(const char *clientIp, bool loginFromWeb) { mLogoutTimeout = LOGOUT_TIMEOUT; mProtected = false; - ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); - genToken(); + + if(loginFromWeb) + ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); + else + genToken(); return reinterpret_cast(mToken.data()); } @@ -69,28 +74,25 @@ class Protection { return mProtected; } - bool isProtected(const char *clientIp, const char *token) const { - if(isProtected(clientIp)) - return true; - - if(0 == mToken[0]) // token is zero - return true; - - return (0 != strncmp(token, mToken.data(), 16)); - } - - bool isProtected(const char *clientIp) const { + bool isProtected(const char *token, bool askedFromWeb) const { // token == clientIp if(mProtected) return true; if(mPwd[0] == '\0') return false; - std::array ip; - ah::ip2Arr(static_cast(ip.data()), clientIp); - for(uint8_t i = 0; i < 4; i++) { - if(mLoginIp[i] != ip[i]) + if(askedFromWeb) { // check IP address + std::array ip; + ah::ip2Arr(static_cast(ip.data()), token); + for(uint8_t i = 0; i < 4; i++) { + if(mLoginIp[i] != ip[i]) + return true; + } + } else { // API call - check token + if(0 == mToken[0]) // token is zero return true; + + return (0 != strncmp(token, mToken.data(), 16)); } return false; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 59b786d7..5103f3ba 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -266,7 +266,7 @@ class RestApi { obj[F("modules")] = String(mApp->getVersionModules()); obj[F("build")] = String(AUTO_GIT_HASH); obj[F("env")] = String(ENV_NAME); - obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str()); + obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str(), true); obj[F("menu_mask")] = (uint16_t)(mConfig->sys.protectionMask ); obj[F("menu_protEn")] = (bool) (mConfig->sys.adminPwd[0] != '\0'); obj[F("cst_lnk")] = String(mConfig->plugin.customLink); @@ -833,7 +833,7 @@ class RestApi { bool setCtrl(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { if(F("auth") == jsonIn[F("cmd")]) { if(String(jsonIn["val"]) == String(mConfig->sys.adminPwd)) - jsonOut["token"] = mApp->unlock(clientIP); + jsonOut["token"] = mApp->unlock(clientIP, false); else { jsonOut[F("error")] = F(AUTH_ERROR); return false; @@ -841,20 +841,10 @@ class RestApi { return true; } - /*if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set - if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT - const char* token = jsonIn["token"]; - if(mApp->isProtected(clientIP, token)) { - jsonOut[F("error")] = F(IS_PROTECTED); - jsonOut[F("bla")] = String(token); - return false; - } - } - }*/ - if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT - if(mApp->isProtected(clientIP)) { + const char* token = jsonIn["token"]; + if(mApp->isProtected(token, false)) { jsonOut[F("error")] = F(IS_PROTECTED); return false; } @@ -904,15 +894,15 @@ class RestApi { } bool setSetup(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { - /*if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set + if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT const char* token = jsonIn["token"]; - if(mApp->isProtected(clientIP, token)) { + if(mApp->isProtected(token, false)) { jsonOut[F("error")] = F(IS_PROTECTED); return false; } } - }*/ + } #if !defined(ETHERNET) if(F("scan_wifi") == jsonIn[F("cmd")]) diff --git a/src/web/web.h b/src/web/web.h index 76503f0b..7ed41f92 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -227,7 +227,7 @@ class Web { } void checkProtection(AsyncWebServerRequest *request) { - if(mApp->isProtected(request->client()->remoteIP().toString().c_str())) { + if(mApp->isProtected(request->client()->remoteIP().toString().c_str(), true)) { checkRedirect(request); return; } @@ -314,7 +314,7 @@ class Web { if (request->args() > 0) { if (String(request->arg("pwd")) == String(mConfig->sys.adminPwd)) { - mApp->unlock(request->client()->remoteIP().toString().c_str()); + mApp->unlock(request->client()->remoteIP().toString().c_str(), true); request->redirect("/"); } } From d15e75dbabe222f206bf16b6d29b5f3d1e27c1aa Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 9 Feb 2024 11:53:20 +0100 Subject: [PATCH 40/79] simplify rxOffset logic - Code cleanup - fix "nRF CE keep high" code (missing argument) --- src/hm/Communication.h | 91 +++++++++++++++++++++--------------------- src/hm/hmDefines.h | 2 +- src/hm/hmInverter.h | 1 - src/hm/hmRadio.h | 42 ++++--------------- src/hm/hmSystem.h | 10 +---- 5 files changed, 55 insertions(+), 91 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 21b78405..a37bcdb2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -13,7 +13,7 @@ #include "../utils/timemonitor.h" #include "Heuristic.h" -#define MAX_BUFFER 250 +#define MAX_BUFFER 200 typedef std::function *)> payloadListenerType; typedef std::function *)> powerLimitAckListenerType; @@ -92,6 +92,8 @@ class Communication : public CommQueue<> { q->iv->mIsSingleframeReq = false; mFramesExpected = getFramesExpected(q); // function to get expected frame count. mTimeout = DURATION_TXFRAME + mFramesExpected*DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]; + if((q->iv->ivGen == IV_MI) && ((q->cmd == MI_REQ_CH1) || (q->cmd == MI_REQ_4CH))) + incrAttempt(q->iv->channels); // 2 more attempts for 2ch, 4 more for 4ch mState = States::START; break; @@ -209,7 +211,7 @@ class Communication : public CommQueue<> { } else { if(q->iv->miMultiParts < 6) { mState = States::WAIT; - if((q->iv->radio->mRadioWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { + if(q->iv->radio->mRadioWaitTime.isTimeout() && q->attempts) { miRepeatRequest(q); return; } @@ -220,6 +222,10 @@ class Communication : public CommQueue<> { || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); } + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("Payload (MI got all)")); + } closeRequest(q, true); } } @@ -443,9 +449,8 @@ class Communication : public CommQueue<> { || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) && (p->packet[0] < (0x39 + SINGLE_FRAME)) - )) { //&& (p->packet[0] != (0x0f + ALL_FRAMES)))) { + )) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 - //mPayload[iv->id].txId = p->packet[0]; miDataDecode(p, q); } else if (p->packet[0] == (0x0f + ALL_FRAMES)) { miHwDecode(p, q); @@ -541,14 +546,16 @@ class Communication : public CommQueue<> { len -= 2; - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("Payload (")); - DBGPRINT(String(len)); - if(*mPrintWholeTrace) { - DBGPRINT(F("): ")); - ah::dumpBuf(mPayload.data(), len); - } else - DBGPRINTLN(F(")")); + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("Payload (")); + DBGPRINT(String(len)); + if(*mPrintWholeTrace) { + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload.data(), len); + } else + DBGPRINTLN(F(")")); + } if(GridOnProFilePara == q->cmd) { q->iv->addGridProfile(mPayload.data(), len); @@ -813,35 +820,21 @@ class Communication : public CommQueue<> { miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - mHeu.evalTxChQuality(q->iv, true, (q->attemptsMax - 1 - q->attempts), 1); miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); } else { q->iv->miMultiParts = 7; // indicate we are ready } } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { - //addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); - mHeu.evalTxChQuality(q->iv, true, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); - q->iv->mIvRxCnt++; // statistics workaround... + q->iv->mIvRxCnt++; // statistics workaround... - } else { // first data msg for 1ch, 2nd for 2ch + } else // first data msg for 1ch, 2nd for 2ch q->iv->miMultiParts += 6; // indicate we are ready - - } } void miNextRequest(uint8_t cmd, const queue_s *q) { - incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... - if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("next request (")); - DBGPRINT(String(q->attempts)); - DBGPRINT(F(" attempts left): 0x")); - DBGHEXLN(cmd); - } - - /*if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7) - q->iv->radioStatistics.rxSuccess++;*/ + mHeu.evalTxChQuality(q->iv, true, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); + mHeu.getTxCh(q->iv); q->iv->radioStatistics.ivSent++; mFramesExpected = getFramesExpected(q); @@ -851,6 +844,13 @@ class Communication : public CommQueue<> { q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("next: (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(cmd); + } mIsRetransmit = true; chgCmd(cmd); //mState = States::WAIT; @@ -858,19 +858,17 @@ class Communication : public CommQueue<> { void miRepeatRequest(const queue_s *q) { setAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... + q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); + q->iv->radioStatistics.retransmits++; + q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); + DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("resend request (")); DBGPRINT(String(q->attempts)); DBGPRINT(F(" attempts left): 0x")); DBGHEXLN(q->cmd); } - - q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - q->iv->radioStatistics.retransmits++; - - q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); - mIsRetransmit = false; + //mIsRetransmit = false; } void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { @@ -953,11 +951,6 @@ class Communication : public CommQueue<> { void miComplete(Inverter<> *iv) { - if (*mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("got all data msgs")); - } - if (iv->mGetLossInterval >= AHOY_GET_LOSS_INTERVAL) { // initially mIvRxCnt = mIvTxCnt = 0 iv->mGetLossInterval = 1; iv->radioStatistics.ivSent = iv->mIvRxCnt + iv->mDtuTxCnt; // iv->mIvRxCnt is the nr. of additional answer frames, default we expect one frame per request @@ -966,10 +959,16 @@ class Communication : public CommQueue<> { iv->radioStatistics.dtuSent = iv->mDtuTxCnt; if (*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN("DTU loss: " + - String (iv->radioStatistics.ivLoss) + "/" + - String (iv->radioStatistics.ivSent) + " frames for " + - String (iv->radioStatistics.dtuSent) + " requests"); + DBGPRINT(F("DTU loss: ") + + String (iv->radioStatistics.ivLoss) + F("/") + + String (iv->radioStatistics.ivSent) + F(" frames for ") + + String (iv->radioStatistics.dtuSent) + F(" requests")); + if(iv->mAckCount) { + DBGPRINT(F(". ACKs: ")); + DBGPRINTLN(String(iv->mAckCount)); + iv->mAckCount = 0; + } else + DBGPRINTLN(F("")); } iv->mIvRxCnt = 0; // start new interval, iVRxCnt is abused to collect additional possible frames iv->mIvTxCnt = 0; // start new interval, iVTxCnt is abused to collect nr. of unanswered requests diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 8fc4f71f..6ba92774 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -89,7 +89,7 @@ const uint8_t duration_reserve[2] = {65, 115}; #define LIMIT_FAST_IV 85 // time limit to qualify an inverter as very fast answering inverter #define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter #define LIMIT_FAST_IV_MI 35 // time limit to qualify a MI type inverter as fast answering inverter -#define LIMIT_VERYFAST_IV_MI 22 // time limit to qualify a MI type inverter as very fast answering inverter +#define LIMIT_VERYFAST_IV_MI 25 // time limit to qualify a MI type inverter as very fast answering inverter #define RETRIES_FAST_IV 12 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter) #define RETRIES_VERYFAST_IV 9 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 51cb0d6d..b6dc93fa 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -132,7 +132,6 @@ class Inverter { record_t recordAlarm; // structure for alarm values InverterStatus status = InverterStatus::OFF; // indicates the current inverter status std::array lastAlarm; // holds last 10 alarms - uint8_t rxOffset = 0; // holds the default channel offset between tx and rx channel (nRF only) int8_t rssi = 0; // RSSI uint16_t alarmCnt = 0; // counts the total number of occurred alarms uint16_t alarmLastId = 0; // lastId which was received diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 09500826..b01df277 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -152,31 +152,22 @@ class HmRadio : public Radio { if(tx_ok) mLastIv->mAckCount++; - //#ifdef DYNAMIC_OFFSET - mRxChIdx = (mTxChIdx + mLastIv->rxOffset) % RF_CHANNELS; - /*#else - mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; - #endif*/ + rxOffset = mLastIv->ivGen == IV_HM ? 3 : 2; // holds the default channel offset between tx and rx channel (nRF only) + mRxChIdx = (mTxChIdx + rxOffset) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); tempRxChIdx = mRxChIdx; // might be better to start off with one channel less? mRxPendular = false; - mNRFloopChannels = (mLastIv->ivGen == IV_MI); - - //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; - //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; - //innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME; + mNRFloopChannels = (mLastIv->mCmd == MI_REQ_CH1 || mLastIv->mCmd == MI_REQ_CH1); innerLoopTimeout = DURATION_LISTEN_MIN; } if(rx_ready) { if (getReceived()) { // check what we got, returns true for last package or success for single frame request mNRFisInRX = false; - rx_ready = false; mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions mNrf24->stopListening(); - return false; } else { innerLoopTimeout = DURATION_LISTEN_MIN; mTimeslotStart = millis(); @@ -188,7 +179,6 @@ class HmRadio : public Radio { } else mRxChIdx = tempRxChIdx; } - return true; } rx_ready = false; // reset return mNRFisInRX; @@ -317,9 +307,11 @@ class HmRadio : public Radio { if (p.packet[0] != 0x00) { if(!checkIvSerial(p.packet, mLastIv)) { - DPRINT(DBG_WARN, "RX other inverter "); + DPRINT(DBG_WARN, F("RX other inverter ")); if(!*mPrivacyMode) ah::dumpBuf(p.packet, p.len); + else + DBGPRINTLN(F("")); } else { mLastIv->mGotFragment = true; mBufCtrl.push(p); @@ -331,14 +323,6 @@ class HmRadio : public Radio { if(isLastPackage) setExpectedFrames(p.packet[9] - ALL_FRAMES); - #ifdef DYNAMIC_OFFSET - if((p.packet[9] == 1) && (p.millis < DURATION_ONEFRAME)) - mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS; - else if(mNRFloopChannels && (mLastIv->rxOffset > RF_CHANNELS)) { // unsure setting? - mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset - mNRFloopChannels = false; - } - #endif } if(IV_MI == mLastIv->ivGen) { @@ -346,10 +330,6 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && isLastPackage = true; // response from dev control command - #ifdef DYNAMIC_OFFSET - if((p.packet[9] == 0x00) && (p.millis < DURATION_ONEFRAME)) - mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS; - #endif } rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads } @@ -385,14 +365,7 @@ class HmRadio : public Radio { DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(", ")); DBGPRINT(String(mTxRetriesNext)); - //DBGPRINT(F(" retries | ")); - //#ifdef DYNAMIC_OFFSET - DBGPRINT(F(" ret., rx offset: ")); - DBGPRINT(String(iv->rxOffset)); - DBGPRINT(F(" | ")); - /*#else DBGPRINT(F(" ret. | ")); - #endif*/ if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf.data(), len, 1, 4); @@ -415,7 +388,7 @@ class HmRadio : public Radio { } mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); - mNrf24->startFastWrite(mTxBuf.data(), len, false); // false = request ACK response + mNrf24->startFastWrite(mTxBuf.data(), len, false, true); // false (3) = request ACK response; true (4) reset CE to high after transmission mMillis = millis(); mLastIv = iv; @@ -455,6 +428,7 @@ class HmRadio : public Radio { bool mRxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); + uint8_t rxOffset = 3; // holds the channel offset between tx and rx channel used for actual inverter std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 22318347..7e79f30a 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -93,16 +93,8 @@ class HmSystem { DBGPRINTLN(String(iv->config->serial.u64, HEX)); - if((iv->config->serial.b[5] == 0x10) && ((iv->config->serial.b[4] & 0x03) == 0x01)) + if(IV_MI == iv->ivGen) DPRINTLN(DBG_WARN, F("MI Inverter, has some restrictions!")); - - #ifdef DYNAMIC_OFFSET - iv->rxOffset = (iv->ivGen == IV_HM) ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting - #else - //iv->rxOffset = ((iv->ivGen == IV_HM) && (iv->type == INV_TYPE_4CH)) ? 3 : 2; - iv->rxOffset = (iv->ivGen == IV_HM) ? 3 : 2; - #endif - cb(iv); } From b8cc3bcfe9cb4c7f614b26c7b4389fae9ae9d148 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 9 Feb 2024 16:37:08 +0100 Subject: [PATCH 41/79] Add hint to 'INV_RESET_MIDNIGHT' --- src/web/lang.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/lang.json b/src/web/lang.json index 689fbb06..1e79f8bf 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -290,8 +290,8 @@ }, { "token": "INV_RESET_MIDNIGHT", - "en": "Reset values and YieldDay at midnight", - "de": "Werte und Gesamtertrag um Mitternacht zurücksetzen" + "en": "Reset values and YieldDay at midnight. ('Pause communication during night' need to be set)", + "de": "Werte und Gesamtertrag um Mitternacht zurücksetzen ('Kommunikation während der Nacht pausieren' muss gesetzt sein)" }, { "token": "INV_PAUSE_SUNSET", From d5cecbb5b017349ece28431ed9b44ad724887039 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 10 Feb 2024 13:03:29 +0100 Subject: [PATCH 42/79] 0.8.78 * fixed protection --- src/CHANGES.md | 2 +- src/app.h | 12 +++----- src/appInterface.h | 5 ++- src/defines.h | 2 +- src/web/Protection.h | 72 +++++++++++++++++++++----------------------- src/web/RestApi.h | 6 ++-- src/web/web.h | 6 ++-- 7 files changed, 49 insertions(+), 56 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index ea067bd2..ce0adc6b 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,6 +1,6 @@ # Development Changes -## 0.8.78 - 2024-02-09 +## 0.8.78 - 2024-02-10 * finalized API token access #1415 ## 0.8.77 - 2024-02-08 diff --git a/src/app.h b/src/app.h index 1a4e780d..b16d7aeb 100644 --- a/src/app.h +++ b/src/app.h @@ -247,8 +247,8 @@ class app : public IApp, public ah::Scheduler { #endif } - void lock(void) override { - mProtection->lock(); + void lock(bool fromWeb) override { + mProtection->lock(fromWeb); } char *unlock(const char *clientIp, bool loginFromWeb) override { @@ -259,12 +259,8 @@ class app : public IApp, public ah::Scheduler { mProtection->resetLockTimeout(); } - bool isProtected(void) const override { - return mProtection->isProtected(); - } - - bool isProtected(const char *token, bool askedFromWeb) const override { - return mProtection->isProtected(token, askedFromWeb); + bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const override { + return mProtection->isProtected(clientIp, token, askedFromWeb); } bool getNrfEnabled(void) override { diff --git a/src/appInterface.h b/src/appInterface.h index f0d2b2a0..536455e0 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -61,11 +61,10 @@ class IApp { virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0; - virtual void lock(void) = 0; + virtual void lock(bool fromWeb) = 0; virtual char *unlock(const char *clientIp, bool loginFromWeb) = 0; virtual void resetLockTimeout(void) = 0; - virtual bool isProtected(void) const = 0; - virtual bool isProtected(const char *token, bool askedFromWeb) const = 0; + virtual bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const = 0; virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0; virtual uint16_t getHistoryMaxDay() = 0; diff --git a/src/defines.h b/src/defines.h index 46be8dac..ab685698 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 77 +#define VERSION_PATCH 78 //------------------------------------- typedef struct { diff --git a/src/web/Protection.h b/src/web/Protection.h index b9eeef95..7c1ff71e 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -18,12 +18,9 @@ class Protection { explicit Protection(const char *pwd) { mPwd = pwd; mLogoutTimeout = 0; - mLoginIp.fill(0); + mWebIp.fill(0); + mApiIp.fill(0); mToken.fill(0); - - // no password set - unlock - if(pwd[0] == '\0') - mProtected = false; } public: @@ -40,27 +37,30 @@ class Protection { // auto logout if(0 != mLogoutTimeout) { if (0 == --mLogoutTimeout) { - if(mPwd[0] != '\0') { - mProtected = true; - } + if(mPwd[0] != '\0') + lock(false); } } } - void lock(void) { - mProtected = true; - mLoginIp.fill(0); + void lock(bool fromWeb) { + mWebIp.fill(0); + if(fromWeb) + return; + + mApiIp.fill(0); mToken.fill(0); } char *unlock(const char *clientIp, bool loginFromWeb) { mLogoutTimeout = LOGOUT_TIMEOUT; - mProtected = false; if(loginFromWeb) - ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); - else + ah::ip2Arr(static_cast(mWebIp.data()), clientIp); + else { + ah::ip2Arr(static_cast(mApiIp.data()), clientIp); genToken(); + } return reinterpret_cast(mToken.data()); } @@ -70,30 +70,19 @@ class Protection { mLogoutTimeout = LOGOUT_TIMEOUT; } - bool isProtected(void) const { - return mProtected; - } - - bool isProtected(const char *token, bool askedFromWeb) const { // token == clientIp - if(mProtected) - return true; - - if(mPwd[0] == '\0') + bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const { + if(mPwd[0] == '\0') // no password set return false; - if(askedFromWeb) { // check IP address - std::array ip; - ah::ip2Arr(static_cast(ip.data()), token); - for(uint8_t i = 0; i < 4; i++) { - if(mLoginIp[i] != ip[i]) - return true; - } - } else { // API call - check token - if(0 == mToken[0]) // token is zero - return true; + if(askedFromWeb) + return !isIdentical(clientIp, mWebIp); + + // API call + if(0 == mToken[0]) // token is zero, from WebUi (logged in) + return !isIdentical(clientIp, mWebIp); + if(isIdentical(clientIp, mApiIp)) return (0 != strncmp(token, mToken.data(), 16)); - } return false; } @@ -106,8 +95,18 @@ class Protection { if(mToken[i] < 10) mToken[i] += 0x30; // convert to ascii number 1-9 (zero isn't allowed) else - mToken[i] += 0x37; // convert to ascii upper case character + mToken[i] += 0x37; // convert to ascii upper case character A-Z + } + } + + bool isIdentical(const char *clientIp, const std::array cmp) const { + std::array ip; + ah::ip2Arr(static_cast(ip.data()), clientIp); + for(uint8_t i = 0; i < 4; i++) { + if(cmp[i] != ip[i]) + return false; } + return true; } protected: @@ -115,9 +114,8 @@ class Protection { private: const char *mPwd; - bool mProtected = true; uint16_t mLogoutTimeout = 0; - std::array mLoginIp; + std::array mWebIp, mApiIp; std::array mToken; }; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 5103f3ba..53b604b5 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -266,7 +266,7 @@ class RestApi { obj[F("modules")] = String(mApp->getVersionModules()); obj[F("build")] = String(AUTO_GIT_HASH); obj[F("env")] = String(ENV_NAME); - obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str(), true); + obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str(), "", true); obj[F("menu_mask")] = (uint16_t)(mConfig->sys.protectionMask ); obj[F("menu_protEn")] = (bool) (mConfig->sys.adminPwd[0] != '\0'); obj[F("cst_lnk")] = String(mConfig->plugin.customLink); @@ -844,7 +844,7 @@ class RestApi { if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT const char* token = jsonIn["token"]; - if(mApp->isProtected(token, false)) { + if(mApp->isProtected(clientIP, token, false)) { jsonOut[F("error")] = F(IS_PROTECTED); return false; } @@ -897,7 +897,7 @@ class RestApi { if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT const char* token = jsonIn["token"]; - if(mApp->isProtected(token, false)) { + if(mApp->isProtected(clientIP, token, false)) { jsonOut[F("error")] = F(IS_PROTECTED); return false; } diff --git a/src/web/web.h b/src/web/web.h index 7ed41f92..692dd779 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -227,7 +227,7 @@ class Web { } void checkProtection(AsyncWebServerRequest *request) { - if(mApp->isProtected(request->client()->remoteIP().toString().c_str(), true)) { + if(mApp->isProtected(request->client()->remoteIP().toString().c_str(), "", true)) { checkRedirect(request); return; } @@ -328,7 +328,7 @@ class Web { DPRINTLN(DBG_VERBOSE, F("onLogout")); checkProtection(request); - mApp->lock(); + mApp->lock(true); AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); response->addHeader(F("Content-Encoding"), "gzip"); @@ -455,7 +455,7 @@ class Web { // protection if (request->arg("adminpwd") != "{PWD}") { request->arg("adminpwd").toCharArray(mConfig->sys.adminPwd, PWD_LEN); - mApp->lock(); + mApp->lock(false); } mConfig->sys.protectionMask = 0x0000; for (uint8_t i = 0; i < 7; i++) { From a51a7612155cb7d13f15c4cb4f9b6e33ac894229 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 11 Feb 2024 00:07:20 +0100 Subject: [PATCH 43/79] 0.8.78 * finalized API token access #1415 --- src/platformio.ini | 2 +- src/web/Protection.h | 16 ++++++------- src/web/RestApi.h | 41 ++++++++++++++++++--------------- src/web/html/index.html | 23 ++++++++---------- src/web/html/setup.html | 28 ++++++++++------------ src/web/html/visualization.html | 18 ++++++++------- 6 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/platformio.ini b/src/platformio.ini index f949aa37..7130bf4c 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -350,7 +350,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize diff --git a/src/web/Protection.h b/src/web/Protection.h index 7c1ff71e..82e4be49 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -33,8 +33,7 @@ class Protection { return mInstance; } - void tickSecond() { - // auto logout + void tickSecond() { // auto logout if(0 != mLogoutTimeout) { if (0 == --mLogoutTimeout) { if(mPwd[0] != '\0') @@ -77,8 +76,10 @@ class Protection { if(askedFromWeb) return !isIdentical(clientIp, mWebIp); - // API call - if(0 == mToken[0]) // token is zero, from WebUi (logged in) + if(nullptr == token) + return true; + + if('*' == token[0]) // call from WebUI return !isIdentical(clientIp, mWebIp); if(isIdentical(clientIp, mApiIp)) @@ -92,10 +93,9 @@ class Protection { mToken.fill(0); for(uint8_t i = 0; i < 16; i++) { mToken[i] = random(1, 35); - if(mToken[i] < 10) - mToken[i] += 0x30; // convert to ascii number 1-9 (zero isn't allowed) - else - mToken[i] += 0x37; // convert to ascii upper case character A-Z + // convert to ascii number 1-9 (zero isn't allowed) or upper + // case character A-Z + mToken[i] += (mToken[i] < 10) ? 0x30 : 0x37; } } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 53b604b5..fadd7277 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -841,15 +841,8 @@ class RestApi { return true; } - if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set - if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT - const char* token = jsonIn["token"]; - if(mApp->isProtected(clientIP, token, false)) { - jsonOut[F("error")] = F(IS_PROTECTED); - return false; - } - } - } + if(isProtected(jsonIn, jsonOut, clientIP)) + return false; Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); bool accepted = true; @@ -894,15 +887,8 @@ class RestApi { } bool setSetup(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { - if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set - if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT - const char* token = jsonIn["token"]; - if(mApp->isProtected(clientIP, token, false)) { - jsonOut[F("error")] = F(IS_PROTECTED); - return false; - } - } - } + if(isProtected(jsonIn, jsonOut, clientIP)) + return false; #if !defined(ETHERNET) if(F("scan_wifi") == jsonIn[F("cmd")]) @@ -951,6 +937,25 @@ class RestApi { return true; } + bool isProtected(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { + if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set + if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT + const char* token = nullptr; + if(jsonIn.containsKey(F("token"))) + token = jsonIn["token"]; + + if(!mApp->isProtected(clientIP, token, false)) + return false; + + jsonOut[F("error")] = F(IS_PROTECTED); + return true; + } + } + + return false; + } + + private: IApp *mApp = nullptr; HMSYSTEM *mSys = nullptr; HmRadio<> *mRadioNrf = nullptr; diff --git a/src/web/html/index.html b/src/web/html/index.html index e7b7afc4..2611db5b 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -41,27 +41,24 @@ var release = null; function apiCb(obj) { - var e = document.getElementById("apiResult"); + var e = document.getElementById("apiResult") if(obj.success) { - e.innerHTML = " {#COMMAND_EXE}"; - getAjax("/api/index", parse); - } - else - e.innerHTML = " {#ERROR}: " + obj.error; + e.innerHTML = " {#COMMAND_EXE}" + getAjax("/api/index", parse) + } else + e.innerHTML = " {#ERROR}: " + obj.error } function setTime() { - var date = new Date(); - var obj = new Object(); - obj.cmd = "set_time"; - obj.val = parseInt(date.getTime() / 1000); - getAjax("/api/setup", apiCb, "POST", JSON.stringify(obj)); + var date = new Date() + var obj = {cmd: "set_time", token: "*", val: parseInt(date.getTime() / 1000)} + getAjax("/api/setup", apiCb, "POST", JSON.stringify(obj)) } function parseGeneric(obj) { if(exeOnce) - parseESP(obj); - parseRssi(obj); + parseESP(obj) + parseRssi(obj) } function parseSys(obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index dec62830..4859fe34 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -559,31 +559,26 @@ } function setTime() { - var date = new Date(); - var obj = new Object(); - obj.cmd = "set_time"; - obj.val = parseInt(date.getTime() / 1000); - getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)); - setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000); + var date = new Date() + var obj = {cmd: "set_time", token: "*", val: parseInt(date.getTime() / 1000)} + getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)) + setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000) } function scan() { - var obj = new Object(); - obj.cmd = "scan_wifi"; + var obj = {cmd: "scan_wifi", token: "*"} getAjax("/api/setup", apiCbWifi, "POST", JSON.stringify(obj)); setTimeout(function() {getAjax('/api/setup/networks', listNetworks)}, 5000); } function syncTime() { - var obj = new Object(); - obj.cmd = "sync_ntp"; - getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)); - setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000); + var obj = {cmd: "sync_ntp", token: "*"} + getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj)) + setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000) } function sendDiscoveryConfig() { - var obj = new Object(); - obj.cmd = "discovery_cfg"; + var obj = {cmd: "discovery_cfg", token: "*"} getAjax("/api/setup", apiCbMqtt, "POST", JSON.stringify(obj)); } @@ -837,8 +832,9 @@ function ivSave() { var o = new Object(); - o.cmd = "save_iv"; - o.id = obj.id; + o.cmd = "save_iv" + o.token = "*" + o.id = obj.id o.ser = parseInt(document.getElementsByName("ser")[0].value, 16); o.name = document.getElementsByName("name")[0].value; o.en = document.getElementsByName("enable")[0].checked; diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 3b90a028..1ce4e264 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -454,18 +454,20 @@ val = 100; var obj = new Object(); - obj.id = id; - obj.cmd = cmd; - obj.val = Math.round(val*10); - getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj)); + obj.id = id + obj.token = "*" + obj.cmd = cmd + obj.val = Math.round(val*10) + getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj)) } function applyCtrl(id, cmd, val=0) { var obj = new Object(); - obj.id = id; - obj.cmd = cmd; - obj.val = val; - getAjax("/api/ctrl", ctrlCb2, "POST", JSON.stringify(obj)); + obj.id = id + obj.token = "*" + obj.cmd = cmd + obj.val = val + getAjax("/api/ctrl", ctrlCb2, "POST", JSON.stringify(obj)) } function ctrlCb(obj) { From e73e31b1ccf39f05b85c6129f3f285c9ffcb91f1 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 11 Feb 2024 00:17:33 +0100 Subject: [PATCH 44/79] 0.8.78 * possible fix of MqTT fix "total values are sent to often" #1421 --- src/CHANGES.md | 1 + src/publisher/pubMqttIvData.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index ce0adc6b..dab588ed 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,7 @@ ## 0.8.78 - 2024-02-10 * finalized API token access #1415 +* possible fix of MqTT fix "total values are sent to often" #1421 ## 0.8.77 - 2024-02-08 * merge PR: BugFix: ACK #1414 diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 5f38768d..06f8e629 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -246,7 +246,7 @@ class PubMqttIvData { mPos++; } else { mSendList->pop(); - mPos = 0; + mSendTotals = false; mState = IDLE; } } From 493c583b79fea184aeb899b6db052ee58e24d134 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 11 Feb 2024 00:21:47 +0100 Subject: [PATCH 45/79] 0.8.78 * removed `switchCycle` from `hmsRadio.h` #1412 --- src/CHANGES.md | 1 + src/hms/hmsRadio.h | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index dab588ed..be5e011c 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,7 @@ ## 0.8.78 - 2024-02-10 * finalized API token access #1415 * possible fix of MqTT fix "total values are sent to often" #1421 +* removed `switchCycle` from `hmsRadio.h` #1412 ## 0.8.77 - 2024-02-08 * merge PR: BugFix: ACK #1414 diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index cb181b0b..d074442b 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -9,7 +9,7 @@ #include "cmt2300a.h" #include "../hm/radio.h" -#define CMT_SWITCH_CHANNEL_CYCLE 5 +//#define CMT_SWITCH_CHANNEL_CYCLE 5 template class CmtRadio : public Radio { @@ -150,9 +150,9 @@ class CmtRadio : public Radio { } inline void sendSwitchChCmd(Inverter<> *iv, uint8_t ch) { - if(CMT_SWITCH_CHANNEL_CYCLE > ++mSwitchCycle) - return; - mSwitchCycle = 0; + //if(CMT_SWITCH_CHANNEL_CYCLE > ++mSwitchCycle) + // return; + //mSwitchCycle = 0; /** ch: * 0x00: 860.00 MHz @@ -176,7 +176,7 @@ class CmtRadio : public Radio { packet_t p; p.millis = millis() - mMillis; if(CmtStatus::SUCCESS == mCmt.getRx(p.packet, &p.len, 28, &p.rssi)) { - mSwitchCycle = 0; + //mSwitchCycle = 0; p.ch = 0; // not used for CMT inverters mBufCtrl.push(p); } @@ -191,7 +191,7 @@ class CmtRadio : public Radio { bool mCmtAvail = false; bool mRqstGetRx = false; uint32_t mMillis = 0; - uint8_t mSwitchCycle = 0; + //uint8_t mSwitchCycle = 0; }; #endif /*__HMS_RADIO_H__*/ From c2902737901d59895306fa6a3239193b036d3c1f Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 11 Feb 2024 01:07:07 +0100 Subject: [PATCH 46/79] 0.8.78 * merge PR: Add hint to INV_RESET_MIDNIGHT resp. INV_PAUSE_DURING_NIGHT #1418 * merge PR: simplify rxOffset logic #1417 * code quality improvments --- src/CHANGES.md | 3 +++ src/eth/ahoyeth.h | 2 +- src/utils/helper.cpp | 6 ++---- src/utils/syslog.cpp | 3 +-- src/web/html/colorBright.css | 6 +++--- src/web/html/colorDark.css | 16 ++++++++-------- src/web/html/style.css | 21 +++++++++++---------- 7 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index be5e011c..aa63153f 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,9 @@ * finalized API token access #1415 * possible fix of MqTT fix "total values are sent to often" #1421 * removed `switchCycle` from `hmsRadio.h` #1412 +* merge PR: Add hint to INV_RESET_MIDNIGHT resp. INV_PAUSE_DURING_NIGHT #1418 +* merge PR: simplify rxOffset logic #1417 +* code quality improvments ## 0.8.77 - 2024-02-08 * merge PR: BugFix: ACK #1414 diff --git a/src/eth/ahoyeth.h b/src/eth/ahoyeth.h index ef8d0751..ebd91c67 100644 --- a/src/eth/ahoyeth.h +++ b/src/eth/ahoyeth.h @@ -49,7 +49,7 @@ class ahoyeth { #if defined(CONFIG_IDF_TARGET_ESP32S3) EthSpi mEthSpi; #endif - settings_t *mConfig = NULL; + settings_t *mConfig = nullptr; uint32_t *mUtcTimestamp; AsyncUDP mUdp; // for time server diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index b3f53a23..24a4d9ee 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -72,11 +72,10 @@ namespace ah { String getTimeStrMs(uint64_t t) { char str[13]; - uint16_t m; if(0 == t) sprintf(str, "n/a"); else { - m = t % 1000; + uint16_t m = t % 1000; t = t / 1000; sprintf(str, "%02d:%02d:%02d.%03d", hour(t), minute(t), second(t), m); } @@ -86,14 +85,13 @@ namespace ah { uint64_t Serial2u64(const char *val) { char tmp[3]; uint64_t ret = 0ULL; - uint64_t u64; memset(tmp, 0, 3); for(uint8_t i = 0; i < 6; i++) { tmp[0] = val[i*2]; tmp[1] = val[i*2 + 1]; if((tmp[0] == '\0') || (tmp[1] == '\0')) break; - u64 = strtol(tmp, NULL, 16); + uint64_t u64 = strtol(tmp, NULL, 16); ret |= (u64 << ((5-i) << 3)); } return ret; diff --git a/src/utils/syslog.cpp b/src/utils/syslog.cpp index c251e899..d02e25ed 100644 --- a/src/utils/syslog.cpp +++ b/src/utils/syslog.cpp @@ -68,12 +68,11 @@ void DbgSyslog::syslogCb (String msg) // Send mSyslogBuffer in chunks because mSyslogBuffer is larger than syslog packet size int packetStart = 0; int packetSize = 122; // syslog payload depends also on hostname and app - char saveChar; if (isEolFound) { mSyslogBuffer[mSyslogBufFill-2]=0; // skip \r\n } while(packetStart < mSyslogBufFill) { - saveChar = mSyslogBuffer[packetStart+packetSize]; + char saveChar = mSyslogBuffer[packetStart+packetSize]; mSyslogBuffer[packetStart+packetSize] = 0; log(mConfig->sys.deviceName,SYSLOG_FACILITY, mSyslogSeverity, &mSyslogBuffer[packetStart]); mSyslogBuffer[packetStart+packetSize] = saveChar; diff --git a/src/web/html/colorBright.css b/src/web/html/colorBright.css index 47382daa..2e676029 100644 --- a/src/web/html/colorBright.css +++ b/src/web/html/colorBright.css @@ -3,9 +3,9 @@ --fg: #000; --fg2: #fff; - --info: #0000dd; - --warn: #ff7700; - --success: #009900; + --info: #00d; + --warn: #f70; + --success: #090; --input-bg: #eee; --table-border: #ccc; diff --git a/src/web/html/colorDark.css b/src/web/html/colorDark.css index 65100721..40bd4cf3 100644 --- a/src/web/html/colorDark.css +++ b/src/web/html/colorDark.css @@ -4,8 +4,8 @@ --fg2: #fff; --info: #0072c8; - --warn: #ffaa00; - --success: #00bb00; + --warn: #fa0; + --success: #0b0; --input-bg: #333; --table-border: #333; @@ -20,14 +20,14 @@ --invalid-bg: #400; - --total-head-title: #555511; - --total-bg: #666622; - --iv-head-title: #115511; - --iv-head-bg: #226622; + --total-head-title: #551; + --total-bg: #662; + --iv-head-title: #151; + --iv-head-bg: #262; --iv-dis-title: #333; --iv-dis: #444; - --ch-head-title: #112255; - --ch-head-bg: #223366; + --ch-head-title: #125; + --ch-head-bg: #236; --ts-head: #333; --ts-bg: #555; } diff --git a/src/web/html/style.css b/src/web/html/style.css index 395fcb99..2d6a03c7 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -16,11 +16,11 @@ span, li, h3, label, fieldset { color: var(--fg); } -fieldset, input[type=submit], .btn { +fieldset, input[type="submit"], .btn { border-radius: 4px; } -input[type=file] { +input[type="file"] { width: 100%; } @@ -33,7 +33,7 @@ textarea { color: var(--fg2); } -svg rect {fill: #0000AA;} +svg rect {fill: #00A;} svg.chart { background: #f2f2f2; border: 2px solid gray; @@ -44,6 +44,7 @@ div.chartDivContainer { padding: 1px; margin: 1px; } + div.chartdivContainer span { color: var(--fg2); } @@ -95,7 +96,7 @@ svg.icon { vertical-align: middle; display: inline-block; margin-top:-4x; - padding: 5px 7px 5px 0px; + padding: 5px 7px 5px 0; } .icon-info { @@ -141,7 +142,7 @@ svg.icon { span.seperator { width: 100%; height: 1px; - margin: 5px 0px 5px; + margin: 5px 0 5px; background-color: #494949; display: block; } @@ -391,7 +392,7 @@ th { #footer .left { color: #bbb; - margin: 23px 0px 0px 25px; + margin: 23px 0 0 25px; } #footer ul { @@ -525,7 +526,7 @@ input, select { font-size: 13pt; } -input[type=text], input[type=password], select, input[type=number] { +input[type="text"], input[type="password"], select, input[type="number"] { width: 100%; box-sizing: border-box; border: 1px solid #ccc; @@ -551,7 +552,7 @@ input.btnDel { input.btn { background-color: var(--primary); color: #fff; - border: 0px; + border: 0; padding: 7px 20px 7px 20px; margin-bottom: 10px; text-transform: uppercase; @@ -572,7 +573,7 @@ label { display: inline-block; font-size: 12pt; padding-right: 10px; - margin: 10px 0px 0px 15px; + margin: 10px 0 0 15px; vertical-align: top; } @@ -601,7 +602,7 @@ div.ModPwr, div.ModName, div.YieldCor { div.hr { height: 1px; border-top: 1px solid #ccc; - margin: 10px 0px 10px; + margin: 10px 0 10px; } #note { From 3e533e82af88471f358af3a4651a39ff8b5c0c26 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 11 Feb 2024 01:37:55 +0100 Subject: [PATCH 47/79] updated GxEPD2 to 1.5.5 --- patches/GxEPD2_SW_SPI.patch | 56 +++++++++++++------------------------ src/platformio.ini | 10 +++---- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/patches/GxEPD2_SW_SPI.patch b/patches/GxEPD2_SW_SPI.patch index dc3fa9ca..87458cce 100644 --- a/patches/GxEPD2_SW_SPI.patch +++ b/patches/GxEPD2_SW_SPI.patch @@ -1,5 +1,5 @@ diff --git a/src/GxEPD2_EPD.cpp b/src/GxEPD2_EPD.cpp -index 8df8bef..91d7f49 100644 +index 40b1b13..d0dbdba 100644 --- a/src/GxEPD2_EPD.cpp +++ b/src/GxEPD2_EPD.cpp @@ -19,9 +19,9 @@ @@ -14,29 +14,25 @@ index 8df8bef..91d7f49 100644 { _initial_write = true; _initial_refresh = true; -@@ -71,27 +71,30 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset +@@ -61,7 +61,6 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset + digitalWrite(_cs, HIGH); // set (needed e.g. for RP2040) + } + _reset(); +- _pSPIx->begin(); // may steal _rst pin (Waveshare Pico-ePaper-2.9) + if (_rst >= 0) + { + digitalWrite(_rst, HIGH); // preset (less glitch for any analyzer) +@@ -84,14 +83,30 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset { pinMode(_busy, INPUT); } -- _pSPIx->begin(); -- if (_busy == MISO) // may be overridden -- { -- pinMode(_busy, INPUT); -- } -- if (_dc == MISO) // may be overridden, TTGO T5 V2.66 -- { -- pinMode(_dc, OUTPUT); -- } -- if (_cs == MISO) // may be overridden + if (_sck < 0) SPI.begin(); +} + +void GxEPD2_EPD::init(int16_t sck, int16_t mosi, uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode) +{ + if ((sck >= 0) && (mosi >= 0)) - { -- pinMode(_cs, INPUT); -- } ++ { + _sck = sck; + _mosi = mosi; + digitalWrite(_sck, LOW); @@ -58,7 +54,7 @@ index 8df8bef..91d7f49 100644 } void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* busy_callback_parameter) -@@ -100,12 +103,6 @@ void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* +@@ -100,12 +115,6 @@ void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* _busy_callback_parameter = busy_callback_parameter; } @@ -71,7 +67,7 @@ index 8df8bef..91d7f49 100644 void GxEPD2_EPD::_reset() { if (_rst >= 0) -@@ -174,115 +171,201 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time) +@@ -174,115 +183,201 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time) void GxEPD2_EPD::_writeCommand(uint8_t c) { @@ -304,21 +300,10 @@ index 8df8bef..91d7f49 100644 + _endTransaction(); } diff --git a/src/GxEPD2_EPD.h b/src/GxEPD2_EPD.h -index 34c1145..c480b7d 100644 +index 3daf37e..96198c2 100644 --- a/src/GxEPD2_EPD.h +++ b/src/GxEPD2_EPD.h -@@ -8,6 +8,10 @@ - // Version: see library.properties - // - // Library: https://github.com/ZinggJM/GxEPD2 -+// To use SW SPI with GxEPD2: -+// add the special call to the added init method BEFORE the normal init method: -+// display.epd2.init(SW_SCK, SW_MOSI, 115200, true, 20, false); // define or replace SW_SCK, SW_MOSI -+// display.init(115200); // needed to init upper level - - #ifndef _GxEPD2_EPD_H_ - #define _GxEPD2_EPD_H_ -@@ -35,6 +39,7 @@ class GxEPD2_EPD +@@ -35,6 +35,7 @@ class GxEPD2_EPD uint16_t w, uint16_t h, GxEPD2::Panel p, bool c, bool pu, bool fpu); virtual void init(uint32_t serial_diag_bitrate = 0); // serial_diag_bitrate = 0 : disabled virtual void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 10, bool pulldown_rst_mode = false); @@ -326,7 +311,7 @@ index 34c1145..c480b7d 100644 virtual void end(); // release SPI and control pins // Support for Bitmaps (Sprites) to Controller Buffer and to Screen virtual void clearScreen(uint8_t value) = 0; // init controller memory and screen (default white) -@@ -97,7 +102,6 @@ class GxEPD2_EPD +@@ -97,7 +98,6 @@ class GxEPD2_EPD { return (a > b ? a : b); }; @@ -334,7 +319,7 @@ index 34c1145..c480b7d 100644 protected: void _reset(); void _waitWhileBusy(const char* comment = 0, uint16_t busy_time = 5000); -@@ -111,17 +115,22 @@ class GxEPD2_EPD +@@ -111,8 +111,14 @@ class GxEPD2_EPD void _startTransfer(); void _transfer(uint8_t value); void _endTransfer(); @@ -346,12 +331,11 @@ index 34c1145..c480b7d 100644 + void _readData(uint8_t* data, uint16_t n); protected: - int16_t _cs, _dc, _rst, _busy, _busy_level; -+ int16_t _cs, _dc, _rst, _busy, _busy_level, _sck, _mosi;; ++ int16_t _cs, _dc, _rst, _busy, _busy_level, _sck, _mosi; uint32_t _busy_timeout; bool _diag_enabled, _pulldown_rst_mode; -- SPIClass* _pSPIx; - SPISettings _spi_settings; - bool _initial_write, _initial_refresh; + SPIClass* _pSPIx; +@@ -121,7 +127,7 @@ class GxEPD2_EPD bool _power_is_on, _using_partial_mode, _hibernating; bool _init_display_done; uint16_t _reset_duration; diff --git a/src/platformio.ini b/src/platformio.ini index 7130bf4c..0a76a59d 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -32,7 +32,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.3 + https://github.com/zinggjm/GxEPD2#1.5.5 build_flags = -std=c++17 -std=gnu++17 @@ -201,7 +201,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.3 + https://github.com/zinggjm/GxEPD2#1.5.5 build_flags = ${env.build_flags} -D ETHERNET -DRELEASE @@ -224,7 +224,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.3 + https://github.com/zinggjm/GxEPD2#1.5.5 build_flags = ${env.build_flags} -D ETHERNET -DRELEASE @@ -418,7 +418,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.3 + https://github.com/zinggjm/GxEPD2#1.5.5 upload_protocol = esp-builtin build_flags = ${env.build_flags} -DETHERNET @@ -463,7 +463,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.3 + https://github.com/zinggjm/GxEPD2#1.5.5 upload_protocol = esp-builtin build_flags = ${env.build_flags} -DETHERNET From 315541ea51d5573a48b78c09e0e73a07b607868c Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 11 Feb 2024 22:44:32 +0100 Subject: [PATCH 48/79] 0.8.79 * fix `opendtufusion` build (started only once USB-console was connected) * code quality improvments --- patches/GxEPD2_SW_SPI.patch | 56 ++++++++++++++++++++++++------------- src/CHANGES.md | 4 +++ src/defines.h | 2 +- src/hm/hmRadio.h | 2 +- src/platformio.ini | 12 ++++---- 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/patches/GxEPD2_SW_SPI.patch b/patches/GxEPD2_SW_SPI.patch index 87458cce..dc3fa9ca 100644 --- a/patches/GxEPD2_SW_SPI.patch +++ b/patches/GxEPD2_SW_SPI.patch @@ -1,5 +1,5 @@ diff --git a/src/GxEPD2_EPD.cpp b/src/GxEPD2_EPD.cpp -index 40b1b13..d0dbdba 100644 +index 8df8bef..91d7f49 100644 --- a/src/GxEPD2_EPD.cpp +++ b/src/GxEPD2_EPD.cpp @@ -19,9 +19,9 @@ @@ -14,25 +14,29 @@ index 40b1b13..d0dbdba 100644 { _initial_write = true; _initial_refresh = true; -@@ -61,7 +61,6 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset - digitalWrite(_cs, HIGH); // set (needed e.g. for RP2040) - } - _reset(); -- _pSPIx->begin(); // may steal _rst pin (Waveshare Pico-ePaper-2.9) - if (_rst >= 0) - { - digitalWrite(_rst, HIGH); // preset (less glitch for any analyzer) -@@ -84,14 +83,30 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset +@@ -71,27 +71,30 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset { pinMode(_busy, INPUT); } +- _pSPIx->begin(); +- if (_busy == MISO) // may be overridden +- { +- pinMode(_busy, INPUT); +- } +- if (_dc == MISO) // may be overridden, TTGO T5 V2.66 +- { +- pinMode(_dc, OUTPUT); +- } +- if (_cs == MISO) // may be overridden + if (_sck < 0) SPI.begin(); +} + +void GxEPD2_EPD::init(int16_t sck, int16_t mosi, uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode) +{ + if ((sck >= 0) && (mosi >= 0)) -+ { + { +- pinMode(_cs, INPUT); +- } + _sck = sck; + _mosi = mosi; + digitalWrite(_sck, LOW); @@ -54,7 +58,7 @@ index 40b1b13..d0dbdba 100644 } void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* busy_callback_parameter) -@@ -100,12 +115,6 @@ void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* +@@ -100,12 +103,6 @@ void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* _busy_callback_parameter = busy_callback_parameter; } @@ -67,7 +71,7 @@ index 40b1b13..d0dbdba 100644 void GxEPD2_EPD::_reset() { if (_rst >= 0) -@@ -174,115 +183,201 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time) +@@ -174,115 +171,201 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time) void GxEPD2_EPD::_writeCommand(uint8_t c) { @@ -300,10 +304,21 @@ index 40b1b13..d0dbdba 100644 + _endTransaction(); } diff --git a/src/GxEPD2_EPD.h b/src/GxEPD2_EPD.h -index 3daf37e..96198c2 100644 +index 34c1145..c480b7d 100644 --- a/src/GxEPD2_EPD.h +++ b/src/GxEPD2_EPD.h -@@ -35,6 +35,7 @@ class GxEPD2_EPD +@@ -8,6 +8,10 @@ + // Version: see library.properties + // + // Library: https://github.com/ZinggJM/GxEPD2 ++// To use SW SPI with GxEPD2: ++// add the special call to the added init method BEFORE the normal init method: ++// display.epd2.init(SW_SCK, SW_MOSI, 115200, true, 20, false); // define or replace SW_SCK, SW_MOSI ++// display.init(115200); // needed to init upper level + + #ifndef _GxEPD2_EPD_H_ + #define _GxEPD2_EPD_H_ +@@ -35,6 +39,7 @@ class GxEPD2_EPD uint16_t w, uint16_t h, GxEPD2::Panel p, bool c, bool pu, bool fpu); virtual void init(uint32_t serial_diag_bitrate = 0); // serial_diag_bitrate = 0 : disabled virtual void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 10, bool pulldown_rst_mode = false); @@ -311,7 +326,7 @@ index 3daf37e..96198c2 100644 virtual void end(); // release SPI and control pins // Support for Bitmaps (Sprites) to Controller Buffer and to Screen virtual void clearScreen(uint8_t value) = 0; // init controller memory and screen (default white) -@@ -97,7 +98,6 @@ class GxEPD2_EPD +@@ -97,7 +102,6 @@ class GxEPD2_EPD { return (a > b ? a : b); }; @@ -319,7 +334,7 @@ index 3daf37e..96198c2 100644 protected: void _reset(); void _waitWhileBusy(const char* comment = 0, uint16_t busy_time = 5000); -@@ -111,8 +111,14 @@ class GxEPD2_EPD +@@ -111,17 +115,22 @@ class GxEPD2_EPD void _startTransfer(); void _transfer(uint8_t value); void _endTransfer(); @@ -331,11 +346,12 @@ index 3daf37e..96198c2 100644 + void _readData(uint8_t* data, uint16_t n); protected: - int16_t _cs, _dc, _rst, _busy, _busy_level; -+ int16_t _cs, _dc, _rst, _busy, _busy_level, _sck, _mosi; ++ int16_t _cs, _dc, _rst, _busy, _busy_level, _sck, _mosi;; uint32_t _busy_timeout; bool _diag_enabled, _pulldown_rst_mode; - SPIClass* _pSPIx; -@@ -121,7 +127,7 @@ class GxEPD2_EPD +- SPIClass* _pSPIx; + SPISettings _spi_settings; + bool _initial_write, _initial_refresh; bool _power_is_on, _using_partial_mode, _hibernating; bool _init_display_done; uint16_t _reset_duration; diff --git a/src/CHANGES.md b/src/CHANGES.md index aa63153f..dff1bb30 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.79 - 2024-02-11 +* fix `opendtufusion` build (started only once USB-console was connected) +* code quality improvments + ## 0.8.78 - 2024-02-10 * finalized API token access #1415 * possible fix of MqTT fix "total values are sent to often" #1421 diff --git a/src/defines.h b/src/defines.h index ab685698..40084c47 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 78 +#define VERSION_PATCH 79 //------------------------------------- typedef struct { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index b01df277..d1d24364 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -159,7 +159,7 @@ class HmRadio : public Radio { mTimeslotStart = millis(); tempRxChIdx = mRxChIdx; // might be better to start off with one channel less? mRxPendular = false; - mNRFloopChannels = (mLastIv->mCmd == MI_REQ_CH1 || mLastIv->mCmd == MI_REQ_CH1); + mNRFloopChannels = (mLastIv->mCmd == MI_REQ_CH1); innerLoopTimeout = DURATION_LISTEN_MIN; } diff --git a/src/platformio.ini b/src/platformio.ini index 0a76a59d..f949aa37 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -32,7 +32,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.5 + https://github.com/zinggjm/GxEPD2#1.5.3 build_flags = -std=c++17 -std=gnu++17 @@ -201,7 +201,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.5 + https://github.com/zinggjm/GxEPD2#1.5.3 build_flags = ${env.build_flags} -D ETHERNET -DRELEASE @@ -224,7 +224,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.5 + https://github.com/zinggjm/GxEPD2#1.5.3 build_flags = ${env.build_flags} -D ETHERNET -DRELEASE @@ -350,7 +350,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - -DARDUINO_USB_CDC_ON_BOOT=1 + #-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize @@ -418,7 +418,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.5 + https://github.com/zinggjm/GxEPD2#1.5.3 upload_protocol = esp-builtin build_flags = ${env.build_flags} -DETHERNET @@ -463,7 +463,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.9 - https://github.com/zinggjm/GxEPD2#1.5.5 + https://github.com/zinggjm/GxEPD2#1.5.3 upload_protocol = esp-builtin build_flags = ${env.build_flags} -DETHERNET From 31232bfd80b4f4405a2f8faed0f0cc468ad5dcf5 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 12 Feb 2024 22:32:13 +0100 Subject: [PATCH 49/79] 0.8.80 * optimize API authentication, Error-Codes #1415 * breaking change: authentication API command changed #1415 * breaking change: limit has to be send als `float`, `0.0 .. 100.0` #1415 * updated documentation #1415 * fix don't send control command twice #1426 --- README.md | 8 ++--- manual/User_Manual.md | 55 +++++++++++++++++++++++++-------- src/CHANGES.md | 7 +++++ src/defines.h | 2 +- src/hm/hmInverter.h | 5 +-- src/publisher/pubMqtt.h | 2 +- src/web/RestApi.h | 37 ++++++++++++---------- src/web/html/visualization.html | 15 +++++++-- src/web/lang.h | 30 ------------------ src/web/lang.json | 25 +++++++++++++++ 10 files changed, 116 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 7a51a98a..16b2a256 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Table of approaches: | Board | MI | HM | HMS/HMT | comment | HowTo start | | ------ | -- | -- | ------- | ------- | ---------- | -| [ESP8266/ESP32, C++](Getting_Started.md) | ✔️ | ✔️ | ✔️ | 👈 the most effort is spent here | [create your own DTU](https://ahoydtu.de/getting_started/) | +| [ESP8266/ESP32, C++](manual/Getting_Started.md) | ✔️ | ✔️ | ✔️ | 👈 the most effort is spent here | [create your own DTU](https://ahoydtu.de/getting_started/) | | [Arduino Nano, C++](tools/nano/NRF24_SendRcv/) | ❌ | ✔️ | ❌ | | | [Raspberry Pi, Python](tools/rpi/) | ❌ | ✔️ | ❌ | | | [Others, C/C++](tools/nano/NRF24_SendRcv/) | ❌ | ✔️ | ❌ | | @@ -39,11 +39,11 @@ Table of approaches: ⚠️ **Warning: HMS-XXXXW-2T WiFi inverters are not supported. They have a 'W' in their name and a DTU serial number on its sticker** ## Getting Started -1. [Guide how to start with a ESP module](Getting_Started.md) +1. [Guide how to start with a ESP module](manual/Getting_Started.md) 2. [ESP Webinstaller (Edge / Chrome Browser only)](https://ahoydtu.de/web_install) -3. [Ahoy Configuration ](ahoy_config.md) +3. [Ahoy Configuration ](manual/ahoy_config.md) ## Our Website [https://ahoydtu.de](https://ahoydtu.de) @@ -64,4 +64,4 @@ If you encounter any problems, use the issue tracker on Github. Provide a detail - [OpenDTU](https://github.com/tbnobody/OpenDTU) <- Our sister project ✨ for Hoymiles HM- and HMS-/HMT-series (for ESP32 only!) - [hms-mqtt-publisher](https://github.com/DennisOSRM/hms-mqtt-publisher) - <- a project which can handle WiFi inverters like HMS-XXXXW-2T \ No newline at end of file + <- a project which can handle WiFi inverters like HMS-XXXXW-2T diff --git a/manual/User_Manual.md b/manual/User_Manual.md index 53da34f4..b5cf5a7e 100644 --- a/manual/User_Manual.md +++ b/manual/User_Manual.md @@ -166,6 +166,8 @@ inverter/ctrl/limit/0 600W ### Power Limit persistent This feature was removed. The persisten limit should not be modified cyclic by a script because of potential wearout of the flash inside the inverter. + + ## Control via REST API ### Generic Information @@ -174,6 +176,46 @@ The rest API works with *JSON* POST requests. All the following instructions mus 👆 `` is the number of the specific inverter in the setup page. +### Authentication (new for versions > `0.8.79`) + +The authentication is only needed if a password was set. +To authenticate from API you have to add the following `JSON` to your request: + +```json +{ + "auth": +} +``` +`` is your DTU password in plain text. + +As Response you get the following `JSON` if successful: + +```json +{ + "success": true, + "token": "" +} +``` +Where `` is a random token with a length of 16 characters. + +For all following commands you have only to include the token into your `JSON`: +```json +{ + "token": "" +} +``` + +ℹ️ Do not pass the plain text password with each command. Authenticate once and then use the token for all following commands. The token expires once the token wasn't sent for 20 minutes. + +If the authentication fails or the token is expired you will receive the following `JSON`: + +```json +{ + "success": false, + "error": "ERR_PROTECTED" +} +``` + ### Inverter Power (On / Off) ```json @@ -245,19 +287,6 @@ The `VALUE` represents a percent number in a range of `[2.0 .. 100.0]` The `VALUE` represents watts in a range of `[1.0 .. 6553.5]` - -### Developer Information REST API (obsolete) -In the same approach as for MQTT any other SubCmd and also MainCmd can be applied and the response payload can be observed in the serial logs. Eg. request the Alarm-Data from the Alarm-Index 5 from inverter 0 will look like this: -```json -{ - "inverter":0, - "tx_request": 21, - "cmd": 17, - "payload": 5, - "payload2": 0 -} -``` - ## Zero Export Control (needs rework) * You can use the mqtt topic `/devcontrol//11` with a number as payload (eg. 300 -> 300 Watt) to set the power limit to the published number in Watt. (In regular cases the inverter will use the new set point within one intervall period; to verify this see next bullet) * You can check the inverter set point for the power limit control on the topic `//ch0/PowerLimit` 👆 This value is ALWAYS in percent of the maximum power limit of the inverter. In regular cases this value will be updated within approx. 15 seconds. (depends on request intervall) diff --git a/src/CHANGES.md b/src/CHANGES.md index dff1bb30..714dc8cc 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,12 @@ # Development Changes +## 0.8.80 - 2024-02-12 +* optimize API authentication, Error-Codes #1415 +* breaking change: authentication API command changed #1415 +* breaking change: limit has to be send als `float`, `0.0 .. 100.0` #1415 +* updated documentation #1415 +* fix don't send control command twice #1426 + ## 0.8.79 - 2024-02-11 * fix `opendtufusion` build (started only once USB-console was connected) * code quality improvments diff --git a/src/defines.h b/src/defines.h index 40084c47..8913db5e 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 79 +#define VERSION_PATCH 80 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b6dc93fa..f608908e 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -163,9 +163,10 @@ class Inverter { void tickSend(std::function cb) { if(mDevControlRequest) { - if(InverterStatus::OFF != status) + if(InverterStatus::OFF != status) { cb(devControlCmd, true); - else + devControlCmd = InitDataState; + } else DPRINTLN(DBG_WARN, F("Inverter is not avail")); mDevControlRequest = false; } else if (IV_MI != ivGen) { // HM / HMS / HMT diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 1b9e35ef..369d9ead 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -316,7 +316,7 @@ class PubMqtt { if(NULL == strstr(topic, "limit")) root[F("val")] = atoi(pyld); else - root[F("val")] = (int)(atof(pyld) * 10.0f); + root[F("val")] = atof(pyld); if(pyld[len-1] == 'W') limitAbs = true; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index fadd7277..37e988c0 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -30,10 +30,6 @@ #define F(sl) (sl) #endif -const uint8_t acList[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PF, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP}; -const uint8_t acListHmt[] = {FLD_UAC_1N, FLD_IAC_1, FLD_PAC, FLD_F, FLD_PF, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP}; -const uint8_t dcList[] = {FLD_UDC, FLD_IDC, FLD_PDC, FLD_YD, FLD_YT, FLD_IRR, FLD_MP}; - template class RestApi { public: @@ -831,14 +827,16 @@ class RestApi { } bool setCtrl(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { - if(F("auth") == jsonIn[F("cmd")]) { - if(String(jsonIn["val"]) == String(mConfig->sys.adminPwd)) - jsonOut["token"] = mApp->unlock(clientIP, false); - else { - jsonOut[F("error")] = F(AUTH_ERROR); + if(jsonIn.containsKey(F("auth"))) { + if(String(jsonIn[F("auth")]) == String(mConfig->sys.adminPwd)) { + jsonOut[F("token")] = mApp->unlock(clientIP, false); + jsonIn[F("token")] = jsonOut[F("token")]; + } else { + jsonOut[F("error")] = F("ERR_AUTH"); return false; } - return true; + if(!jsonIn.containsKey(F("cmd"))) + return true; } if(isProtected(jsonIn, jsonOut, clientIP)) @@ -847,7 +845,7 @@ class RestApi { Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); bool accepted = true; if(NULL == iv) { - jsonOut[F("error")] = F(INV_INDEX_INVALID) + jsonIn[F("id")].as(); + jsonOut[F("error")] = F("ERR_INDEX"); return false; } jsonOut[F("id")] = jsonIn[F("id")]; @@ -857,7 +855,7 @@ class RestApi { else if(F("restart") == jsonIn[F("cmd")]) accepted = iv->setDevControlRequest(Restart); else if(0 == strncmp("limit_", jsonIn[F("cmd")].as(), 6)) { - iv->powerLimit[0] = jsonIn["val"]; + iv->powerLimit[0] = static_cast(jsonIn["val"].as() * 10.0); if(F("limit_persistent_relative") == jsonIn[F("cmd")]) iv->powerLimit[1] = RelativPersistent; else if(F("limit_persistent_absolute") == jsonIn[F("cmd")]) @@ -874,12 +872,12 @@ class RestApi { DPRINTLN(DBG_INFO, F("dev cmd")); iv->setDevCommand(jsonIn[F("val")].as()); } else { - jsonOut[F("error")] = F(UNKNOWN_CMD) + jsonIn["cmd"].as() + "'"; + jsonOut[F("error")] = F("ERR_UNKNOWN_CMD"); return false; } if(!accepted) { - jsonOut[F("error")] = F(INV_DOES_NOT_ACCEPT_LIMIT_AT_MOMENT); + jsonOut[F("error")] = F("ERR_LIMIT_NOT_ACCEPT"); return false; } @@ -930,7 +928,7 @@ class RestApi { iv->config->disNightCom = jsonIn[F("disnightcom")]; mApp->saveSettings(false); // without reboot } else { - jsonOut[F("error")] = F(UNKNOWN_CMD); + jsonOut[F("error")] = F("ERR_UNKNOWN_CMD"); return false; } @@ -947,7 +945,7 @@ class RestApi { if(!mApp->isProtected(clientIP, token, false)) return false; - jsonOut[F("error")] = F(IS_PROTECTED); + jsonOut[F("error")] = F("ERR_PROTECTED"); return true; } } @@ -955,6 +953,13 @@ class RestApi { return false; } + private: + constexpr static uint8_t acList[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PF, FLD_T, FLD_YT, + FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP}; + constexpr static uint8_t acListHmt[] = {FLD_UAC_1N, FLD_IAC_1, FLD_PAC, FLD_F, FLD_PF, FLD_T, + FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP}; + constexpr static uint8_t dcList[] = {FLD_UDC, FLD_IDC, FLD_PDC, FLD_YD, FLD_YT, FLD_IRR, FLD_MP}; + private: IApp *mApp = nullptr; HMSYSTEM *mSys = nullptr; diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 1ce4e264..81962add 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -22,6 +22,15 @@ var total = Array(6).fill(0); var tPwrAck; + function getErrStr(code) { + if("ERR_AUTH") return "{#ERR_AUTH}" + if("ERR_INDEX") return "{#ERR_INDEX}" + if("ERR_UNKNOWN_CMD") return "{#ERR_UNKNOWN_CMD}" + if("ERR_LIMIT_NOT_ACCEPT") return "{#ERR_LIMIT_NOT_ACCEPT}" + if("ERR_UNKNOWN_CMD") return "{#ERR_AUTH}" + return "n/a" + } + function parseGeneric(obj) { if(true == exeOnce){ parseNav(obj); @@ -457,7 +466,7 @@ obj.id = id obj.token = "*" obj.cmd = cmd - obj.val = Math.round(val*10) + obj.val = val getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj)) } @@ -477,7 +486,7 @@ tPwrAck = window.setInterval("getAjax('/api/inverter/pwrack/" + obj.id + "', updatePwrAck)", 1000); } else - e.innerHTML = "{#ERROR}: " + obj["error"]; + e.innerHTML = "{#ERROR}: " + getErrStr(obj.error); } function ctrlCb2(obj) { @@ -485,7 +494,7 @@ if(obj.success) e.innerHTML = "{#COMMAND_RECEIVED}"; else - e.innerHTML = "{#ERROR}: " + obj["error"]; + e.innerHTML = "{#ERROR}: " + getErrStr(obj.error); } function updatePwrAck(obj) { diff --git a/src/web/lang.h b/src/web/lang.h index 1e066928..fb5506ee 100644 --- a/src/web/lang.h +++ b/src/web/lang.h @@ -24,36 +24,6 @@ #define WAS_IN_CH_12_TO_14 "Your ESP was in wifi channel 12 to 14. It may cause reboots of your AhoyDTU" #endif -#ifdef LANG_DE - #define INV_INDEX_INVALID "Wechselrichterindex ungültig; " -#else /*LANG_EN*/ - #define INV_INDEX_INVALID "inverter index invalid: " -#endif - -#ifdef LANG_DE - #define AUTH_ERROR "Authentifizierungsfehler" -#else /*LANG_EN*/ - #define AUTH_ERROR "authentication error" -#endif - -#ifdef LANG_DE - #define UNKNOWN_CMD "unbekanntes Kommando: '" -#else /*LANG_EN*/ - #define UNKNOWN_CMD "unknown cmd: '" -#endif - -#ifdef LANG_DE - #define IS_PROTECTED "nicht angemeldet, Kommando nicht möglich!" -#else /*LANG_EN*/ - #define IS_PROTECTED "not logged in, command not possible!" -#endif - -#ifdef LANG_DE - #define INV_DOES_NOT_ACCEPT_LIMIT_AT_MOMENT "Leistungsbegrenzung / Ansteuerung aktuell nicht möglich" -#else /*LANG_EN*/ - #define INV_DOES_NOT_ACCEPT_LIMIT_AT_MOMENT "inverter does not accept dev control request at this moment" -#endif - #ifdef LANG_DE #define PATH_NOT_FOUND "Pfad nicht gefunden: " #else /*LANG_EN*/ diff --git a/src/web/lang.json b/src/web/lang.json index 1e79f8bf..335f0d2a 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -1432,6 +1432,31 @@ "token": "INV_ACK", "en": "inverter acknowledged active power control command", "de": "Wechselrichter hat die Leistungsbegrenzung akzeptiert" + }, + { + "token": "ERR_AUTH", + "en": "authentication error", + "de": "Authentifizierungsfehler" + }, + { + "token": "ERR_INDEX", + "en": "inverter index invalid", + "de": "Wechselrichterindex ungültig" + }, + { + "token": "ERR_UNKNOWN_CMD", + "en": "unknown cmd", + "de": "unbekanntes Kommando" + }, + { + "token": "ERR_LIMIT_NOT_ACCEPT", + "en": "inverter does not accept dev control request at this moment", + "de": "Leistungsbegrenzung / Ansteuerung aktuell nicht möglich" + }, + { + "token": "ERR_PROTECTED", + "en": "not logged in, command not possible!", + "de": "nicht angemeldet, Kommando nicht möglich!" } ] }, From 9d1147b3716f98856f4129f19bfeecb6bbd14c9a Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 13 Feb 2024 12:13:53 +0100 Subject: [PATCH 50/79] more gracefull handling of complete retransmits - Heuristics is less strict with complete retransmits - fix MI typo - new logic for MI alarms (not working correctly!) --- src/hm/Communication.h | 86 +++++++++++++++++++++++------------------- src/hm/Heuristic.h | 8 +++- src/hm/hmRadio.h | 4 +- 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index a37bcdb2..8c7fbe6d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -276,7 +276,7 @@ class Communication : public CommQueue<> { DBGPRINT(F(" frames missing ")); DBGPRINTLN(F("-> complete retransmit")); } - mHeu.evalTxChQuality(q->iv, false, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); + mHeu.evalTxChQuality(q->iv, false, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt, true); q->iv->radioStatistics.txCnt--; q->iv->radioStatistics.retransmits++; mCompleteRetry = true; @@ -893,50 +893,60 @@ class Communication : public CommQueue<> { uint16_t prntsts = (statusMi == 3) ? 1 : statusMi; bool stsok = true; - if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? - q->iv->alarmCnt = 1; // minimum... + bool changedStatus = false; //if true, raise alarms and send via mqtt (might affect single channel only) + uint8_t oldState = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; + if ( prntsts != oldState ) { // sth.'s changed? stsok = false; - //sth is or was wrong? - if ((q->iv->type != INV_TYPE_1CH) - && ((statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (q->iv->lastAlarm[stschan].code != 1))) - ) { - q->iv->lastAlarm[stschan+q->iv->type==INV_TYPE_2CH ? 2: 4] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); - q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); - q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; - } else if ((q->iv->type == INV_TYPE_1CH) - && ( (statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (q->iv->lastAlarm[stschan].code != 1))) - ) { - q->iv->lastAlarm[stschan] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); - } else if (q->iv->type == INV_TYPE_1CH) - stsok = true; - - q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; - - if (q->iv->alarmCnt > 1) { //more than one channel - for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 - if (q->iv->lastAlarm[ch].code == 1) { - stsok = true; - break; + if(!oldState) { // initial zero value? => just write this channel to main state and raise changed flags + changedStatus = true; + q->iv->alarmCnt = 1; // minimum... + } else { + //sth is or was wrong? + if (q->iv->type == INV_TYPE_1CH) { + changedStatus = true; + if(q->iv->alarmCnt == 2) // we had sth. other than "producing" in the past + q->iv->lastAlarm[1].end = q->ts; + else { // copy old state and mark as ended + q->iv->lastAlarm[1] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); + q->iv->alarmCnt = 2; + } + } else if((prntsts != 1) || (q->iv->alarmCnt > 1) ) { // we had sth. other than "producing" in the past in at least one channel (2 and 4 ch types) + if (q->iv->alarmCnt == 1) + q->iv->alarmCnt = (q->iv->type == INV_TYPE_2CH) ? 5 : 9; + if(q->iv->lastAlarm[stschan].code != prntsts) { // changed? + changedStatus = true; + if(q->iv->lastAlarm[stschan].code) // copy old data and mark as ended (if any) + q->iv->lastAlarm[(stschan + (q->iv->type==INV_TYPE_2CH ? 2 : 4))] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); + q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); + } + if(changedStatus) { + for (uint8_t i = 1; i <= q->iv->channels; i++) { //start with 1 + if (q->iv->lastAlarm[i].code == 1) { + stsok = true; + break; + } + } } } } - if(*mSerialDebug) { - DPRINT(DBG_WARN, F("New state on CH")); - DBGPRINT(String(stschan)); DBGPRINT(F(" (")); - DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); - DBGPRINTLN(q->iv->getAlarmStr(prntsts)); - } - if(!q->iv->miMultiParts) - q->iv->miMultiParts = 1; // indicate we got status info (1+2 ch types) } if (!stsok) { q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); + } + if (changedStatus || !stsok) { rec->ts = q->ts; rec->mqttSentStatus = MqttSentStatus::NEW_DATA; + q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; + if (NULL != mCbAlarm) + (mCbAlarm)(q->iv); + if(*mSerialDebug) { + DPRINT(DBG_WARN, F("New state on CH")); + DBGPRINT(String(stschan)); DBGPRINT(F(" (")); + DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); + DBGPRINTLN(q->iv->getAlarmStr(prntsts)); + } } if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { @@ -947,6 +957,8 @@ class Communication : public CommQueue<> { DBGPRINTLN(String(q->iv->alarmMesIndex)); } } + if(!q->iv->miMultiParts) + q->iv->miMultiParts = 1; // indicate we got status info (1+2 ch types) } @@ -986,10 +998,8 @@ class Communication : public CommQueue<> { ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); } else { for(uint8_t i = 1; i <= iv->channels; i++) { - if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { - uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); - ac_pow += iv->getValue(pos, rec); - } + if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) + ac_pow += iv->getValue(iv->getPosByChFld(i, FLD_PDC, rec), rec); } } ac_pow = (int) (ac_pow*9.5); diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index ecf82aa7..cc42df4f 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -38,6 +38,8 @@ class Heuristic { ih->txRfChId = curId; curId = (curId + 1) % RF_MAX_CHANNEL_ID; } + if(ih->txRfQuality[ih->txRfChId] == RF_MIN_QUALTIY) // all channels are bad, reset... + ih->clear(); if(ih->testPeriodSendCnt < 0xff) ih->testPeriodSendCnt++; @@ -71,7 +73,7 @@ class Heuristic { return id2Ch(ih->txRfChId); } - void evalTxChQuality(Inverter<> *iv, bool crcPass, uint8_t retransmits, uint8_t rxFragments) { + void evalTxChQuality(Inverter<> *iv, bool crcPass, uint8_t retransmits, uint8_t rxFragments, bool quotaMissed = false) { HeuristicInv *ih = &iv->heuristics; #if (DBG_DEBUG == DEBUG_LEVEL) @@ -84,8 +86,10 @@ class Heuristic { DBGPRINT(", "); DBGPRINTLN(String(ih->lastRxFragments)); #endif + if(quotaMissed) // we got not enough frames on this attempt, but iv was answering + updateQuality(ih, (rxFragments > 3 ? RF_TX_CHAN_QUALITY_GOOD : (rxFragments > 1 ? RF_TX_CHAN_QUALITY_OK : RF_TX_CHAN_QUALITY_LOW))); - if(ih->lastRxFragments == rxFragments) { + else if(ih->lastRxFragments == rxFragments) { if(crcPass) updateQuality(ih, RF_TX_CHAN_QUALITY_GOOD); else if(!retransmits || isNewTxCh(ih)) { // nothing received: send probably lost diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d1d24364..eb44dd8c 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -77,7 +77,7 @@ class HmRadio : public Radio { #else mNrf24->begin(mSpi.get(), ce, cs); #endif - mNrf24->setRetries(3, 9); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms + mNrf24->setRetries(3, 15); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms mNrf24->setDataRate(RF24_250KBPS); //mNrf24->setAutoAck(true); // enabled by default @@ -159,7 +159,7 @@ class HmRadio : public Radio { mTimeslotStart = millis(); tempRxChIdx = mRxChIdx; // might be better to start off with one channel less? mRxPendular = false; - mNRFloopChannels = (mLastIv->mCmd == MI_REQ_CH1); + mNRFloopChannels = (mLastIv->mCmd == MI_REQ_CH1 || mLastIv->mCmd == MI_REQ_CH2); innerLoopTimeout = DURATION_LISTEN_MIN; } From bd532805a66f64bae723b5a62f38668e84b7fb34 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 13 Feb 2024 23:46:15 +0100 Subject: [PATCH 51/79] 0.8.81 * fixed authentication with empty token #1415 * added new setting for future function to send log via MqTT * combined firmware and hardware version to JSON topics (MqTT) #1212 --- src/CHANGES.md | 5 +++ src/config/settings.h | 9 ++++- src/defines.h | 2 +- src/publisher/pubMqttIvData.h | 59 +++++++++++++++++++--------- src/web/Protection.h | 2 +- src/web/RestApi.h | 1 + src/web/html/setup.html | 73 +++++++++++++---------------------- src/web/lang.json | 5 +++ src/web/web.h | 1 + 9 files changed, 90 insertions(+), 67 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 714dc8cc..f39a5640 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.81 - 2024-02-13 +* fixed authentication with empty token #1415 +* added new setting for future function to send log via MqTT +* combined firmware and hardware version to JSON topics (MqTT) #1212 + ## 0.8.80 - 2024-02-12 * optimize API authentication, Error-Codes #1415 * breaking change: authentication API command changed #1415 diff --git a/src/config/settings.h b/src/config/settings.h index 0cb9ed4e..18725b48 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -31,7 +31,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 10 +#define CONFIG_VERSION 11 #define PROT_MASK_INDEX 0x0001 @@ -120,6 +120,7 @@ typedef struct { bool debug; bool privacyLog; bool printWholeTrace; + bool log2mqtt; } cfgSerial_t; typedef struct { @@ -436,6 +437,7 @@ class settings { mCfg.serial.debug = false; mCfg.serial.privacyLog = true; mCfg.serial.printWholeTrace = false; + mCfg.serial.log2mqtt = false; mCfg.mqtt.port = DEF_MQTT_PORT; snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER); @@ -509,6 +511,9 @@ class settings { mCfg.sys.region = 0; // Europe mCfg.sys.timezone = 1; } + if(mCfg.configVersion < 11) { + mCfg.serial.log2mqtt = false; + } } } @@ -658,11 +663,13 @@ class settings { obj[F("debug")] = mCfg.serial.debug; obj[F("prv")] = (bool) mCfg.serial.privacyLog; obj[F("trc")] = (bool) mCfg.serial.printWholeTrace; + obj[F("mqtt")] = (bool) mCfg.serial.log2mqtt; } else { getVal(obj, F("show"), &mCfg.serial.showIv); getVal(obj, F("debug"), &mCfg.serial.debug); getVal(obj, F("prv"), &mCfg.serial.privacyLog); getVal(obj, F("trc"), &mCfg.serial.printWholeTrace); + getVal(obj, F("mqtt"), &mCfg.serial.log2mqtt); } } diff --git a/src/defines.h b/src/defines.h index 8913db5e..200c2561 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 80 +#define VERSION_PATCH 81 //------------------------------------- typedef struct { diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 06f8e629..c430da85 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -6,6 +6,7 @@ #ifndef __PUB_MQTT_IV_DATA_H__ #define __PUB_MQTT_IV_DATA_H__ +#include #include "../utils/dbg.h" #include "../hm/hmSystem.h" #include "pubMqttDefs.h" @@ -107,14 +108,14 @@ class PubMqttIvData { if(found) { record_t<> *rec = mIv->getRecordStruct(mCmd); if(MqttSentStatus::NEW_DATA == rec->mqttSentStatus) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/last_success", mIv->config->name); - snprintf(mVal, 40, "%d", mIv->getLastTs(rec)); - mPublish(mSubTopic, mVal, true, QOS_0); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/last_success", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", mIv->getLastTs(rec)); + mPublish(mSubTopic.data(), mVal.data(), true, QOS_0); if((mIv->ivGen == IV_HMS) || (mIv->ivGen == IV_HMT)) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch0/rssi", mIv->config->name); - snprintf(mVal, 40, "%d", mIv->rssi); - mPublish(mSubTopic, mVal, false, QOS_0); + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch0/rssi", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "%d", mIv->rssi); + mPublish(mSubTopic.data(), mVal.data(), false, QOS_0); } rec->mqttSentStatus = MqttSentStatus::LAST_SUCCESS_SENT; } @@ -144,7 +145,7 @@ class PubMqttIvData { if(mPos < rec->length) { bool retained = false; - if (mCmd == RealTimeRunData_Debug) { + if (RealTimeRunData_Debug == mCmd) { if((FLD_YT == rec->assign[mPos].fieldId) || (FLD_YD == rec->assign[mPos].fieldId)) retained = true; @@ -176,10 +177,32 @@ class PubMqttIvData { } if (MqttSentStatus::LAST_SUCCESS_SENT == rec->mqttSentStatus) { + if(InverterDevInform_All == mCmd) { + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/firmware", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "{\"version\":%d,\"build_year\":\"%s\",\"build_month_day\":%d,\"build_hour_min\":%d,\"bootloader\":%d}", + mIv->getChannelFieldValue(CH0, FLD_FW_VERSION, rec), + mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_YEAR, rec), + mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_MONTH_DAY, rec), + mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec), + mIv->getChannelFieldValue(CH0, FLD_BOOTLOADER_VER, rec)); + retained = true; + } else if(InverterDevInform_Simple == mCmd) { + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/hardware", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "{\"part\":%d,\"version\":\"%s\",\"grid_profile_code\":%d,\"grid_profile_version\":%d}", + mIv->getChannelFieldValue(CH0, FLD_PART_NUM, rec), + mIv->getChannelFieldValue(CH0, FLD_HW_VERSION, rec), + mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec), + mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec)); + retained = true; + } else { + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]); + snprintf(mVal.data(), mVal.size(), "%g", ah::round3(mIv->getValue(mPos, rec))); + } + uint8_t qos = (FLD_ACT_ACTIVE_PWR_LIMIT == rec->assign[mPos].fieldId) ? QOS_2 : QOS_0; - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]); - snprintf(mVal, 40, "%g", ah::round3(mIv->getValue(mPos, rec))); - mPublish(mSubTopic, mVal, retained, qos); + if((FLD_EVT != rec->assign[mPos].fieldId) + && (FLD_LAST_ALARM_CODE != rec->assign[mPos].fieldId)) + mPublish(mSubTopic.data(), mVal.data(), retained, qos); } mPos++; } else { @@ -192,8 +215,8 @@ class PubMqttIvData { } inline void sendRadioStat(uint8_t start) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/radio_stat", mIv->config->name); - snprintf(mVal, 140, "{\"tx\":%d,\"success\":%d,\"fail\":%d,\"no_answer\":%d,\"retransmits\":%d,\"lossIvRx\":%d,\"lossIvTx\":%d,\"lossDtuRx\":%d,\"lossDtuTx\":%d}", + snprintf(mSubTopic.data(), mSubTopic.size(), "%s/radio_stat", mIv->config->name); + snprintf(mVal.data(), mVal.size(), "{\"tx\":%d,\"success\":%d,\"fail\":%d,\"no_answer\":%d,\"retransmits\":%d,\"lossIvRx\":%d,\"lossIvTx\":%d,\"lossDtuRx\":%d,\"lossDtuTx\":%d}", mIv->radioStatistics.txCnt, mIv->radioStatistics.rxSuccess, mIv->radioStatistics.rxFail, @@ -203,7 +226,7 @@ class PubMqttIvData { mIv->radioStatistics.ivSent, mIv->radioStatistics.dtuLoss, mIv->radioStatistics.dtuSent); - mPublish(mSubTopic, mVal, false, QOS_0); + mPublish(mSubTopic.data(), mVal.data(), false, QOS_0); } void stateSendTotals() { @@ -240,9 +263,9 @@ class PubMqttIvData { retained = false; break; } - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); - snprintf(mVal, 40, "%g", ah::round3(mTotal[mPos])); - mPublish(mSubTopic, mVal, retained, QOS_0); + snprintf(mSubTopic.data(), mSubTopic.size(), "total/%s", fields[fieldId]); + snprintf(mVal.data(), mVal.size(), "%g", ah::round3(mTotal[mPos])); + mPublish(mSubTopic.data(), mVal.data(), retained, QOS_0); mPos++; } else { mSendList->pop(); @@ -266,8 +289,8 @@ class PubMqttIvData { uint8_t mPos = 0; bool mRTRDataHasBeenSent = false; - char mSubTopic[32 + MAX_NAME_LENGTH + 1]; - char mVal[140]; + std::array mSubTopic; + std::array mVal; std::queue *mSendList = nullptr; }; diff --git a/src/web/Protection.h b/src/web/Protection.h index 82e4be49..74f04b52 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -85,7 +85,7 @@ class Protection { if(isIdentical(clientIp, mApiIp)) return (0 != strncmp(token, mToken.data(), 16)); - return false; + return true; } private: diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 37e988c0..09bba06e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -680,6 +680,7 @@ class RestApi { obj[F("debug")] = mConfig->serial.debug; obj[F("priv")] = mConfig->serial.privacyLog; obj[F("wholeTrace")] = mConfig->serial.printWholeTrace; + obj[F("log2mqtt")] = mConfig->serial.log2mqtt; } void getStaticIp(JsonObject obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 4859fe34..47d935b9 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -43,24 +43,8 @@
-
+
{#SERIAL_CONSOLE} -
-
{#LOG_PRINT_INVERTER_DATA}
-
-
-
-
{#LOG_SERIAL_DEBUG}
-
-
-
-
{#LOG_PRIVACY_MODE}
-
-
-
-
{#LOG_PRINT_TRACES}
-
-
@@ -716,6 +700,13 @@ ivGlob(obj); } + function divRow(item0, item1) { + return ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-3 mt-2"}, item0), + ml("div", {class: "col-9"}, item1) + ]) + } + function ivModal(obj) { var lines = []; lines.push(ml("tr", {}, [ @@ -743,43 +734,23 @@ var html = ml("div", {}, [ tabs(["{#TAB_GENERAL}", "{#TAB_INPUTS}", "{#TAB_RADIO}", "{#TAB_ADVANCED}"]), ml("div", {id: "div{#TAB_GENERAL}", class: "tab-content"}, [ - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-2"}, "{#INV_ENABLE}"), - ml("div", {class: "col-10"}, cbEn) - ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-2 mt-2"}, "{#INV_SERIAL}"), - ml("div", {class: "col-10"}, ser) - ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-2 mt-2"}, "Name"), - ml("div", {class: "col-10"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) - ]) + divRow("{#INV_ENABLE}", cbEn), + divRow("{#INV_SERIAL}", ser), + divRow("Name", ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) ]), ml("div", {id: "div{#TAB_INPUTS}", class: "tab-content hide"}, [ ml("div", {class: "row mb-3"}, - ml("table", {class: "table"}, - ml("tbody", {}, lines) - ) + ml("table", {class: "table"}, ml("tbody", {}, lines)) ) ]), ml("div", {id: "div{#TAB_RADIO}", class: "tab-content hide"}, [ ml("input", {type: "hidden", name: "isnrf"}, null), ml("div", {id: "setcmt"}, [ - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-3 mt-2"}, "{#INV_FREQUENCY}"), - ml("div", {class: "col-9"}, sel("freq", esp32cmtFreq, obj.freq)) - ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-3 mt-2"}, "{#INV_POWER_LEVEL}"), - ml("div", {class: "col-9"}, sel("cmtpa", esp32cmtPa, obj.pa)) - ]), + divRow("{#INV_FREQUENCY}", sel("freq", esp32cmtFreq, obj.freq)), + divRow("{#INV_POWER_LEVEL}", sel("cmtpa", esp32cmtPa, obj.pa)) ]), ml("div", {id: "setnrf"}, - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-3 mt-2"}, "{#INV_POWER_LEVEL}"), - ml("div", {class: "col-9"}, sel("nrfpa", nrfPa, obj.pa)) - ]), + divRow("{#INV_POWER_LEVEL}", sel("nrfpa", nrfPa, obj.pa)) ), ]), ml("div", {id: "div{#TAB_ADVANCED}", class: "tab-content hide"}, [ @@ -1026,8 +997,18 @@ /*ENDIF_ESP32*/ function parseSerial(obj) { - for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"], ["priv", "priv"], ["wholeTrace", "wholeTrace"]]) - document.getElementsByName(i[0])[0].checked = obj[i[1]]; + var e = document.getElementById("serialCb") + var l = [["serEn", "show_live_data", "{#LOG_PRINT_INVERTER_DATA}"], ["serDbg", "debug", "{#LOG_SERIAL_DEBUG}"], ["priv", "priv", "{#LOG_PRIVACY_MODE}"], ["wholeTrace", "wholeTrace", "{#LOG_PRINT_TRACES}"], ["log2mqtt", "log2mqtt", "{#LOG_TO_MQTT}"]] + for(var i of l) { + var cb = ml("input", {name: i[0], type: "checkbox"}, null) + cb.checked = obj[i[1]] + e.appendChild( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-8 col-sm-3"}, i[2]), + ml("div", {class: "col-4 col-sm-9"}, cb) + ]) + ) + } } function parseDisplay(obj, type, system) { diff --git a/src/web/lang.json b/src/web/lang.json index 335f0d2a..066370c5 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -203,6 +203,11 @@ "en": "Print whole traces in Log", "de": "alle Informationen in Log schreiben" }, + { + "token": "LOG_TO_MQTT", + "en": "Send Serial debug over MqTT", + "de": "sende serielles Log über MqTT" + }, { "token": "NETWORK", "en": "Network", diff --git a/src/web/web.h b/src/web/web.h index 692dd779..8495ba23 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -552,6 +552,7 @@ class Web { mConfig->serial.privacyLog = (request->arg("priv") == "on"); mConfig->serial.printWholeTrace = (request->arg("wholeTrace") == "on"); mConfig->serial.showIv = (request->arg("serEn") == "on"); + mConfig->serial.log2mqtt = (request->arg("log2mqtt") == "on"); // display mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on"); From 8c132048e678201100bba964805e2ef86fe5364c Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 15 Feb 2024 23:22:24 +0100 Subject: [PATCH 52/79] 0.8.82 * fixed crash once firmware version was read and sent via MqTT #1428 * possible fix: reset yield offset on midnight #1429 --- src/CHANGES.md | 4 ++++ src/app.cpp | 3 +-- src/defines.h | 2 +- src/hm/hmInverter.h | 20 ++++++++++---------- src/publisher/pubMqttIvData.h | 22 +++++++++++----------- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f39a5640..75fede55 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.82 - 2024-02-15 +* fixed crash once firmware version was read and sent via MqTT #1428 +* possible fix: reset yield offset on midnight #1429 + ## 0.8.81 - 2024-02-13 * fixed authentication with empty token #1415 * added new setting for future function to send log via MqTT diff --git a/src/app.cpp b/src/app.cpp index bee12387..0bead49e 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -466,8 +466,6 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { continue; // skip to next inverter if (!iv->config->enabled) continue; // skip to next inverter - if (iv->commEnabled) - continue; // skip to next inverter if (checkAvail) { if (!iv->isAvailable()) @@ -495,6 +493,7 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { pos = iv->getPosByChFld(ch, FLD_MP, rec); iv->setValue(pos, rec, 0.0f); } + iv->resetAlarms(); iv->doCalculations(); } diff --git a/src/defines.h b/src/defines.h index 200c2561..68094ba3 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 81 +#define VERSION_PATCH 82 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index f608908e..50b4267c 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -149,9 +149,6 @@ class Inverter { uint32_t tsMaxAcPower = 0; // holds the timestamp when the MaxAC power was seen bool commEnabled = true; // 'pause night communication' sets this field to false - static uint32_t *timestamp; // system timestamp - static cfgInst_t *generalConfig; // general inverter configuration from setup - public: Inverter() { @@ -826,20 +823,23 @@ class Inverter { radioId.b[0] = 0x01; } - private: - float mOffYD[6], mLastYD[6]; - bool mDevControlRequest = false; // true if change needed - uint8_t mGridLen = 0; - std::array mGridProfile; - uint8_t mAlarmNxtWrPos = 0; // indicates the position in array (rolling buffer) - public: + static uint32_t *timestamp; // system timestamp + static cfgInst_t *generalConfig; // general inverter configuration from setup + uint16_t mDtuRxCnt = 0; uint16_t mDtuTxCnt = 0; uint8_t mGetLossInterval = 0; // request iv every AHOY_GET_LOSS_INTERVAL RealTimeRunData_Debug uint16_t mIvRxCnt = 0; uint16_t mIvTxCnt = 0; uint16_t mAckCount = 0; + + private: + float mOffYD[6], mLastYD[6]; + bool mDevControlRequest = false; // true if change needed + uint8_t mGridLen = 0; + std::array mGridProfile; + uint8_t mAlarmNxtWrPos = 0; // indicates the position in array (rolling buffer) }; template diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index c430da85..c3ae3814 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -179,20 +179,20 @@ class PubMqttIvData { if (MqttSentStatus::LAST_SUCCESS_SENT == rec->mqttSentStatus) { if(InverterDevInform_All == mCmd) { snprintf(mSubTopic.data(), mSubTopic.size(), "%s/firmware", mIv->config->name); - snprintf(mVal.data(), mVal.size(), "{\"version\":%d,\"build_year\":\"%s\",\"build_month_day\":%d,\"build_hour_min\":%d,\"bootloader\":%d}", - mIv->getChannelFieldValue(CH0, FLD_FW_VERSION, rec), - mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_YEAR, rec), - mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_MONTH_DAY, rec), - mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec), - mIv->getChannelFieldValue(CH0, FLD_BOOTLOADER_VER, rec)); + snprintf(mVal.data(), mVal.size(), "{\"version\":%d,\"build_year\":\"%d\",\"build_month_day\":%d,\"build_hour_min\":%d,\"bootloader\":%d}", + static_cast(mIv->getChannelFieldValue(CH0, FLD_FW_VERSION, rec)), + static_cast(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_YEAR, rec)), + static_cast(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_MONTH_DAY, rec)), + static_cast(mIv->getChannelFieldValue(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec)), + static_cast(mIv->getChannelFieldValue(CH0, FLD_BOOTLOADER_VER, rec))); retained = true; } else if(InverterDevInform_Simple == mCmd) { snprintf(mSubTopic.data(), mSubTopic.size(), "%s/hardware", mIv->config->name); - snprintf(mVal.data(), mVal.size(), "{\"part\":%d,\"version\":\"%s\",\"grid_profile_code\":%d,\"grid_profile_version\":%d}", - mIv->getChannelFieldValue(CH0, FLD_PART_NUM, rec), - mIv->getChannelFieldValue(CH0, FLD_HW_VERSION, rec), - mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec), - mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec)); + snprintf(mVal.data(), mVal.size(), "{\"part\":%d,\"version\":\"%d\",\"grid_profile_code\":%d,\"grid_profile_version\":%d}", + static_cast(mIv->getChannelFieldValue(CH0, FLD_PART_NUM, rec)), + static_cast(mIv->getChannelFieldValue(CH0, FLD_HW_VERSION, rec)), + static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec)), + static_cast(mIv->getChannelFieldValue(CH0, FLD_GRID_PROFILE_VERSION, rec))); retained = true; } else { snprintf(mSubTopic.data(), mSubTopic.size(), "%s/ch%d/%s", mIv->config->name, rec->assign[mPos].ch, fields[rec->assign[mPos].fieldId]); From 024445b472005fbe7e71d847abb675053f1fd554 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 17 Feb 2024 00:26:24 +0100 Subject: [PATCH 53/79] 0.8.83 release * updated workflows --- .github/workflows/compile_development.yml | 9 +- .github/workflows/compile_release.yml | 150 ++- src/CHANGES.md | 1295 +-------------------- src/defines.h | 2 +- 4 files changed, 148 insertions(+), 1308 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 66dbf74b..c15bd883 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -1,4 +1,4 @@ -name: Ahoy Dev-Build for ESP8266/ESP32 +name: Ahoy Development on: push: @@ -8,6 +8,7 @@ on: jobs: check: + name: Check Repository runs-on: ubuntu-latest if: github.repository == 'lumapu/ahoy' && github.ref_name == 'development03' continue-on-error: true @@ -15,6 +16,7 @@ jobs: - uses: actions/checkout@v4 build-en: + name: Build Environments (English) needs: check runs-on: ubuntu-latest continue-on-error: true @@ -75,6 +77,7 @@ jobs: path: firmware/* build-de: + name: Build Environments (German) needs: check runs-on: ubuntu-latest continue-on-error: true @@ -135,8 +138,10 @@ jobs: path: firmware/* deploy: + name: Deploy Environments needs: [build-en, build-de] runs-on: ubuntu-latest + continue-on-error: false steps: - uses: actions/checkout@v4 #- name: Copy boot_app0.bin @@ -155,7 +160,7 @@ jobs: - name: Set Version uses: cschleiden/replace-tokens@v1 with: - files: tools/esp8266/User_Manual.md + files: manual/User_Manual.md env: VERSION: ${{ steps.version_name.outputs.name }} diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index a7e3511d..bf9709a0 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -1,29 +1,50 @@ -name: Ahoy Release for ESP8266/ESP32 +name: Ahoy Release on: push: branches: main - paths: - - 'src/**' # build only when changes occur here - - '.github/workflows/compile_release.yml' - - '!README.md' - - '!CHANGES.md' - - '!User_Manual.md' + paths-ignore: + - '**.md' # Do no build on *.md changes + jobs: build: + name: Build Environments + needs: check runs-on: ubuntu-latest - + if: github.repository == 'lumapu/ahoy' && github.ref_name == 'main' + continue-on-error: false + strategy: + matrix: + variant: + - esp8266 + - esp8266-prometheus + - esp8285 + - esp32-wroom32 + - esp32-wroom32-prometheus + - esp32-wroom32-ethernet + - esp32-s2-mini + - esp32-c3-mini + - opendtufusion + - opendtufusion-ethernet + - esp8266-de + - esp8266-prometheus-de + - esp8285-de + - esp32-wroom32-de + - esp32-wroom32-prometheus-de + - esp32-wroom32-ethernet-de + - esp32-s2-mini-de + - esp32-c3-mini-de + - opendtufusion-de + - opendtufusion-ethernet-de steps: - - uses: actions/checkout@v3 - with: - ref: main - - uses: benjlevesque/short-sha@v2.1 + - uses: actions/checkout@v4 + - uses: benjlevesque/short-sha@v3.0 id: short-sha with: length: 7 - name: Cache Pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} @@ -31,13 +52,13 @@ jobs: ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - name: Setup Python - uses: actions/setup-python@v4.3.0 + uses: actions/setup-python@v5 with: python-version: "3.x" @@ -47,58 +68,91 @@ jobs: pip install --upgrade platformio - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment esp32-c3-mini --environment opendtufusion --environment opendtufusion-ethernet + run: pio run -d src -e ${{ matrix.variant }} - - name: Copy boot_app0.bin - run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin + - name: Rename Firmware + run: python scripts/getVersion.py ${{ matrix.variant }} >> $GITHUB_OUTPUT + + - name: Create Artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.variant }} + path: firmware/* - - name: Rename Binary files - id: rename-binary-files - working-directory: src - run: python ../scripts/getVersion.py >> $GITHUB_OUTPUT - - name: Create Release - id: create-release - uses: actions/create-release@v1 + release: + name: Create Release + runs-on: ubuntu-latest + needs: [build] + continue-on-error: false + permissions: + contents: write + + steps: + - name: Get Artifacts + uses: actions/download-artifact@v4 with: - draft: false - prerelease: false - release_name: ${{ steps.rename-binary-files.outputs.name }} - tag_name: ${{ steps.rename-binary-files.outputs.name }} - body_path: src/CHANGES.md - env: - GITHUB_TOKEN: ${{ github.token }} + merge-multiple: true + path: firmware + + - name: Get Version from code + id: version_name + run: python scripts/getVersion.py ${{ matrix.variant }} >> $GITHUB_OUTPUT - name: Set Version uses: cschleiden/replace-tokens@v1 with: - files: User_Manual.md + files: manual/User_Manual.md env: - VERSION: ${{ steps.rename-binary-files.outputs.name }} + VERSION: ${{ steps.version_name.outputs.name }} - - name: Create Artifact - run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip src/firmware/* User_Manual.md + - name: Rename firmware directory + run: mv firmware ${{ steps.version_name.outputs.name }} - - name: Upload Release - id: upload-release - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Publish Release + uses: actions/checkout@v3 + uses: ncipollo/release-action@v1 + with: + artifacts: ${{ steps.version_name.outputs.name }} + bodyFile: src/CHANGES.md + commit: "main" + tag: ${{ steps.rename-binary-files.outputs.name }} + name: ${{ steps.rename-binary-files.outputs.name }} + + + deploy: + name: Deploy Environments to fw.ahoydtu.de + needs: [build] + runs-on: ubuntu-latest + continue-on-error: false + steps: + - uses: actions/checkout@v4 + - name: Get Artifacts + uses: actions/download-artifact@v4 with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: ./${{ steps.rename-binary-files.outputs.name }}.zip - asset_name: ${{ steps.rename-binary-files.outputs.name }}.zip - asset_content_type: application/zip + merge-multiple: true + path: firmware + + - name: Get Version from code + id: version_name + run: python scripts/getVersion.py ${{ matrix.variant }} >> $GITHUB_OUTPUT + + - name: Set Version + uses: cschleiden/replace-tokens@v1 + with: + files: manual/User_Manual.md + env: + VERSION: ${{ steps.version_name.outputs.name }} - name: Rename firmware directory - run: mv src/firmware src/${{ steps.rename-binary-files.outputs.name }} + run: mv firmware ${{ steps.version_name.outputs.name }} - name: Deploy uses: nogsantos/scp-deploy@master with: - src: src/${{ steps.rename-binary-files.outputs.name }}/ + src: ${{ steps.version_name.outputs.name }}/ host: ${{ secrets.FW_SSH_HOST }} - remote: ${{ secrets.FW_SSH_DIR }}/release + remote: ${{ secrets.FW_SSH_DIR }}/dev port: ${{ secrets.FW_SSH_PORT }} user: ${{ secrets.FW_SSH_USER }} key: ${{ secrets.FW_SSH_KEY }} diff --git a/src/CHANGES.md b/src/CHANGES.md index 75fede55..5fd4fc31 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,1260 +1,41 @@ -# Development Changes +Changelog v0.8.83 -## 0.8.82 - 2024-02-15 -* fixed crash once firmware version was read and sent via MqTT #1428 -* possible fix: reset yield offset on midnight #1429 - -## 0.8.81 - 2024-02-13 -* fixed authentication with empty token #1415 -* added new setting for future function to send log via MqTT -* combined firmware and hardware version to JSON topics (MqTT) #1212 - -## 0.8.80 - 2024-02-12 -* optimize API authentication, Error-Codes #1415 -* breaking change: authentication API command changed #1415 -* breaking change: limit has to be send als `float`, `0.0 .. 100.0` #1415 -* updated documentation #1415 -* fix don't send control command twice #1426 - -## 0.8.79 - 2024-02-11 -* fix `opendtufusion` build (started only once USB-console was connected) -* code quality improvments - -## 0.8.78 - 2024-02-10 -* finalized API token access #1415 -* possible fix of MqTT fix "total values are sent to often" #1421 -* removed `switchCycle` from `hmsRadio.h` #1412 -* merge PR: Add hint to INV_RESET_MIDNIGHT resp. INV_PAUSE_DURING_NIGHT #1418 -* merge PR: simplify rxOffset logic #1417 -* code quality improvments - -## 0.8.77 - 2024-02-08 -* merge PR: BugFix: ACK #1414 -* fix suspicious if condition #1416 -* prepared API token for access, not functional #1415 - -## 0.8.76 - 2024-02-07 -* revert changes from yesterday regarding snprintf and its size #1410, #1411 -* reduced cppcheck linter warnings significantly -* try to improve ePaper (ghosting) #1107 - -## 0.8.75 - 2024-02-06 -* fix active power control value #1406, #1409 -* update Mqtt lib to version `1.6.0` -* take care of null terminator of chars #1410, #1411 - -## 0.8.74 - 2024-02-05 -* reduced cppcheck linter warnings significantly - -## 0.8.73 - 2024-02-03 -* fix nullpointer during communication #1401 -* added `max_power` to MqTT total values #1375 - -## 0.8.72 - 2024-02-03 -* fixed translation #1403 -* fixed sending commands to inverters which are soft turned off #1397 -* reduce switchChannel command for HMS (only each 5th cycle it will be send now) - -## 0.8.71 - 2024-02-03 -* fix heuristics reset -* fix CMT missing frames problem -* removed inverter gap setting -* removed add to total (MqTT) inverter setting -* fixed sending commands to inverters which are soft turned off -* save settings before they are exported #1395 -* fix autologin bug if no password is set -* translated `/serial` -* removed "yield day" history - -## 0.8.70 - 2024-02-01 -* prevent sending commands to inverter which isn't active #1387 -* protect commands from popup in `/live` if password is set #1199 - -## 0.8.69 - 2024-01-31 -* merge PR: Dynamic retries, pendular first rx chan #1394 - -## 0.8.68 - 2024-01-29 -* fix HMS / HMT startup -* added `flush_rx` to NRF on TX -* start with heuristics set to `0` -* added warning for WiFi channel 12-14 (ESP8266 only) #1381 - -## 0.8.67 - 2024-01-29 -* fix HMS frequency -* fix display of inverter id in serial log (was displayed twice) - -## 0.8.66 - 2024-01-28 -* added support for other regions - untested #1271 -* fix generation of DTU-ID; was computed twice without reset if two radios are enabled - -## 0.8.65 - 2024-01-24 -* removed patch for NRF `PLOS` -* fix lang issues #1388 -* fix build on Windows of `opendtufusion` environments (git: trailing whitespaces) - -## 0.8.64 - 2024-01-22 -* add `ARC` to log (NRF24 Debug) -* merge PR: ETH NTP update bugfix #1385 - -## 0.8.63 - 2024-01-22 -* made code review -* fixed endless loop #1387 - -## 0.8.62 - 2024-01-21 -* updated version in footer #1381 -* repaired radio statistics #1382 - -## 0.8.61 - 2024-01-21 -* add favicon to header -* improved NRF communication -* merge PR: provide localized times to display mono classes #1376 -* merge PR: Bypass OOM-Crash on minimal version & history access #1378 -* merge PR: Add some REST Api Endpoints to avail_endpoints #1380 - -## 0.8.60 - 2024-01-20 -* merge PR: non blocking nRF loop #1371 -* merge PR: fixed millis in serial log #1373 -* merge PR: fix powergraph scale #1374 -* changed inverter gap to `1` as default (old settings will be overridden) - -## 0.8.59 - 2024-01-18 -* merge PR: solve display settings dependencies #1369 -* fix language typos #1346 -* full update of ePaper after booting #1107 -* fix MqTT yield day reset even if `pause inverter during nighttime` isn't active #1368 - -## 0.8.58 - 2024-01-17 -* fix missing refresh URL #1366 -* fix view of grid profile #1365 -* fix webUI translation #1346 -* fix protection mask #1352 -* merge PR: Add Watchdog for ESP32 #1367 -* merge PR: ETH support for CMT2300A - HMS/HMT #1356 -* full refresh of ePaper after booting #1107 -* add optional custom link #1199 -* pinout has an own subgroup in `/settings` -* grid profile will be displayed as hex in every case #1199 - -## 0.8.57 - 2024-01-15 -* merge PR: fix immediate clearing of display after sunset #1364 -* merge PR: MI-MQTT and last retransmit #1363 -* fixed DTU-ID, now built from the unique part of the MAC -* fix lang in `/system` #1346 -* added protection to prevent update to wrong firmware (environment check) - -## 0.8.56 - 2024-01-15 -* potential fix of update problems and random reboots #1359 #1354 - -## 0.8.55 - 2024-01-14 -* merge PR: fix reboot problem with deactivated power graph #1360 -* changed scope of variables and member functions inside display classes -* removed automatically "minimal" builds -* fix include of "settings.h" (was already done in #1360) -* merge PR: Enhancement: Add info about compiled modules to version string #1357 -* add info about installed binary to `/update` #1353 -* fix lang in `/system` #1346 - -## 0.8.54 - 2024-01-13 -* added minimal version (without: MqTT, Display, History), WebUI is not changed! -* added simulator (must be activated before compile, standard: off) -* changed communication attempts back to 5 - -## 0.8.53 - 2024-01-12 -* fix history graph -* fix MqTT yield day #1331 - -## 0.8.52 - 2024-01-11 -* possible fix of 'division by zero' #1345 -* fix lang #1348 #1346 -* fix timestamp `max AC power` #1324 -* fix stylesheet overlay `max AC power` #1324 -* fix download link #1340 -* fix history graph -* try to fix #1331 - -## 0.8.51 - 2024-01-10 -* fix translation #1346 -* further improve sending active power control command faster #1332 -* added history protection mask -* merge PR: display graph improvements #1347 - -## 0.8.50 - 2024-01-09 -* merge PR: added history charts to web #1336 -* merge PR: small display changes #1339 -* merge PR: MI - add "get loss logic" #1341 -* translated `/history` -* fix translations in title of documents -* added translations for error messages #1343 - -## 0.8.49 - 2024-01-08 -* fix send total values if inverter state is different from `OFF` #1331 -* fix german language issues #1335 - -## 0.8.48 - 2024-01-07 -* merge PR: pin selection for ESP-32 S2 #1334 -* merge PR: enhancement: power graph display option #1330 - -## 0.8.47 - 2024-01-06 -* reduce GxEPD2 lib to compile faster -* upgraded GxEPD2 lib to `1.5.3` -* updated espressif32 platform to `6.5.0` -* updated U8g2 to `2.35.9` -* started to convert deprecated functions of new ArduinoJson `7.0.0` -* started to have german translations of all variants (environments) #925 #1199 -* merge PR: add defines for retry attempts #1329 - -## 0.8.46 - 2024-01-06 -* improved communication - -## 0.8.45 - 2024-01-05 -* fix MqTT total values #1326 -* start implementing a wizard for initial (WiFi) configuration #1199 - -## 0.8.44 - 2024-01-05 -* fix MqTT transmission of data #1326 -* live data is read much earlier / faster and more often #1272 - -## 0.8.43 - 2024-01-04 -* fix display of sunrise in `/system` #1308 -* fix overflow of `getLossRate` calculation #1318 -* improved MqTT by marking sent data and improved `last_success` resends #1319 -* added timestamp for `max ac power` as tooltip #1324 #1123 #1199 -* repaired Power-limit acknowledge #1322 -* fix `max_power` in `/visualization` was set to `0` after sunset - -## 0.8.42 - 2024-01-02 -* add LED to display whether it's night time or not. Can be reused as output to control battery system #1308 -* merge PR: beautifiying typography, added spaces between value and unit for `/visualization` #1314 -* merge PR: Prometheus add `getLossRate` and bugfixing #1315 -* add loss rate to `/visualization` in the statistics window -* corrected `getLossRate` infos for MqTT and prometheus +* added German translations for all variants +* added reading grid profile +* added decimal place for active power control (APC aka power limit) * added information about working IRQ for NRF24 and CMT2300A to `/system` +* added loss rate to `/visualization` in the statistics window and MqTT +* added optional output to display whether it's night time or not. Can be reused as output to control battery system or mapped to a LED +* added timestamp for `max ac power` as tooltip +* added wizard for initial WiFi connection +* added history graph (still under development) +* added simulator (must be activated before compile, standard: off) +* added minimal version (without: MqTT, Display, History), WebUI is not changed! (not compiled automatically) +* added info about installed binary to `/update` +* added protection to prevent update to wrong firmware (environment check) +* added optional custom link to the menu +* added support for other regions (USA, Indonesia) +* added warning for WiFi channel 12-14 (ESP8266 only) +* added `max_power` to MqTT total values +* added API-Token authentification for external scripts +* improved MqTT by marking sent data and improved `last_success` resends +* improved communication for HM and MI inverters +* improved reading live data from inverter +* improved sending active power control command faster +* improved `/settings`: pinout has an own subgroup +* improved export by saving settings before they are exported (to have everything in JSON) +* improved code quality (cppcheck) +* seperated sunrise and sunset offset to two fields +* fix MqTT night communication +* fix missing favicon to html header +* fix build on Windows of `opendtufusion` environments (git: trailing whitespaces) +* fix generation of DTU-ID +* fix: protect commands from popup in `/live` if password is set +* fix: prevent sending commands to inverter which isn't active +* combined firmware and hardware version to JSON topics (MqTT) +* updated Prometheus with latest changes +* upgraded most libraries to newer versions +* beautified typography, added spaces between value and unit for `/visualization` +* removed add to total (MqTT) inverter setting -## 0.8.41 - 2024-01-02 -* fix display timeout (OLED) to 60s -* change offs to signed value - -## 0.8.40 - 2024-01-02 -* fix display of sunrise and sunset in `/system` #1308 -* fix MqTT set power limit #1313 - -## 0.8.39 - 2024-01-01 -* fix MqTT dis_night_comm in the morning #1309 #1286 -* seperated offset for sunrise and sunset #1308 -* powerlimit (active power control) now has one decimal place (MqTT / API) #1199 -* merge Prometheus metrics fix #1310 -* merge MI grid profile request #1306 -* merge update documentation / readme #1305 -* add `getLossRate` to radio statistics and to MqTT #1199 - -## 0.8.38 - 2023-12-31 -* fix Grid-Profile JSON #1304 - -## 0.8.37 - 2023-12-30 -* added grid profiles -* format version of grid profile - -# RELEASE 0.8.36 - 2023-12-30 - -## 0.8.35 - 2023-12-30 -* added dim option for LEDS -* changed reload time for opendtufusion after update to 5s -* fix default interval and gap for communication -* fix serial number in exported json (was decimal, now correct as hexdecimal number) -* beautified factory reset -* added second stage for erase settings -* increased maximal number of inverters to 32 for opendtufusion board (ESP32-S3) -* fixed crash if CMT inverter is enabled, but CMT isn't configured - -# RELEASE 0.8.34 - 2023-12-29 - -## 0.8.33 - 2023-12-29 -* improved communication thx @rejoe2 - -## 0.8.32 - 2023-12-29 -* fix `start` / `stop` / `restart` commands #1287 -* added message, if profile was not read until now #1300 -* added developer option to use 'syslog-server' instead of 'web-serail' #1299 - -## 0.8.31 - 2023-12-29 -* added class to handle timeouts PR #1298 - -## 0.8.30 - 2023-12-28 -* added info if grid profile was not found -* merge PR #1293 -* merge PR #1295 fix ESP8266 pin settings -* merge PR #1297 fix layout for OLED displays - -## 0.8.29 - 2023-12-27 -* fix MqTT generic topic `comm_disabled` #1265 #1286 -* potential fix of #1285 (reset yield day) -* fix fraction of yield correction #1280 -* fix crash if `getLossRate` was read from inverter #1288 #1290 -* reduce reload time for opendtufusion ethernet variant to 5 seconds -* added basic grid parser -* added ESP32-C3 mini environment #1289 - -## 0.8.28 - 2023-12-23 -* fix bug heuristic -* add version information to clipboard once 'copy' was clicked -* add get loss rate @rejoe2 -* improve communication @rejoe2 - -## 0.8.27 - 2023-12-18 -* fix set power limit #1276 - -## 0.8.26 - 2023-12-17 -* read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) - -## 0.8.25 - 2023-12-17 -* RX channel ID starts with fixed value #1277 -* fix static IP for Ethernet - -## 0.8.24 - 2023-12-16 -* fix NRF communication for opendtufusion ethernet variant - -## 0.8.23 - 2023-12-14 -* heuristics fix #1269 #1270 -* moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* -* try to prevent access to radio classes if they are not activated -* fixed millis in serial log -* changed 'print whole trace' = `false` as default -* added communication loop duration in [ms] to serial console -* don't print Hex-Payload if 'print whole trace' == `false` - -## 0.8.22 - 2023-12-13 -* fix communication state-machine regarding zero export #1267 - -## 0.8.21 - 2023-12-12 -* fix ethernet save inverter parameters #886 -* fix ethernet OTA update #886 -* improved radio statistics, fixed heuristic output for HMS and HMT inverters - -## 0.8.20 - 2023-12-12 -* improved HM communication #1259 #1249 -* fix `loadDefaults` for ethernet builds #1263 -* don't loop through radios which aren't in use #1264 - -## 0.8.19 - 2023-12-11 -* added ms to serial log -* added (debug) option to configure gap between inverter requests - -## 0.8.18 - 2023-12-10 -* copied even more from the original heuristic code #1259 -* added mDNS support #1262 - -## 0.8.17 - 2023-12-10 -* possible fix of NRF with opendtufusion (without ETH) -* small fix in heuristics (if conditions made assignment not comparisson) - -## 0.8.16 - 2023-12-09 -* fix crash if NRF is not enabled -* updated heuristic #1080 #1259 -* fix compile opendtufusion fusion ethernet - -## 0.8.15 - 2023-12-09 -* added support for opendtufusion fusion ethernet shield #886 -* fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 -* changed `yield effiency` per default to `1.0` #1243 -* small heuristics improvements #1258 -* added class to combine inverter heuristics fields #1258 - -## 0.8.14 - 2023-12-07 -* fixed decimal points for temperature (WebUI) PR #1254 #1251 -* fixed inverter statemachine available state PR #1252 #1253 -* fixed NTP update and sunrise calculation #1240 #886 -* display improvments #1248 #1247 -* fixed overflow in `hmRadio.h` #1244 - -## 0.8.13 - 2023-11-28 -* merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality -* fix MqTT IP addr for ETH connections PR #1240 -* added ethernet build for fusion board, not tested so far - -## 0.8.12 - 2023-11-20 -* added button `copy to clipboard` to `/serial` - -## 0.8.11 - 2023-11-20 -* improved communication, thx @rejoe2 -* improved heuristics, thx @rejoe2, @Oberfritze -* added option to strip payload of frames to significant area - -## 0.8.10 - 2023-11-19 -* fix Mi and HM inverter communication #1235 -* added privacy mode option #1211 -* changed serial debug option to work without reboot - -## 0.8.9 - 2023-11-19 -* merged PR #1234 -* added new alarm codes -* removed serial interval, was not in use anymore - -## 0.8.8 - 2023-11-16 -* fix ESP8266 save inverter #1232 - -## 0.8.7 - 2023-11-13 -* fix ESP8266 inverter settings #1226 -* send radio statistics via MqTT #1227 -* made night communication inverter depended -* added option to prevent adding values of inverter to total values (MqTT only) #1199 - -## 0.8.6 - 2023-11-12 -* merged PR #1225 -* improved heuristics (prevent update of statitistic during testing) - -## 0.8.5 - 2023-11-12 -* fixed endless loop while switching CMT frequency -* removed obsolete "retries" field from settings #1224 -* fixed crash while defining new invertes #1224 -* fixed default frequency settings -* added default input power to `400` while adding new inverters -* fixed color of wifi RSSI icon #1224 - -## 0.8.4 - 2023-11-10 -* changed MqTT alarm topic, removed retained flag #1212 -* reduce last_success MQTT messages (#1124) -* introduced tabs in WebGUI (inverter settings) -* added inverter-wise power level and frequency - -## 0.8.3 - 2023-11-09 -* fix yield day reset during day #848 -* add total AC Max Power to WebUI -* fix opendtufusion build (GxEPD patch) -* fix null ptr PR #1222 - -## 0.8.2 - 2023-11-08 -* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) - -## 0.8.1 - 2023-11-05 -* added tx channel heuristics (per inverter) -* fix statistics counter - -## 0.8.0 - 2023-10-?? -* switched to new communication scheme - -## 0.7.66 - 2023-10-04 -* prepared PA-Level for CMT -* removed settings for number of retransmits, its fixed to `5` now -* added parentheses to have a excactly defined behaviour - -## 0.7.65 - 2023-10-02 -* MI control command review #1197 - -## 0.7.64 - 2023-10-02 -* moved active power control to modal in `live` view (per inverter) by click on current APC state - -## 0.7.63 - 2023-10-01 -* fix NRF24 communication #1200 - -## 0.7.62 - 2023-10-01 -* fix communication to inverters #1198 -* add timeout before payload is tried to process (necessary for HMS/HMT) - -## 0.7.61 - 2023-10-01 -* merged `hmPayload` and `hmsPayload` into single class -* merged generic radio functions into new parent class `radio.h` -* moved radio statistics into the inverter - each inverter has now seperate statistics which can be accessed by click on the footer in `/live` -* fix compiler warnings #1191 -* fix ePaper logo during night time #1151 - -## 0.7.60 - 2023-09-27 -* fixed typos in changelog #1172 -* fixed MqTT manual clientId storage #1174 -* fixed inverter name length in setup #1181 -* added inverter name to the header of alarm list #1181 -* improved code to avoid warning during compilation #1182 -* fix scheduler #1188, #1179 - -## 0.7.59 - 2023-09-20 -* re-add another HM-400 hardware serial number accidentally removed with `0.7.45` (#1169) -* merge PR #1170 -* reduce last_success MQTT messages (#1124) -* add re-request if inverter is known to be online and first try fails -* add alarm reporting to MI (might need review!) -* rebuild MI limiting code closer to DTUSimMI example -* round APC in `W` to an integer #1171 - -## 0.7.58 -* fix ESP8266 save settings issue #1166 - -## 0.7.57 - 2023-09-18 -* fix Alarms are always in queue (since 0.7.56) -* fix display active power control to long for small devices #1165 - -## 0.7.56 - 2023-09-17 -* only request alarms which were not received before #1113 -* added flag if alarm was requested but not received and re-request it #1105 -* merge PR #1163 - -## 0.7.55 - 2023-09-17 -* fix prometheus builds -* fix ESP32 default pinout #1159 -* added `opendtufusion-dev` because of annoying `-DARDUINO_USB_CDC_ON_BOOT=1` flag -* fix display of current power on `index` -* fix OTA, was damaged by version `0.7.51`, need to use webinstaller (from `0.7.51` to `0.7.54`) - -## 0.7.54 - 2023-09-16 -* added active power control in `W` to live view #201, #673 -* updated docu, active power control related #706 -* added current AC-Power to `index` page and removed version #763 -* improved statistic data, moved to entire struct -* removed `/api/statistics` endpoint from REST-API - -## 0.7.53 - 2023-09-16 -* fix ePaper / display night behaviour #1151 -* fix ESP8266 compile error - -## 0.7.52 - 2023-09-16 -* fix CMT configurable pins #1150, #1159 -* update MqTT lib to version `1.4.5` - -## 0.7.51 - 2023-09-16 -* fix CMT configurable pins #1150 -* fix default CMT pins for opendtufusion -* beautified `system` -* changed main loops, fix resets #1125, #1135 - -## 0.7.50 - 2023-09-12 -* moved MqTT info to `system` -* added CMT info for ESP32 devices -* improved CMT settings, now `SCLK` and `SDIO` are configurable #1046, #1150 -* changed `Power-Limit` in live-view to `Active Power Control` -* increase length of update file selector #1132 - -## 0.7.49 - 2023-09-11 -* merge PR: symbolic icons for mono displays, PR #1136 -* merge MI code restructuring PR #1145 -* merge Prometheus PR #1148 -* add option to strip webUI for ESP8266 (reduce code size, add ESP32 special features; `IF_ESP32` directives) -* started to get CMT info into `system` - not finished - -## 0.7.48 - 2023-09-10 -* fix SSD1309 2.42" display pinout -* improved setup page: save and delete of inverters - -## 0.7.47 - 2023-09-07 -* fix boot loop #1140 -* fix regex in `setup` page -* fix MI serial number display `max-module-power` in `setup` #1142 -* renamed `opendtufusionv1` to `opendtufusion` - -## 0.7.46 - 2023-09-04 -* removed `delay` from ePaper -* started improvements of `/system` -* fix LEDs to check all configured inverters -* send loop skip disabled inverters fix -* print generated DTU SN to console -* HW Versions for MI series PR #1133 -* 2.42" display (SSD1309) integration PR #1139 -* update user manual PR #1121 -* add / rename alarm codes PR #1118 -* revert default pin ESP32 for NRF23-CE #1132 -* luminance of display can be changed during runtime #1106 - -## 0.7.45 - 2023-08-29 -* change ePaper text to symbols PR #1131 -* added some invertes to dev info list #1111 - -## 0.7.44 - 2023-08-28 -* fix `last_success` transmitted to often #1124 - -## 0.7.43 - 2023-08-28 -* improved RSSI for NRF24, now it's read per package (and inverter) #1129 -* arranged `heap` related info together in `/system` -* fix display navi during save -* clean up binary output, separated to folders - -## 0.7.42 - 2023-08-27 -* fix ePaper for opendtufusion_v2.x boards (Software SPI) -* add signal strength for NRF24 - PR #1119 -* refactor wifi class to support ESP32 S2 PR #1127 -* update platform for ESP32 to 6.3.2 -* fix opendtufusion LED (were mixed) -* fix `last_success` transmitted to often #1124 -* added ESP32-S3-mini to github actions -* added old Changelog Entries, to have full log of changes - -## 0.7.41 - 2023-08-26 -* merge PR #1117 code spelling fixes #1112 -* alarms were not read after the first day - -## 0.7.40 - 2023-08-21 -* added default pins for opendtu-fusion-v1 board -* fixed hw version display in `live` -* removed development builds, renamed environments in `platform.ini` - -## 0.7.39 - 2023-08-21 -* fix background color of invalid inputs -* add hardware info (click in `live` on inverter name) - -## 0.7.38 - 2023-08-21 -* reset alarms at midnight (if inverter is not available) #1105, #1096 -* add option to reset 'max' values on midnight #1102 -* added default pins for CMT2300A (matching OpenDTU) - -## 0.7.37 - 2023-08-18 -* fix alarm time on WebGui #1099 -* added RSSI info for HMS and HMT inverters (MqTT + REST API) - -# RELEASE 0.7.36 - 2023-08-18 - -## 0.7.35 - 2023-08-17 -* fixed timestamp for alarms send over MqTT -* auto-patch of `AsyncWebServer` #834, #1036 -* Update documentation in Git regarding `ESP8266` default NRF24 pin assignments - -## 0.7.34 - 2023-08-16 -* fixed timezone offset of alarms -* added `AC` and `DC` to `/live` #1098 -* changed `ESP8266` default NRF24 pin assignments (`D3` = `CE` and `D4` = `IRQ`) -* fixed background of modal window for bright color -* fix MI crashes -* fix some lost debug messages -* merged PR #1095, MI fixes for 0.7.x versions -* fix scheduled reboot #1097 -* added vector graphic logo `/doc/logo.svg` -* merge PR #1093, improved Nokia5110 display layout - -## 0.7.33 - 2023-08-15 -* add alarms overview to WebGui #608 -* fix webGui total values #1084 - -## 0.7.32 - 2023-08-14 -* fix colors of live view #1091 - -## 0.7.31 - 2023-08-13 -* fixed docu #1085 -* changed active power limit MqTT messages to QOS2 #1072 -* improved alarm messages, added alarm-id to log #1089 -* trigger power limit read on next day (if inverter was offline meanwhile) -* disabled improv implementation to check if it is related to 'Schwuppdizitaet' -* changed live view to gray once inverter isn't available -* added inverter status to API -* changed sum of totals on WebGui depending on inverter status #1084 -* merge maximum power (AC and DC) from PR #1080 - -## 0.7.30 - 2023-08-10 -* attempt to improve speed / response times (Schwuppdizitaet) #1075 - -## 0.7.29 - 2023-08-09 -* MqTT alarm data was never sent, fixed -* REST API: added alarm data -* REST API: made get record obsolete -* REST API: added power limit acknowledge `/api/inverter/id/[0-x]` #1072 - -## 0.7.28 - 2023-08-08 -* fix MI inverter support #1078 - -## 0.7.27 - 2023-08-08 -* added compile option for ethernet #886 -* fix ePaper configuration, missing `Busy`-Pin #1075 - -# RELEASE 0.7.26 - 2023-08-06 - -* fix MqTT `last_success` - -# RELEASE 0.7.25 - 2023-08-06 - -## 0.7.24 - 2023-08-05 -* merge PR #1069 make MqTT client ID configurable -* fix #1016, general MqTT status depending on inverter state machine -* changed icon for fully available inverter to a filled check mark #1070 -* fixed `last_success` update with MqTT #1068 -* removed `improv` esp-web-installer script, because it is not fully functional at this time - -## 0.7.23 - 2023-08-04 -* merge PR #1056, visualization html -* update MqTT library to 1.4.4 -* update RF24 library to 1.4.7 -* update ArduinoJson library to 6.21.3 -* set minimum invervall for `/live` to 5 seconds - -## 0.7.22 - 2023-08-04 -* attempt to fix homeassistant auto discovery #1066 - -## 0.7.21 - 2023-07-30 -* fix MqTT YieldDay Total goes to 0 several times #1016 - -## 0.7.20 - 2023-07-28 -* merge PR #1048 version and hash in API, fixes #1045 -* fix: no yield day update if yield day reads `0` after inverter reboot (mostly on evening) #848 -* try to fix Wifi override #1047 -* added information after NTP sync to WebUI #1040 - -## 0.7.19 - 2023-07-27 -* next attempt to fix yield day for multiple inverters #1016 -* reduced threshold for inverter state machine from 60min to 15min to go from state `WAS_ON` to `OFF` - -## 0.7.18 - 2023-07-26 -* next attempt to fix yield day for multiple inverters #1016 - -## 0.7.17 - 2023-07-25 -* next attempt to fix yield day for multiple inverters #1016 -* added two more states for the inverter status (also docu) - -## 0.7.16 - 2023-07-24 -* next attempt to fix yield day for multiple inverters #1016 -* fix export settings date #1040 -* fix time on WebUI (timezone was not observed) #913 #1016 - -## 0.7.15 - 2023-07-23 -* add NTP sync interval #1019 -* adjusted range of contrast / luminance setting #1041 -* use only ISO time format in Web-UI #913 - -## 0.7.14 - 2023-07-23 -* fix Contrast for Nokia Display #1041 -* attempt to fix #1016 by improving inverter status -* added option to adjust efficiency for yield (day/total) #1028 - -## 0.7.13 - 2023-07-19 -* merged display PR #1027 -* add date, time and version to export json #1024 - -## 0.7.12 - 2023-07-09 -* added inverter status - state-machine #1016 - -## 0.7.11 - 2023-07-09 -* fix MqTT endless loop #1013 - -## 0.7.10 - 2023-07-08 -* fix MqTT endless loop #1013 - -## 0.7.9 - 2023-07-08 -* added 'improve' functions to set wifi password directly with ESP web tools #1014 -* fixed MqTT publish while applying power limit #1013 -* slightly improved HMT live view (Voltage & Current) - -## 0.7.8 - 2023-07-05 -* fix `YieldDay`, `YieldTotal` and `P_AC` in `TotalValues` #929 -* fix some serial debug prints -* merge PR #1005 which fixes issue #889 -* merge homeassistant PR #963 -* merge PR #890 which gives option for scheduled reboot at midnight (default off) - -## 0.7.7 - 2023-07-03 -* attempt to fix MqTT `YieldDay` in `TotalValues` #927 -* attempt to fix MqTT `YieldDay` and `YieldTotal` even if inverters are not completely available #929 -* fix wrong message 'NRF not connected' if it is disabled #1007 - -## 0.7.6 - 2023-06-17 -* fix display of hidden SSID checkbox -* changed yield correction data type to `double`, now decimal places are supported -* corrected name of 0.91" display in settings -* attempt to fix MqTT zero values only if setting is there #980, #957 -* made AP password configurable #951 -* added option to start without time-sync, eg. for AP-only-mode #951 - -## 0.7.5 - 2023-06-16 -* fix yield day reset on midnight #957 -* improved tickers in `app.cpp` - -## 0.7.4 - 2023-06-15 -* fix MqTT `P_AC` send if inverters are available #987 -* fix assignments for HMS 1CH and 2CH devices -* fixed uptime overflow #990 - -## 0.7.3 - 2023-06-09 -* fix hidden SSID scan #983 -* improved NRF24 missing message on home screen #981 -* fix MqTT publishing only updated values #982 - -## 0.7.2 - 2023-06-08 -* fix HMS-800 and HMS-1000 assignments #981 -* make nrf enabled all the time for ESP8266 -* fix menu item `active` highlight for 'API' and 'Doku' -* fix MqTT totals issue #927, #980 -* reduce maximum number of inverters to 4 for ESP8266, increase to 16 for ESP32 - -## 0.7.1 - 2023-06-05 -* enabled power limit control for HMS / HMT devices -* changed NRF24 lib version back to 1.4.5 because of compile problems for EPS8266 - -## 0.7.0 - 2023-06-04 -* HMS / HMT support for ESP32 devices - -## 0.6.15 - 2023-05-25 -* improved Prometheus Endpoint PR #958 -* fix turn off ePaper only if setting was set #956 -* improved reset values and update MqTT #957 - -## 0.6.14 - 2023-05-21 -* merge PR #902 Mono-Display - -## 0.6.13 - 2023-05-16 -* merge PR #934 (fix JSON API) and #944 (update manual) - -## 0.6.12 - 2023-04-28 -* improved MqTT -* fix menu active item - -## 0.6.11 - 2023-04-27 -* added MqTT class for publishing all values in Arduino `loop` - -## 0.6.10 - HMS -* Version available in `HMS` branch - -# RELEASE 0.6.9 - 2023-04-19 - -## 0.6.8 - 2023-04-19 -* fix #892 `zeroYieldDay` loop was not applied to all channels - -## 0.6.7 - 2023-04-13 -* merge PR #883, improved store of settings and javascript, thx @tastendruecker123 -* support `.` and `,` as floating point separator in setup #881 - -## 0.6.6 - 2023-04-12 -* increased distance for `import` button in mobile view #879 -* changed `led_high_active` to `bool` #879 - -## 0.6.5 - 2023-04-11 -* fix #845 MqTT subscription for `ctrl/power/[IV-ID]` was missing -* merge PR #876, check JSON settings during read for existence -* **NOTE:** incompatible change: renamed `led_high_active` to `act_high`, maybe setting must be changed after update -* merge PR #861 do not send channel metric if channel is disabled - -## 0.6.4 - 2023-04-06 -* merge PR #846, improved NRF24 communication and MI, thx @beegee3 & @rejoe2 -* merge PR #859, fix burger menu height, thx @ThomasPohl - -## 0.6.3 - 2023-04-04 -* fix login, password length was not checked #852 -* merge PR #854 optimize browser caching, thx @tastendruecker123 #828 -* fix WiFi reconnect not working #851 -* updated issue templates #822 - -## 0.6.2 - 2023-04-04 -* fix login from multiple clients #819 -* fix login screen on small displays - -## 0.6.1 - 2023-04-01 -* merge LED fix - LED1 shows MqTT state, LED configurable active high/low #839 -* only publish new inverter data #826 -* potential fix of WiFi hostname during boot up #752 - -# RELEASE 0.6.0 - 2023-03-27 - -## 0.5.110 -* MQTT fix reconnection by new lib version #780 -* add `about` page -* improved documentation regarding SPI pins #814 -* improved documentation (getting started) #815 #816 -* improved MI 4-ch inverter #820 - -## 0.5.109 -* reduced heap fragmentation by optimizing MqTT #768 -* ePaper: centered text thx @knickohr - -## 0.5.108 -* merge: PR SPI pins configurable (ESP32) #807, #806 (requires manual set of MISO=19, MOSI=23, SCLK=18 in GUI for existing installs) -* merge: PR MI serial outputs #809 -* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805 -* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805 - -## 0.5.107 -* fix: show save message -* fix: removed serial newline for `enqueueCmd` -* Merged improved Prometheus #808 - -## 0.5.106 -* merged MI and debug message changes #804 -* fixed MQTT autodiscover #794, #632 - -## 0.5.105 -* merged MI, thx @rejoe2 #788 -* fixed reboot message #793 - -## 0.5.104 -* further improved save settings -* removed `#` character from ePaper -* fixed saving pinout for `Nokia-Display` -* removed `Reset` Pin for monochrome displays -* improved wifi connection #652 - -## 0.5.103 -* merged MI improvements, thx @rejoe2 #778 -* changed display inverter online message -* merged heap improvements #772 - -## 0.5.102 -* Warning: old exports are not compatible any more! -* fix JSON import #775 -* fix save settings, at least already stored settings are not lost #771 -* further save settings improvements (only store inverters which are existing) -* improved display of settings save return value -* made save settings asynchronous (more heap memory is free) - -## 0.5.101 -* fix SSD1306 -* update documentation -* Update miPayload.h -* Update README.md -* MI - remarks to user manual -* MI - fix AC calc -* MI - fix status msg. analysis - -## 0.5.100 -* fix add inverter `setup.html` #766 -* fix MQTT retained flag for total values #726 -* renamed buttons for import and export `setup.html` -* added serial message `settings saved` - -## 0.5.99 -* fix limit in [User_Manual.md](../User_Manual.md) -* changed `contrast` to `luminance` in `setup.html` -* try to fix SSD1306 display #759 -* only show necessary display pins depending on setting - -## 0.5.98 -* fix SH1106 rotation and turn off during night #756 -* removed MQTT subscription `sync_ntp`, `set_time` with a value of `0` does the same #696 -* simplified MQTT subscription for `limit`. Check [User_Manual.md](../User_Manual.md) for new syntax #696, #713 -* repaired inverter wise limit control -* fix upload settings #686 - -## 0.5.97 -* Attention: re-ordered display types, check your settings! #746 -* improved saving settings of display #747, #746 -* disabled contrast for Nokia display #746 -* added Prometheus as compile option #719, #615 -* update MQTT lib to v1.4.1 -* limit decimal places to 2 in `live` -* added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657 -* a `max-module-power` of `0` disables channel in live view `setup` -* merge MI improvements, get firmware information #753 - -## 0.5.96 -* added Nokia display again for ESP8266 #764 -* changed `var` / `VAr` to SI unit `var` #732 -* fix MQTT retained flags for totals (P_AC, P_DC) #726, #721 - -## 0.5.95 -* merged #742 MI Improvements -* merged #736 remove obsolete JSON Endpoint - -## 0.5.94 -* added ePaper (for ESP32 only!), thx @dAjaY85 #735 -* improved `/live` margins #732 -* renamed `var` to `VAr` #732 - -## 0.5.93 -* improved web API for `live` -* added dark mode option -* converted all forms to reponsive design -* repaired menu with password protection #720, #716, #709 -* merged MI series fixes #729 - -## 0.5.92 -* fix mobile menu -* fix inverters in select `serial.html` #709 - -## 0.5.91 -* improved html and navi, navi is visible even when API dies #660 -* reduced maximum allowed JSON size for API to 6000Bytes #660 -* small fix: output command at `prepareDevInformCmd` #692 -* improved inverter handling #671 - -## 0.5.90 -* merged PR #684, #698, #705 -* webserial minor overflow fix #660 -* web `index.html` improve version information #701 -* fix MQTT sets power limit to zero (0) #692 -* changed `reset at midnight` with timezone #697 - -## 0.5.89 -* reduced heap fragmentation (removed `strtok` completely) #644, #645, #682 -* added part of mac address to MQTT client ID to separate multiple ESPs in same network -* added dictionary for MQTT to reduce heap-fragmentation -* removed `last Alarm` from Live view, because it showed always the same alarm - will change in future - -## 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 - -## 0.5.86 -* prevent send devcontrol request during disabled night communication -* changed yield total correction as module (inverter input) value #570 -* MQTT Yield Day zero, next try to fix #671 - -## 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 -* fixed 'polling stop message' on `index.html` #639 - -## 0.5.84 -* fix blue LED lights up all the time #672 -* added an instant start communication (once NTP is synced) -* add MI 3rd generation inverters (10x2 serial numbers) -* first decodings of messages from MI 2nd generation inverters - -## 0.5.83 -* fix MQTT publishing, `callback` was set but reset by following `setup()` - -## 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`) - -## 0.5.80 -* fixed communication #656 - -## 0.5.79 -* fixed mixed reset flags #648 -* fixed `mCbAlarm` if MQTT is not used #653 -* fixed MQTT `autodiscover` #630 thanks to @antibill51 -* next changes from @beegee many thanks for your contribution! -* replaced `CircularBuffer` by `std::queue` -* reworked `hmRadio.h` completely (interrupts, packaging) -* fix exception while `reboot` -* cleanup MQTT coding - -## 0.5.78 -* further improvements regarding wifi #611, fix connection if only one AP with same SSID is there -* fix endless loop in `zerovalues` #564 -* fix auto discover again #565 -* added total values to autodiscover #630 -* improved zero at midnight #625 - -## 0.5.77 -* fix wrong filename for automatically created manifest (online installer) #620 -* added rotate display feature #619 -* improved Prometheus endpoint #615, thx to @fsck-block -* improved wifi to connect always to strongest RSSI, thx to @beegee3 #611 - -## 0.5.76 -* reduce MQTT retry interval from maximum speed to one second -* fixed homeassistant autodiscovery #565 -* implemented `getNTPTime` improvements #609 partially #611 -* added alarm messages to MQTT #177, #600, #608 - -## 0.5.75 -* fix wakeup issue, once wifi was lost during night the communication didn't start in the morning -* re-enabled FlashStringHelper because of lacking RAM -* complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup -* fix power limit not possible #607 - -## 0.5.74 -* improved payload handling (retransmit all fragments on CRC error) -* improved `isAvailable`, checks all record structs, inverter becomes available more early because version is check first -* fix tickers were not set if NTP is not available -* disabled annoying `FlashStringHelper` it gives randomly Exceptions during development, feels more stable since then -* moved erase button to the bottom in settings, not nice but more functional -* split `tx_count` to `tx_cnt` and `retransmits` in `system.html` -* fix mqtt retransmit IP address #602 -* added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console) - -## 0.5.73 -* improved payload handling (request / retransmit) #464 -* included alarm ID parse to serial console (in development) - -## 0.5.72 -* repaired system, scheduler was not called any more #596 - -## 0.5.71 -* improved wifi handling and tickers, many thanks to @beegee3 #571 -* fixed YieldTotal correction calculation #589 -* fixed serial output of power limit acknowledge #569 -* reviewed `sendDiscoveryConfig` #565 -* merged PR `Monodisplay`, many thanks to @dAjaY85 #566, Note: (settings are introduced but not able to be modified, will be included in next version) - -## 0.5.70 -* corrected MQTT `comm_disabled` #529 -* fix Prometheus and JSON endpoints (`config_override.h`) #561 -* publish MQTT with fixed interval even if inverter is not available #542 -* added JSON settings upload. NOTE: settings JSON download changed, so only settings should be uploaded starting from version `0.5.70` #551 -* MQTT topic and inverter name have more allowed characters: `[A-Za-z0-9./#$%&=+_-]+`, thx: @Mo Demman -* improved potential issue with `checkTicker`, thx @cbscpe -* MQTT option for reset values on midnight / not avail / communication stop #539 -* small fix in `tickIVCommunication` #534 -* add `YieldTotal` correction, eg. to have the option to zero at year start #512 - -## 0.5.69 -* merged SH1106 1.3" Display, thx @dAjaY85 -* added SH1106 to automatic build -* added IP address to MQTT (version, device and IP are retained and only transmitted once after boot) #556 -* added `set_power_limit` acknowledge MQTT publish #553 -* changed: version, device name are only published via MQTT once after boot -* added `Login` to menu if admin password is set #554 -* added `development` to second changelog link in `index.html` #543 -* added interval for MQTT (as option). With this settings MQTT live data is published in a fixed timing (only if inverter is available) #542, #523 -* added MQTT `comm_disabled` #529 -* changed name of binaries, moved GIT-Sha to the front #538 - -## 0.5.68 -* repaired receive payload -* Powerlimit is transferred immediately to inverter - -## 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 -* payload: if last frame is missing, request all frames again - -# RELEASE 0.5.66 - 2022-12-30 - -## 0.5.65 -* wifi, code optimization #509 - -## 0.5.64 -* channel name can use any character, not limited any more -* added `/` to MQTT topic and Inverter name -* trigger for `calcSunrise` is now using local time #515 -* fix reconnect timeout for WiFi #509 -* start AP only after boot, not on WiFi connection loss -* improved /system `free_heap` value (measured before JSON-tree is built) - -## 0.5.63 -* fix Update button protection (prevent double click #527) -* optimized scheduler #515 (thx @beegee3) -* potential fix of #526 duplicates in API `/api/record/live` -* added update information to `index.html` - -## 0.5.62 -* fix MQTT `status` update -* removed MQTT `available_text` (can be deducted from `available`) -* enhanced MQTT documentation in `User_Manual.md` -* removed `tickSunset` and `tickSunrise` from MQTT. It's not needed any more because of minute wise check of status (`processIvStatus`) -* changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` -* fix regular expression of `setup.html` for inverter name and channel name - -## 0.5.61 -* fix #521 no reconnect at beginning of day -* added immediate (each minute) report of inverter status MQTT #522 -* added protection mask to select which pages should be protected -* update of monochrome display, show values also if nothing changed - -## 0.5.60 -* added regex to inverter name and MQTT topic (setup.html) -* beautified serial.html -* added ticker for wifi loop #515 - -## 0.5.59 -* fix night communication enable -* improved different WiFi connection scenarios (STA WiFi not found, reconnect #509, redirect for AP to configuration) -* increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 - -## 0.5.58 -* improved stability -* improved WiFi initial connection - especially if station WiFi is not available -* removed new operators from web.h (reduce dynamic allocation) -* improved sun calculation #515, #505 -* fixed WiFi auto reconnect #509 -* added disable night communication flag to MQTT #505 -* changed MQTT publish of `available` and `available_text` to sunset #468 - -## 0.5.57 -* improved stability -* added icons to index.html, added WiFi-strength symbol on each page -* moved packet stats and sun to system.html -* refactored communication offset (adjustable in minutes now) - -## 0.5.56 -* factory reset formats entire little fs -* renamed sunrise / sunset on index.html to start / stop communication -* show system information only if called directly from menu -* beautified system.html - -## 0.5.55 -* fixed static IP save - -## 0.5.54 -* changed sunrise / sunset calculation, angle is now `-3.5` instead of original `-0.83` -* improved scheduler (removed -1 from `reload`) #483 -* improved reboot flag in `app.h` -* fixed #493 no MQTT payload once display is defined - -## 0.5.53 -* Mono-Display: show values in offline mode #498 -* improved WiFi class #483 -* added communication enable / disable (to test multiple DTUs with the same inverter) -* fix factory reset #495 - -## 0.5.52 -* improved ahoyWifi class -* added interface class for app -* refactored web and webApi -> RestApi -* fix calcSunrise was not called every day -* added MQTT RX counter to index.html -* all values are displayed on /live even if they are 0 -* added MQTT /status to show status over all inverters - -## 0.5.51 -* improved scheduler, @beegee3 #483 -* refactored get NTP time, @beegee3 #483 -* generate `bin.gz` only for 1M device ESP8285 -* fix calcSunrise was not called every day -* increased number of allowed characters for MQTT user, broker and password, @DanielR92 -* added NRF24 info to Systeminfo, @DanielR92 -* added timezone for monochrome displays, @gh-fx2 -* added support for second inverter for monochrome displays, @gh-fx2 - -## 0.5.50 -* fixed scheduler, uptime and timestamp counted too fast -* added / renamed automatically build outputs -* fixed MQTT ESP uptime on reconnect (not zero any more) -* changed uptime on index.html to count each second, synced with ESP each 10 seconds - -## 0.5.49 -* fixed AP mode on brand new ESP modules -* fixed `last_success` MQTT message -* fixed MQTT inverter available status at sunset -* reordered enqueue commands after boot up to prevent same payload length for successive commands -* added automatic build for Nokia5110 and SSD1306 displays (ESP8266) - -## 0.5.48 -* added MQTT message send at sunset -* added monochrome display support -* added `once` and `onceAt` to scheduler to make code cleaner -* improved sunrise / sunset calculation - -## 0.5.47 -* refactored ahoyWifi class: AP is opened on every boot, once station connection is successful the AP will be closed -* improved NTP sync after boot, faster sync -* fix NRF24 details only on valid SPI connection - -## 0.5.46 -* fix sunrise / sunset calculation -* improved setup.html: `reboot on save` is checked as default - -## 0.5.45 -* changed MQTT last will topic from `status` to `mqtt` -* fix sunrise / sunset calculation -* fix time of serial web console - -## 0.5.44 -* marked some MQTT messages as retained -* moved global functions to global location (no duplicates) -* changed index.html interval to static 10 seconds -* fix static IP -* fix NTP with static IP -* print MQTT info only if MQTT was configured - -## 0.5.43 -* updated REST API and MQTT (both of them use the same functionality) -* added ESP-heap information as MQTT message -* changed output name of automatic development build to fixed name (to have a static link from https://ahoydtu.de) -* updated user manual to latest MQTT and API changes - -## 0.5.42 -* fix web logout (auto logout) -* switched MQTT library - -# RELEASE 0.5.41 - 2022-11-22 - -# RELEASE 0.5.28 - 2022-10-30 - -# RELEASE 0.5.17 - 2022-09-06 - -# RELEASE 0.5.16 - 2022-09-04 - +full version log: [Development Log](https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md) diff --git a/src/defines.h b/src/defines.h index 68094ba3..bf111d99 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 82 +#define VERSION_PATCH 83 //------------------------------------- typedef struct { From 9e58d58fa26714d0792e26b3265a48cb0a432e81 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 17 Feb 2024 00:29:02 +0100 Subject: [PATCH 54/79] 0.8.83 release --- .github/workflows/compile_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index bf9709a0..c5f52308 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -89,6 +89,7 @@ jobs: contents: write steps: + - uses: actions/checkout@v4 - name: Get Artifacts uses: actions/download-artifact@v4 with: @@ -110,7 +111,6 @@ jobs: run: mv firmware ${{ steps.version_name.outputs.name }} - name: Publish Release - uses: actions/checkout@v3 uses: ncipollo/release-action@v1 with: artifacts: ${{ steps.version_name.outputs.name }} From ca98e75eead35507045ba12713dac988eb826e9b Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 17 Feb 2024 00:29:51 +0100 Subject: [PATCH 55/79] 0.8.83 release --- .github/workflows/compile_release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index c5f52308..65b6ca76 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -9,7 +9,6 @@ on: jobs: build: name: Build Environments - needs: check runs-on: ubuntu-latest if: github.repository == 'lumapu/ahoy' && github.ref_name == 'main' continue-on-error: false From 630e3fd219bf756a202972e7f1e483e2c0fe0e97 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 17 Feb 2024 00:45:09 +0100 Subject: [PATCH 56/79] 0.8.83 release --- .github/workflows/compile_release.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 65b6ca76..569b1843 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -99,6 +99,17 @@ jobs: id: version_name run: python scripts/getVersion.py ${{ matrix.variant }} >> $GITHUB_OUTPUT + - name: Create tag + uses: actions/github-script@v7 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/${{ steps.version_name.outputs.name }}', + sha: context.sha + }) + - name: Set Version uses: cschleiden/replace-tokens@v1 with: @@ -113,15 +124,17 @@ jobs: uses: ncipollo/release-action@v1 with: artifacts: ${{ steps.version_name.outputs.name }} + artifactErrorsFailBuild: true + skipIfReleaseExists: true bodyFile: src/CHANGES.md - commit: "main" tag: ${{ steps.rename-binary-files.outputs.name }} name: ${{ steps.rename-binary-files.outputs.name }} + token: ${{ secrets.GITHUB_TOKEN }} deploy: name: Deploy Environments to fw.ahoydtu.de - needs: [build] + needs: [build, release] runs-on: ubuntu-latest continue-on-error: false steps: @@ -151,7 +164,7 @@ jobs: with: src: ${{ steps.version_name.outputs.name }}/ host: ${{ secrets.FW_SSH_HOST }} - remote: ${{ secrets.FW_SSH_DIR }}/dev + remote: ${{ secrets.FW_SSH_DIR }}/release port: ${{ secrets.FW_SSH_PORT }} user: ${{ secrets.FW_SSH_USER }} key: ${{ secrets.FW_SSH_KEY }} From 894700458697938daf191010a5a41685c1c2289a Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 17 Feb 2024 00:51:44 +0100 Subject: [PATCH 57/79] 0.8.83 release --- .github/workflows/compile_release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 569b1843..6eb1366a 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -123,12 +123,12 @@ jobs: - name: Publish Release uses: ncipollo/release-action@v1 with: - artifacts: ${{ steps.version_name.outputs.name }} artifactErrorsFailBuild: true skipIfReleaseExists: true bodyFile: src/CHANGES.md - tag: ${{ steps.rename-binary-files.outputs.name }} - name: ${{ steps.rename-binary-files.outputs.name }} + artifacts: ${{ steps.version_name.outputs.name }} + tag: ${{ steps.version_name.outputs.name }} + name: ${{ steps.version_name.outputs.name }} token: ${{ secrets.GITHUB_TOKEN }} From 360832254f18792aa05b0d41f0d70c0c123819ef Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 17 Feb 2024 01:05:52 +0100 Subject: [PATCH 58/79] 0.8.83 release --- .github/workflows/compile_release.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 6eb1366a..8cafc57e 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -120,13 +120,19 @@ jobs: - name: Rename firmware directory run: mv firmware ${{ steps.version_name.outputs.name }} + - name: Rename firmware directory + uses: vimtor/action-zip@v1.2 + with: + files: ${{ steps.version_name.outputs.name }} manual/User_Manual.md manual/Getting_Started.md + dest: '${{ steps.version_name.outputs.name }}.zip' + - name: Publish Release uses: ncipollo/release-action@v1 with: artifactErrorsFailBuild: true skipIfReleaseExists: true bodyFile: src/CHANGES.md - artifacts: ${{ steps.version_name.outputs.name }} + artifacts: '${{ steps.version_name.outputs.name }}.zip' tag: ${{ steps.version_name.outputs.name }} name: ${{ steps.version_name.outputs.name }} token: ${{ secrets.GITHUB_TOKEN }} From 5ebfe5a8fb5bcc833b64a0dd083686031808cec8 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 17 Feb 2024 01:08:48 +0100 Subject: [PATCH 59/79] 0.8.83 release --- .github/workflows/compile_release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 8cafc57e..59adf28c 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -122,9 +122,9 @@ jobs: - name: Rename firmware directory uses: vimtor/action-zip@v1.2 - with: - files: ${{ steps.version_name.outputs.name }} manual/User_Manual.md manual/Getting_Started.md - dest: '${{ steps.version_name.outputs.name }}.zip' + with: + files: ${{ steps.version_name.outputs.name }} manual/User_Manual.md manual/Getting_Started.md + dest: '${{ steps.version_name.outputs.name }}.zip' - name: Publish Release uses: ncipollo/release-action@v1 From 426d47786c1629d8ac60ab779822e7c1ef0e8e0a Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 17 Feb 2024 09:38:17 +0100 Subject: [PATCH 60/79] Remove hint to 'INV_RESET_MIDNIGHT' --- src/web/lang.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/lang.json b/src/web/lang.json index 066370c5..5b45a2b7 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -295,8 +295,8 @@ }, { "token": "INV_RESET_MIDNIGHT", - "en": "Reset values and YieldDay at midnight. ('Pause communication during night' need to be set)", - "de": "Werte und Gesamtertrag um Mitternacht zurücksetzen ('Kommunikation während der Nacht pausieren' muss gesetzt sein)" + "en": "Reset values and YieldDay at midnight", + "de": "Werte und Gesamtertrag um Mitternacht zurücksetzen" }, { "token": "INV_PAUSE_SUNSET", From c7f7d77fb2b2bd36ed3961471cb9c73bd16b9e99 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 19 Feb 2024 23:03:23 +0100 Subject: [PATCH 61/79] 0.8.84 * fix homeassistant autodiscovery #1432 --- src/CHANGES.md | 1300 +++++++++++++++++++++++++++++++++++++-- src/defines.h | 2 +- src/publisher/pubMqtt.h | 7 +- 3 files changed, 1268 insertions(+), 41 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 5fd4fc31..e55145c5 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,41 +1,1265 @@ -Changelog v0.8.83 +# Development Changes -* added German translations for all variants -* added reading grid profile -* added decimal place for active power control (APC aka power limit) -* added information about working IRQ for NRF24 and CMT2300A to `/system` -* added loss rate to `/visualization` in the statistics window and MqTT -* added optional output to display whether it's night time or not. Can be reused as output to control battery system or mapped to a LED -* added timestamp for `max ac power` as tooltip -* added wizard for initial WiFi connection -* added history graph (still under development) -* added simulator (must be activated before compile, standard: off) -* added minimal version (without: MqTT, Display, History), WebUI is not changed! (not compiled automatically) -* added info about installed binary to `/update` -* added protection to prevent update to wrong firmware (environment check) -* added optional custom link to the menu -* added support for other regions (USA, Indonesia) -* added warning for WiFi channel 12-14 (ESP8266 only) -* added `max_power` to MqTT total values -* added API-Token authentification for external scripts -* improved MqTT by marking sent data and improved `last_success` resends -* improved communication for HM and MI inverters -* improved reading live data from inverter -* improved sending active power control command faster -* improved `/settings`: pinout has an own subgroup -* improved export by saving settings before they are exported (to have everything in JSON) -* improved code quality (cppcheck) -* seperated sunrise and sunset offset to two fields -* fix MqTT night communication -* fix missing favicon to html header -* fix build on Windows of `opendtufusion` environments (git: trailing whitespaces) -* fix generation of DTU-ID -* fix: protect commands from popup in `/live` if password is set -* fix: prevent sending commands to inverter which isn't active -* combined firmware and hardware version to JSON topics (MqTT) -* updated Prometheus with latest changes -* upgraded most libraries to newer versions -* beautified typography, added spaces between value and unit for `/visualization` +## 0.8.84 - 2024-02-19 +* fix homeassistant autodiscovery #1432 + +# RELEASE 0.8.83 - 2024-02-16 + +## 0.8.82 - 2024-02-15 +* fixed crash once firmware version was read and sent via MqTT #1428 +* possible fix: reset yield offset on midnight #1429 + +## 0.8.81 - 2024-02-13 +* fixed authentication with empty token #1415 +* added new setting for future function to send log via MqTT +* combined firmware and hardware version to JSON topics (MqTT) #1212 + +## 0.8.80 - 2024-02-12 +* optimize API authentication, Error-Codes #1415 +* breaking change: authentication API command changed #1415 +* breaking change: limit has to be send als `float`, `0.0 .. 100.0` #1415 +* updated documentation #1415 +* fix don't send control command twice #1426 + +## 0.8.79 - 2024-02-11 +* fix `opendtufusion` build (started only once USB-console was connected) +* code quality improvments + +## 0.8.78 - 2024-02-10 +* finalized API token access #1415 +* possible fix of MqTT fix "total values are sent to often" #1421 +* removed `switchCycle` from `hmsRadio.h` #1412 +* merge PR: Add hint to INV_RESET_MIDNIGHT resp. INV_PAUSE_DURING_NIGHT #1418 +* merge PR: simplify rxOffset logic #1417 +* code quality improvments + +## 0.8.77 - 2024-02-08 +* merge PR: BugFix: ACK #1414 +* fix suspicious if condition #1416 +* prepared API token for access, not functional #1415 + +## 0.8.76 - 2024-02-07 +* revert changes from yesterday regarding snprintf and its size #1410, #1411 +* reduced cppcheck linter warnings significantly +* try to improve ePaper (ghosting) #1107 + +## 0.8.75 - 2024-02-06 +* fix active power control value #1406, #1409 +* update Mqtt lib to version `1.6.0` +* take care of null terminator of chars #1410, #1411 + +## 0.8.74 - 2024-02-05 +* reduced cppcheck linter warnings significantly + +## 0.8.73 - 2024-02-03 +* fix nullpointer during communication #1401 +* added `max_power` to MqTT total values #1375 + +## 0.8.72 - 2024-02-03 +* fixed translation #1403 +* fixed sending commands to inverters which are soft turned off #1397 +* reduce switchChannel command for HMS (only each 5th cycle it will be send now) + +## 0.8.71 - 2024-02-03 +* fix heuristics reset +* fix CMT missing frames problem +* removed inverter gap setting * removed add to total (MqTT) inverter setting +* fixed sending commands to inverters which are soft turned off +* save settings before they are exported #1395 +* fix autologin bug if no password is set +* translated `/serial` +* removed "yield day" history + +## 0.8.70 - 2024-02-01 +* prevent sending commands to inverter which isn't active #1387 +* protect commands from popup in `/live` if password is set #1199 + +## 0.8.69 - 2024-01-31 +* merge PR: Dynamic retries, pendular first rx chan #1394 + +## 0.8.68 - 2024-01-29 +* fix HMS / HMT startup +* added `flush_rx` to NRF on TX +* start with heuristics set to `0` +* added warning for WiFi channel 12-14 (ESP8266 only) #1381 + +## 0.8.67 - 2024-01-29 +* fix HMS frequency +* fix display of inverter id in serial log (was displayed twice) + +## 0.8.66 - 2024-01-28 +* added support for other regions - untested #1271 +* fix generation of DTU-ID; was computed twice without reset if two radios are enabled + +## 0.8.65 - 2024-01-24 +* removed patch for NRF `PLOS` +* fix lang issues #1388 +* fix build on Windows of `opendtufusion` environments (git: trailing whitespaces) + +## 0.8.64 - 2024-01-22 +* add `ARC` to log (NRF24 Debug) +* merge PR: ETH NTP update bugfix #1385 + +## 0.8.63 - 2024-01-22 +* made code review +* fixed endless loop #1387 + +## 0.8.62 - 2024-01-21 +* updated version in footer #1381 +* repaired radio statistics #1382 + +## 0.8.61 - 2024-01-21 +* add favicon to header +* improved NRF communication +* merge PR: provide localized times to display mono classes #1376 +* merge PR: Bypass OOM-Crash on minimal version & history access #1378 +* merge PR: Add some REST Api Endpoints to avail_endpoints #1380 + +## 0.8.60 - 2024-01-20 +* merge PR: non blocking nRF loop #1371 +* merge PR: fixed millis in serial log #1373 +* merge PR: fix powergraph scale #1374 +* changed inverter gap to `1` as default (old settings will be overridden) + +## 0.8.59 - 2024-01-18 +* merge PR: solve display settings dependencies #1369 +* fix language typos #1346 +* full update of ePaper after booting #1107 +* fix MqTT yield day reset even if `pause inverter during nighttime` isn't active #1368 + +## 0.8.58 - 2024-01-17 +* fix missing refresh URL #1366 +* fix view of grid profile #1365 +* fix webUI translation #1346 +* fix protection mask #1352 +* merge PR: Add Watchdog for ESP32 #1367 +* merge PR: ETH support for CMT2300A - HMS/HMT #1356 +* full refresh of ePaper after booting #1107 +* add optional custom link #1199 +* pinout has an own subgroup in `/settings` +* grid profile will be displayed as hex in every case #1199 + +## 0.8.57 - 2024-01-15 +* merge PR: fix immediate clearing of display after sunset #1364 +* merge PR: MI-MQTT and last retransmit #1363 +* fixed DTU-ID, now built from the unique part of the MAC +* fix lang in `/system` #1346 +* added protection to prevent update to wrong firmware (environment check) + +## 0.8.56 - 2024-01-15 +* potential fix of update problems and random reboots #1359 #1354 + +## 0.8.55 - 2024-01-14 +* merge PR: fix reboot problem with deactivated power graph #1360 +* changed scope of variables and member functions inside display classes +* removed automatically "minimal" builds +* fix include of "settings.h" (was already done in #1360) +* merge PR: Enhancement: Add info about compiled modules to version string #1357 +* add info about installed binary to `/update` #1353 +* fix lang in `/system` #1346 + +## 0.8.54 - 2024-01-13 +* added minimal version (without: MqTT, Display, History), WebUI is not changed! +* added simulator (must be activated before compile, standard: off) +* changed communication attempts back to 5 + +## 0.8.53 - 2024-01-12 +* fix history graph +* fix MqTT yield day #1331 + +## 0.8.52 - 2024-01-11 +* possible fix of 'division by zero' #1345 +* fix lang #1348 #1346 +* fix timestamp `max AC power` #1324 +* fix stylesheet overlay `max AC power` #1324 +* fix download link #1340 +* fix history graph +* try to fix #1331 + +## 0.8.51 - 2024-01-10 +* fix translation #1346 +* further improve sending active power control command faster #1332 +* added history protection mask +* merge PR: display graph improvements #1347 + +## 0.8.50 - 2024-01-09 +* merge PR: added history charts to web #1336 +* merge PR: small display changes #1339 +* merge PR: MI - add "get loss logic" #1341 +* translated `/history` +* fix translations in title of documents +* added translations for error messages #1343 + +## 0.8.49 - 2024-01-08 +* fix send total values if inverter state is different from `OFF` #1331 +* fix german language issues #1335 + +## 0.8.48 - 2024-01-07 +* merge PR: pin selection for ESP-32 S2 #1334 +* merge PR: enhancement: power graph display option #1330 + +## 0.8.47 - 2024-01-06 +* reduce GxEPD2 lib to compile faster +* upgraded GxEPD2 lib to `1.5.3` +* updated espressif32 platform to `6.5.0` +* updated U8g2 to `2.35.9` +* started to convert deprecated functions of new ArduinoJson `7.0.0` +* started to have german translations of all variants (environments) #925 #1199 +* merge PR: add defines for retry attempts #1329 + +## 0.8.46 - 2024-01-06 +* improved communication + +## 0.8.45 - 2024-01-05 +* fix MqTT total values #1326 +* start implementing a wizard for initial (WiFi) configuration #1199 + +## 0.8.44 - 2024-01-05 +* fix MqTT transmission of data #1326 +* live data is read much earlier / faster and more often #1272 + +## 0.8.43 - 2024-01-04 +* fix display of sunrise in `/system` #1308 +* fix overflow of `getLossRate` calculation #1318 +* improved MqTT by marking sent data and improved `last_success` resends #1319 +* added timestamp for `max ac power` as tooltip #1324 #1123 #1199 +* repaired Power-limit acknowledge #1322 +* fix `max_power` in `/visualization` was set to `0` after sunset + +## 0.8.42 - 2024-01-02 +* add LED to display whether it's night time or not. Can be reused as output to control battery system #1308 +* merge PR: beautifiying typography, added spaces between value and unit for `/visualization` #1314 +* merge PR: Prometheus add `getLossRate` and bugfixing #1315 +* add loss rate to `/visualization` in the statistics window +* corrected `getLossRate` infos for MqTT and prometheus +* added information about working IRQ for NRF24 and CMT2300A to `/system` + +## 0.8.41 - 2024-01-02 +* fix display timeout (OLED) to 60s +* change offs to signed value + +## 0.8.40 - 2024-01-02 +* fix display of sunrise and sunset in `/system` #1308 +* fix MqTT set power limit #1313 + +## 0.8.39 - 2024-01-01 +* fix MqTT dis_night_comm in the morning #1309 #1286 +* seperated offset for sunrise and sunset #1308 +* powerlimit (active power control) now has one decimal place (MqTT / API) #1199 +* merge Prometheus metrics fix #1310 +* merge MI grid profile request #1306 +* merge update documentation / readme #1305 +* add `getLossRate` to radio statistics and to MqTT #1199 + +## 0.8.38 - 2023-12-31 +* fix Grid-Profile JSON #1304 + +## 0.8.37 - 2023-12-30 +* added grid profiles +* format version of grid profile + +# RELEASE 0.8.36 - 2023-12-30 + +## 0.8.35 - 2023-12-30 +* added dim option for LEDS +* changed reload time for opendtufusion after update to 5s +* fix default interval and gap for communication +* fix serial number in exported json (was decimal, now correct as hexdecimal number) +* beautified factory reset +* added second stage for erase settings +* increased maximal number of inverters to 32 for opendtufusion board (ESP32-S3) +* fixed crash if CMT inverter is enabled, but CMT isn't configured + +# RELEASE 0.8.34 - 2023-12-29 + +## 0.8.33 - 2023-12-29 +* improved communication thx @rejoe2 + +## 0.8.32 - 2023-12-29 +* fix `start` / `stop` / `restart` commands #1287 +* added message, if profile was not read until now #1300 +* added developer option to use 'syslog-server' instead of 'web-serail' #1299 + +## 0.8.31 - 2023-12-29 +* added class to handle timeouts PR #1298 + +## 0.8.30 - 2023-12-28 +* added info if grid profile was not found +* merge PR #1293 +* merge PR #1295 fix ESP8266 pin settings +* merge PR #1297 fix layout for OLED displays + +## 0.8.29 - 2023-12-27 +* fix MqTT generic topic `comm_disabled` #1265 #1286 +* potential fix of #1285 (reset yield day) +* fix fraction of yield correction #1280 +* fix crash if `getLossRate` was read from inverter #1288 #1290 +* reduce reload time for opendtufusion ethernet variant to 5 seconds +* added basic grid parser +* added ESP32-C3 mini environment #1289 + +## 0.8.28 - 2023-12-23 +* fix bug heuristic +* add version information to clipboard once 'copy' was clicked +* add get loss rate @rejoe2 +* improve communication @rejoe2 + +## 0.8.27 - 2023-12-18 +* fix set power limit #1276 + +## 0.8.26 - 2023-12-17 +* read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) + +## 0.8.25 - 2023-12-17 +* RX channel ID starts with fixed value #1277 +* fix static IP for Ethernet + +## 0.8.24 - 2023-12-16 +* fix NRF communication for opendtufusion ethernet variant + +## 0.8.23 - 2023-12-14 +* heuristics fix #1269 #1270 +* moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* +* try to prevent access to radio classes if they are not activated +* fixed millis in serial log +* changed 'print whole trace' = `false` as default +* added communication loop duration in [ms] to serial console +* don't print Hex-Payload if 'print whole trace' == `false` + +## 0.8.22 - 2023-12-13 +* fix communication state-machine regarding zero export #1267 + +## 0.8.21 - 2023-12-12 +* fix ethernet save inverter parameters #886 +* fix ethernet OTA update #886 +* improved radio statistics, fixed heuristic output for HMS and HMT inverters + +## 0.8.20 - 2023-12-12 +* improved HM communication #1259 #1249 +* fix `loadDefaults` for ethernet builds #1263 +* don't loop through radios which aren't in use #1264 + +## 0.8.19 - 2023-12-11 +* added ms to serial log +* added (debug) option to configure gap between inverter requests + +## 0.8.18 - 2023-12-10 +* copied even more from the original heuristic code #1259 +* added mDNS support #1262 + +## 0.8.17 - 2023-12-10 +* possible fix of NRF with opendtufusion (without ETH) +* small fix in heuristics (if conditions made assignment not comparisson) + +## 0.8.16 - 2023-12-09 +* fix crash if NRF is not enabled +* updated heuristic #1080 #1259 +* fix compile opendtufusion fusion ethernet + +## 0.8.15 - 2023-12-09 +* added support for opendtufusion fusion ethernet shield #886 +* fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 +* changed `yield effiency` per default to `1.0` #1243 +* small heuristics improvements #1258 +* added class to combine inverter heuristics fields #1258 + +## 0.8.14 - 2023-12-07 +* fixed decimal points for temperature (WebUI) PR #1254 #1251 +* fixed inverter statemachine available state PR #1252 #1253 +* fixed NTP update and sunrise calculation #1240 #886 +* display improvments #1248 #1247 +* fixed overflow in `hmRadio.h` #1244 + +## 0.8.13 - 2023-11-28 +* merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality +* fix MqTT IP addr for ETH connections PR #1240 +* added ethernet build for fusion board, not tested so far + +## 0.8.12 - 2023-11-20 +* added button `copy to clipboard` to `/serial` + +## 0.8.11 - 2023-11-20 +* improved communication, thx @rejoe2 +* improved heuristics, thx @rejoe2, @Oberfritze +* added option to strip payload of frames to significant area + +## 0.8.10 - 2023-11-19 +* fix Mi and HM inverter communication #1235 +* added privacy mode option #1211 +* changed serial debug option to work without reboot + +## 0.8.9 - 2023-11-19 +* merged PR #1234 +* added new alarm codes +* removed serial interval, was not in use anymore + +## 0.8.8 - 2023-11-16 +* fix ESP8266 save inverter #1232 + +## 0.8.7 - 2023-11-13 +* fix ESP8266 inverter settings #1226 +* send radio statistics via MqTT #1227 +* made night communication inverter depended +* added option to prevent adding values of inverter to total values (MqTT only) #1199 + +## 0.8.6 - 2023-11-12 +* merged PR #1225 +* improved heuristics (prevent update of statitistic during testing) + +## 0.8.5 - 2023-11-12 +* fixed endless loop while switching CMT frequency +* removed obsolete "retries" field from settings #1224 +* fixed crash while defining new invertes #1224 +* fixed default frequency settings +* added default input power to `400` while adding new inverters +* fixed color of wifi RSSI icon #1224 + +## 0.8.4 - 2023-11-10 +* changed MqTT alarm topic, removed retained flag #1212 +* reduce last_success MQTT messages (#1124) +* introduced tabs in WebGUI (inverter settings) +* added inverter-wise power level and frequency + +## 0.8.3 - 2023-11-09 +* fix yield day reset during day #848 +* add total AC Max Power to WebUI +* fix opendtufusion build (GxEPD patch) +* fix null ptr PR #1222 + +## 0.8.2 - 2023-11-08 +* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) + +## 0.8.1 - 2023-11-05 +* added tx channel heuristics (per inverter) +* fix statistics counter + +## 0.8.0 - 2023-10-?? +* switched to new communication scheme + +## 0.7.66 - 2023-10-04 +* prepared PA-Level for CMT +* removed settings for number of retransmits, its fixed to `5` now +* added parentheses to have a excactly defined behaviour + +## 0.7.65 - 2023-10-02 +* MI control command review #1197 + +## 0.7.64 - 2023-10-02 +* moved active power control to modal in `live` view (per inverter) by click on current APC state + +## 0.7.63 - 2023-10-01 +* fix NRF24 communication #1200 + +## 0.7.62 - 2023-10-01 +* fix communication to inverters #1198 +* add timeout before payload is tried to process (necessary for HMS/HMT) + +## 0.7.61 - 2023-10-01 +* merged `hmPayload` and `hmsPayload` into single class +* merged generic radio functions into new parent class `radio.h` +* moved radio statistics into the inverter - each inverter has now seperate statistics which can be accessed by click on the footer in `/live` +* fix compiler warnings #1191 +* fix ePaper logo during night time #1151 + +## 0.7.60 - 2023-09-27 +* fixed typos in changelog #1172 +* fixed MqTT manual clientId storage #1174 +* fixed inverter name length in setup #1181 +* added inverter name to the header of alarm list #1181 +* improved code to avoid warning during compilation #1182 +* fix scheduler #1188, #1179 + +## 0.7.59 - 2023-09-20 +* re-add another HM-400 hardware serial number accidentally removed with `0.7.45` (#1169) +* merge PR #1170 +* reduce last_success MQTT messages (#1124) +* add re-request if inverter is known to be online and first try fails +* add alarm reporting to MI (might need review!) +* rebuild MI limiting code closer to DTUSimMI example +* round APC in `W` to an integer #1171 + +## 0.7.58 +* fix ESP8266 save settings issue #1166 + +## 0.7.57 - 2023-09-18 +* fix Alarms are always in queue (since 0.7.56) +* fix display active power control to long for small devices #1165 + +## 0.7.56 - 2023-09-17 +* only request alarms which were not received before #1113 +* added flag if alarm was requested but not received and re-request it #1105 +* merge PR #1163 + +## 0.7.55 - 2023-09-17 +* fix prometheus builds +* fix ESP32 default pinout #1159 +* added `opendtufusion-dev` because of annoying `-DARDUINO_USB_CDC_ON_BOOT=1` flag +* fix display of current power on `index` +* fix OTA, was damaged by version `0.7.51`, need to use webinstaller (from `0.7.51` to `0.7.54`) + +## 0.7.54 - 2023-09-16 +* added active power control in `W` to live view #201, #673 +* updated docu, active power control related #706 +* added current AC-Power to `index` page and removed version #763 +* improved statistic data, moved to entire struct +* removed `/api/statistics` endpoint from REST-API + +## 0.7.53 - 2023-09-16 +* fix ePaper / display night behaviour #1151 +* fix ESP8266 compile error + +## 0.7.52 - 2023-09-16 +* fix CMT configurable pins #1150, #1159 +* update MqTT lib to version `1.4.5` + +## 0.7.51 - 2023-09-16 +* fix CMT configurable pins #1150 +* fix default CMT pins for opendtufusion +* beautified `system` +* changed main loops, fix resets #1125, #1135 + +## 0.7.50 - 2023-09-12 +* moved MqTT info to `system` +* added CMT info for ESP32 devices +* improved CMT settings, now `SCLK` and `SDIO` are configurable #1046, #1150 +* changed `Power-Limit` in live-view to `Active Power Control` +* increase length of update file selector #1132 + +## 0.7.49 - 2023-09-11 +* merge PR: symbolic icons for mono displays, PR #1136 +* merge MI code restructuring PR #1145 +* merge Prometheus PR #1148 +* add option to strip webUI for ESP8266 (reduce code size, add ESP32 special features; `IF_ESP32` directives) +* started to get CMT info into `system` - not finished + +## 0.7.48 - 2023-09-10 +* fix SSD1309 2.42" display pinout +* improved setup page: save and delete of inverters + +## 0.7.47 - 2023-09-07 +* fix boot loop #1140 +* fix regex in `setup` page +* fix MI serial number display `max-module-power` in `setup` #1142 +* renamed `opendtufusionv1` to `opendtufusion` + +## 0.7.46 - 2023-09-04 +* removed `delay` from ePaper +* started improvements of `/system` +* fix LEDs to check all configured inverters +* send loop skip disabled inverters fix +* print generated DTU SN to console +* HW Versions for MI series PR #1133 +* 2.42" display (SSD1309) integration PR #1139 +* update user manual PR #1121 +* add / rename alarm codes PR #1118 +* revert default pin ESP32 for NRF23-CE #1132 +* luminance of display can be changed during runtime #1106 + +## 0.7.45 - 2023-08-29 +* change ePaper text to symbols PR #1131 +* added some invertes to dev info list #1111 + +## 0.7.44 - 2023-08-28 +* fix `last_success` transmitted to often #1124 + +## 0.7.43 - 2023-08-28 +* improved RSSI for NRF24, now it's read per package (and inverter) #1129 +* arranged `heap` related info together in `/system` +* fix display navi during save +* clean up binary output, separated to folders + +## 0.7.42 - 2023-08-27 +* fix ePaper for opendtufusion_v2.x boards (Software SPI) +* add signal strength for NRF24 - PR #1119 +* refactor wifi class to support ESP32 S2 PR #1127 +* update platform for ESP32 to 6.3.2 +* fix opendtufusion LED (were mixed) +* fix `last_success` transmitted to often #1124 +* added ESP32-S3-mini to github actions +* added old Changelog Entries, to have full log of changes + +## 0.7.41 - 2023-08-26 +* merge PR #1117 code spelling fixes #1112 +* alarms were not read after the first day + +## 0.7.40 - 2023-08-21 +* added default pins for opendtu-fusion-v1 board +* fixed hw version display in `live` +* removed development builds, renamed environments in `platform.ini` + +## 0.7.39 - 2023-08-21 +* fix background color of invalid inputs +* add hardware info (click in `live` on inverter name) + +## 0.7.38 - 2023-08-21 +* reset alarms at midnight (if inverter is not available) #1105, #1096 +* add option to reset 'max' values on midnight #1102 +* added default pins for CMT2300A (matching OpenDTU) + +## 0.7.37 - 2023-08-18 +* fix alarm time on WebGui #1099 +* added RSSI info for HMS and HMT inverters (MqTT + REST API) + +# RELEASE 0.7.36 - 2023-08-18 + +## 0.7.35 - 2023-08-17 +* fixed timestamp for alarms send over MqTT +* auto-patch of `AsyncWebServer` #834, #1036 +* Update documentation in Git regarding `ESP8266` default NRF24 pin assignments + +## 0.7.34 - 2023-08-16 +* fixed timezone offset of alarms +* added `AC` and `DC` to `/live` #1098 +* changed `ESP8266` default NRF24 pin assignments (`D3` = `CE` and `D4` = `IRQ`) +* fixed background of modal window for bright color +* fix MI crashes +* fix some lost debug messages +* merged PR #1095, MI fixes for 0.7.x versions +* fix scheduled reboot #1097 +* added vector graphic logo `/doc/logo.svg` +* merge PR #1093, improved Nokia5110 display layout + +## 0.7.33 - 2023-08-15 +* add alarms overview to WebGui #608 +* fix webGui total values #1084 + +## 0.7.32 - 2023-08-14 +* fix colors of live view #1091 + +## 0.7.31 - 2023-08-13 +* fixed docu #1085 +* changed active power limit MqTT messages to QOS2 #1072 +* improved alarm messages, added alarm-id to log #1089 +* trigger power limit read on next day (if inverter was offline meanwhile) +* disabled improv implementation to check if it is related to 'Schwuppdizitaet' +* changed live view to gray once inverter isn't available +* added inverter status to API +* changed sum of totals on WebGui depending on inverter status #1084 +* merge maximum power (AC and DC) from PR #1080 + +## 0.7.30 - 2023-08-10 +* attempt to improve speed / response times (Schwuppdizitaet) #1075 + +## 0.7.29 - 2023-08-09 +* MqTT alarm data was never sent, fixed +* REST API: added alarm data +* REST API: made get record obsolete +* REST API: added power limit acknowledge `/api/inverter/id/[0-x]` #1072 + +## 0.7.28 - 2023-08-08 +* fix MI inverter support #1078 + +## 0.7.27 - 2023-08-08 +* added compile option for ethernet #886 +* fix ePaper configuration, missing `Busy`-Pin #1075 + +# RELEASE 0.7.26 - 2023-08-06 + +* fix MqTT `last_success` + +# RELEASE 0.7.25 - 2023-08-06 + +## 0.7.24 - 2023-08-05 +* merge PR #1069 make MqTT client ID configurable +* fix #1016, general MqTT status depending on inverter state machine +* changed icon for fully available inverter to a filled check mark #1070 +* fixed `last_success` update with MqTT #1068 +* removed `improv` esp-web-installer script, because it is not fully functional at this time + +## 0.7.23 - 2023-08-04 +* merge PR #1056, visualization html +* update MqTT library to 1.4.4 +* update RF24 library to 1.4.7 +* update ArduinoJson library to 6.21.3 +* set minimum invervall for `/live` to 5 seconds + +## 0.7.22 - 2023-08-04 +* attempt to fix homeassistant auto discovery #1066 + +## 0.7.21 - 2023-07-30 +* fix MqTT YieldDay Total goes to 0 several times #1016 + +## 0.7.20 - 2023-07-28 +* merge PR #1048 version and hash in API, fixes #1045 +* fix: no yield day update if yield day reads `0` after inverter reboot (mostly on evening) #848 +* try to fix Wifi override #1047 +* added information after NTP sync to WebUI #1040 + +## 0.7.19 - 2023-07-27 +* next attempt to fix yield day for multiple inverters #1016 +* reduced threshold for inverter state machine from 60min to 15min to go from state `WAS_ON` to `OFF` + +## 0.7.18 - 2023-07-26 +* next attempt to fix yield day for multiple inverters #1016 + +## 0.7.17 - 2023-07-25 +* next attempt to fix yield day for multiple inverters #1016 +* added two more states for the inverter status (also docu) + +## 0.7.16 - 2023-07-24 +* next attempt to fix yield day for multiple inverters #1016 +* fix export settings date #1040 +* fix time on WebUI (timezone was not observed) #913 #1016 + +## 0.7.15 - 2023-07-23 +* add NTP sync interval #1019 +* adjusted range of contrast / luminance setting #1041 +* use only ISO time format in Web-UI #913 + +## 0.7.14 - 2023-07-23 +* fix Contrast for Nokia Display #1041 +* attempt to fix #1016 by improving inverter status +* added option to adjust efficiency for yield (day/total) #1028 + +## 0.7.13 - 2023-07-19 +* merged display PR #1027 +* add date, time and version to export json #1024 + +## 0.7.12 - 2023-07-09 +* added inverter status - state-machine #1016 + +## 0.7.11 - 2023-07-09 +* fix MqTT endless loop #1013 + +## 0.7.10 - 2023-07-08 +* fix MqTT endless loop #1013 + +## 0.7.9 - 2023-07-08 +* added 'improve' functions to set wifi password directly with ESP web tools #1014 +* fixed MqTT publish while applying power limit #1013 +* slightly improved HMT live view (Voltage & Current) + +## 0.7.8 - 2023-07-05 +* fix `YieldDay`, `YieldTotal` and `P_AC` in `TotalValues` #929 +* fix some serial debug prints +* merge PR #1005 which fixes issue #889 +* merge homeassistant PR #963 +* merge PR #890 which gives option for scheduled reboot at midnight (default off) + +## 0.7.7 - 2023-07-03 +* attempt to fix MqTT `YieldDay` in `TotalValues` #927 +* attempt to fix MqTT `YieldDay` and `YieldTotal` even if inverters are not completely available #929 +* fix wrong message 'NRF not connected' if it is disabled #1007 + +## 0.7.6 - 2023-06-17 +* fix display of hidden SSID checkbox +* changed yield correction data type to `double`, now decimal places are supported +* corrected name of 0.91" display in settings +* attempt to fix MqTT zero values only if setting is there #980, #957 +* made AP password configurable #951 +* added option to start without time-sync, eg. for AP-only-mode #951 + +## 0.7.5 - 2023-06-16 +* fix yield day reset on midnight #957 +* improved tickers in `app.cpp` + +## 0.7.4 - 2023-06-15 +* fix MqTT `P_AC` send if inverters are available #987 +* fix assignments for HMS 1CH and 2CH devices +* fixed uptime overflow #990 + +## 0.7.3 - 2023-06-09 +* fix hidden SSID scan #983 +* improved NRF24 missing message on home screen #981 +* fix MqTT publishing only updated values #982 + +## 0.7.2 - 2023-06-08 +* fix HMS-800 and HMS-1000 assignments #981 +* make nrf enabled all the time for ESP8266 +* fix menu item `active` highlight for 'API' and 'Doku' +* fix MqTT totals issue #927, #980 +* reduce maximum number of inverters to 4 for ESP8266, increase to 16 for ESP32 + +## 0.7.1 - 2023-06-05 +* enabled power limit control for HMS / HMT devices +* changed NRF24 lib version back to 1.4.5 because of compile problems for EPS8266 + +## 0.7.0 - 2023-06-04 +* HMS / HMT support for ESP32 devices + +## 0.6.15 - 2023-05-25 +* improved Prometheus Endpoint PR #958 +* fix turn off ePaper only if setting was set #956 +* improved reset values and update MqTT #957 + +## 0.6.14 - 2023-05-21 +* merge PR #902 Mono-Display + +## 0.6.13 - 2023-05-16 +* merge PR #934 (fix JSON API) and #944 (update manual) + +## 0.6.12 - 2023-04-28 +* improved MqTT +* fix menu active item + +## 0.6.11 - 2023-04-27 +* added MqTT class for publishing all values in Arduino `loop` + +## 0.6.10 - HMS +* Version available in `HMS` branch + +# RELEASE 0.6.9 - 2023-04-19 + +## 0.6.8 - 2023-04-19 +* fix #892 `zeroYieldDay` loop was not applied to all channels + +## 0.6.7 - 2023-04-13 +* merge PR #883, improved store of settings and javascript, thx @tastendruecker123 +* support `.` and `,` as floating point separator in setup #881 + +## 0.6.6 - 2023-04-12 +* increased distance for `import` button in mobile view #879 +* changed `led_high_active` to `bool` #879 + +## 0.6.5 - 2023-04-11 +* fix #845 MqTT subscription for `ctrl/power/[IV-ID]` was missing +* merge PR #876, check JSON settings during read for existence +* **NOTE:** incompatible change: renamed `led_high_active` to `act_high`, maybe setting must be changed after update +* merge PR #861 do not send channel metric if channel is disabled + +## 0.6.4 - 2023-04-06 +* merge PR #846, improved NRF24 communication and MI, thx @beegee3 & @rejoe2 +* merge PR #859, fix burger menu height, thx @ThomasPohl + +## 0.6.3 - 2023-04-04 +* fix login, password length was not checked #852 +* merge PR #854 optimize browser caching, thx @tastendruecker123 #828 +* fix WiFi reconnect not working #851 +* updated issue templates #822 + +## 0.6.2 - 2023-04-04 +* fix login from multiple clients #819 +* fix login screen on small displays + +## 0.6.1 - 2023-04-01 +* merge LED fix - LED1 shows MqTT state, LED configurable active high/low #839 +* only publish new inverter data #826 +* potential fix of WiFi hostname during boot up #752 + +# RELEASE 0.6.0 - 2023-03-27 + +## 0.5.110 +* MQTT fix reconnection by new lib version #780 +* add `about` page +* improved documentation regarding SPI pins #814 +* improved documentation (getting started) #815 #816 +* improved MI 4-ch inverter #820 + +## 0.5.109 +* reduced heap fragmentation by optimizing MqTT #768 +* ePaper: centered text thx @knickohr + +## 0.5.108 +* merge: PR SPI pins configurable (ESP32) #807, #806 (requires manual set of MISO=19, MOSI=23, SCLK=18 in GUI for existing installs) +* merge: PR MI serial outputs #809 +* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805 +* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805 + +## 0.5.107 +* fix: show save message +* fix: removed serial newline for `enqueueCmd` +* Merged improved Prometheus #808 + +## 0.5.106 +* merged MI and debug message changes #804 +* fixed MQTT autodiscover #794, #632 + +## 0.5.105 +* merged MI, thx @rejoe2 #788 +* fixed reboot message #793 + +## 0.5.104 +* further improved save settings +* removed `#` character from ePaper +* fixed saving pinout for `Nokia-Display` +* removed `Reset` Pin for monochrome displays +* improved wifi connection #652 + +## 0.5.103 +* merged MI improvements, thx @rejoe2 #778 +* changed display inverter online message +* merged heap improvements #772 + +## 0.5.102 +* Warning: old exports are not compatible any more! +* fix JSON import #775 +* fix save settings, at least already stored settings are not lost #771 +* further save settings improvements (only store inverters which are existing) +* improved display of settings save return value +* made save settings asynchronous (more heap memory is free) + +## 0.5.101 +* fix SSD1306 +* update documentation +* Update miPayload.h +* Update README.md +* MI - remarks to user manual +* MI - fix AC calc +* MI - fix status msg. analysis + +## 0.5.100 +* fix add inverter `setup.html` #766 +* fix MQTT retained flag for total values #726 +* renamed buttons for import and export `setup.html` +* added serial message `settings saved` + +## 0.5.99 +* fix limit in [User_Manual.md](../User_Manual.md) +* changed `contrast` to `luminance` in `setup.html` +* try to fix SSD1306 display #759 +* only show necessary display pins depending on setting + +## 0.5.98 +* fix SH1106 rotation and turn off during night #756 +* removed MQTT subscription `sync_ntp`, `set_time` with a value of `0` does the same #696 +* simplified MQTT subscription for `limit`. Check [User_Manual.md](../User_Manual.md) for new syntax #696, #713 +* repaired inverter wise limit control +* fix upload settings #686 + +## 0.5.97 +* Attention: re-ordered display types, check your settings! #746 +* improved saving settings of display #747, #746 +* disabled contrast for Nokia display #746 +* added Prometheus as compile option #719, #615 +* update MQTT lib to v1.4.1 +* limit decimal places to 2 in `live` +* added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657 +* a `max-module-power` of `0` disables channel in live view `setup` +* merge MI improvements, get firmware information #753 + +## 0.5.96 +* added Nokia display again for ESP8266 #764 +* changed `var` / `VAr` to SI unit `var` #732 +* fix MQTT retained flags for totals (P_AC, P_DC) #726, #721 + +## 0.5.95 +* merged #742 MI Improvements +* merged #736 remove obsolete JSON Endpoint + +## 0.5.94 +* added ePaper (for ESP32 only!), thx @dAjaY85 #735 +* improved `/live` margins #732 +* renamed `var` to `VAr` #732 + +## 0.5.93 +* improved web API for `live` +* added dark mode option +* converted all forms to reponsive design +* repaired menu with password protection #720, #716, #709 +* merged MI series fixes #729 + +## 0.5.92 +* fix mobile menu +* fix inverters in select `serial.html` #709 + +## 0.5.91 +* improved html and navi, navi is visible even when API dies #660 +* reduced maximum allowed JSON size for API to 6000Bytes #660 +* small fix: output command at `prepareDevInformCmd` #692 +* improved inverter handling #671 + +## 0.5.90 +* merged PR #684, #698, #705 +* webserial minor overflow fix #660 +* web `index.html` improve version information #701 +* fix MQTT sets power limit to zero (0) #692 +* changed `reset at midnight` with timezone #697 + +## 0.5.89 +* reduced heap fragmentation (removed `strtok` completely) #644, #645, #682 +* added part of mac address to MQTT client ID to separate multiple ESPs in same network +* added dictionary for MQTT to reduce heap-fragmentation +* removed `last Alarm` from Live view, because it showed always the same alarm - will change in future + +## 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 + +## 0.5.86 +* prevent send devcontrol request during disabled night communication +* changed yield total correction as module (inverter input) value #570 +* MQTT Yield Day zero, next try to fix #671 + +## 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 +* fixed 'polling stop message' on `index.html` #639 + +## 0.5.84 +* fix blue LED lights up all the time #672 +* added an instant start communication (once NTP is synced) +* add MI 3rd generation inverters (10x2 serial numbers) +* first decodings of messages from MI 2nd generation inverters + +## 0.5.83 +* fix MQTT publishing, `callback` was set but reset by following `setup()` + +## 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`) + +## 0.5.80 +* fixed communication #656 + +## 0.5.79 +* fixed mixed reset flags #648 +* fixed `mCbAlarm` if MQTT is not used #653 +* fixed MQTT `autodiscover` #630 thanks to @antibill51 +* next changes from @beegee many thanks for your contribution! +* replaced `CircularBuffer` by `std::queue` +* reworked `hmRadio.h` completely (interrupts, packaging) +* fix exception while `reboot` +* cleanup MQTT coding + +## 0.5.78 +* further improvements regarding wifi #611, fix connection if only one AP with same SSID is there +* fix endless loop in `zerovalues` #564 +* fix auto discover again #565 +* added total values to autodiscover #630 +* improved zero at midnight #625 + +## 0.5.77 +* fix wrong filename for automatically created manifest (online installer) #620 +* added rotate display feature #619 +* improved Prometheus endpoint #615, thx to @fsck-block +* improved wifi to connect always to strongest RSSI, thx to @beegee3 #611 + +## 0.5.76 +* reduce MQTT retry interval from maximum speed to one second +* fixed homeassistant autodiscovery #565 +* implemented `getNTPTime` improvements #609 partially #611 +* added alarm messages to MQTT #177, #600, #608 + +## 0.5.75 +* fix wakeup issue, once wifi was lost during night the communication didn't start in the morning +* re-enabled FlashStringHelper because of lacking RAM +* complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup +* fix power limit not possible #607 + +## 0.5.74 +* improved payload handling (retransmit all fragments on CRC error) +* improved `isAvailable`, checks all record structs, inverter becomes available more early because version is check first +* fix tickers were not set if NTP is not available +* disabled annoying `FlashStringHelper` it gives randomly Exceptions during development, feels more stable since then +* moved erase button to the bottom in settings, not nice but more functional +* split `tx_count` to `tx_cnt` and `retransmits` in `system.html` +* fix mqtt retransmit IP address #602 +* added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console) + +## 0.5.73 +* improved payload handling (request / retransmit) #464 +* included alarm ID parse to serial console (in development) + +## 0.5.72 +* repaired system, scheduler was not called any more #596 + +## 0.5.71 +* improved wifi handling and tickers, many thanks to @beegee3 #571 +* fixed YieldTotal correction calculation #589 +* fixed serial output of power limit acknowledge #569 +* reviewed `sendDiscoveryConfig` #565 +* merged PR `Monodisplay`, many thanks to @dAjaY85 #566, Note: (settings are introduced but not able to be modified, will be included in next version) + +## 0.5.70 +* corrected MQTT `comm_disabled` #529 +* fix Prometheus and JSON endpoints (`config_override.h`) #561 +* publish MQTT with fixed interval even if inverter is not available #542 +* added JSON settings upload. NOTE: settings JSON download changed, so only settings should be uploaded starting from version `0.5.70` #551 +* MQTT topic and inverter name have more allowed characters: `[A-Za-z0-9./#$%&=+_-]+`, thx: @Mo Demman +* improved potential issue with `checkTicker`, thx @cbscpe +* MQTT option for reset values on midnight / not avail / communication stop #539 +* small fix in `tickIVCommunication` #534 +* add `YieldTotal` correction, eg. to have the option to zero at year start #512 + +## 0.5.69 +* merged SH1106 1.3" Display, thx @dAjaY85 +* added SH1106 to automatic build +* added IP address to MQTT (version, device and IP are retained and only transmitted once after boot) #556 +* added `set_power_limit` acknowledge MQTT publish #553 +* changed: version, device name are only published via MQTT once after boot +* added `Login` to menu if admin password is set #554 +* added `development` to second changelog link in `index.html` #543 +* added interval for MQTT (as option). With this settings MQTT live data is published in a fixed timing (only if inverter is available) #542, #523 +* added MQTT `comm_disabled` #529 +* changed name of binaries, moved GIT-Sha to the front #538 + +## 0.5.68 +* repaired receive payload +* Powerlimit is transferred immediately to inverter + +## 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 +* payload: if last frame is missing, request all frames again + +# RELEASE 0.5.66 - 2022-12-30 + +## 0.5.65 +* wifi, code optimization #509 + +## 0.5.64 +* channel name can use any character, not limited any more +* added `/` to MQTT topic and Inverter name +* trigger for `calcSunrise` is now using local time #515 +* fix reconnect timeout for WiFi #509 +* start AP only after boot, not on WiFi connection loss +* improved /system `free_heap` value (measured before JSON-tree is built) + +## 0.5.63 +* fix Update button protection (prevent double click #527) +* optimized scheduler #515 (thx @beegee3) +* potential fix of #526 duplicates in API `/api/record/live` +* added update information to `index.html` + +## 0.5.62 +* fix MQTT `status` update +* removed MQTT `available_text` (can be deducted from `available`) +* enhanced MQTT documentation in `User_Manual.md` +* removed `tickSunset` and `tickSunrise` from MQTT. It's not needed any more because of minute wise check of status (`processIvStatus`) +* changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` +* fix regular expression of `setup.html` for inverter name and channel name + +## 0.5.61 +* fix #521 no reconnect at beginning of day +* added immediate (each minute) report of inverter status MQTT #522 +* added protection mask to select which pages should be protected +* update of monochrome display, show values also if nothing changed + +## 0.5.60 +* added regex to inverter name and MQTT topic (setup.html) +* beautified serial.html +* added ticker for wifi loop #515 + +## 0.5.59 +* fix night communication enable +* improved different WiFi connection scenarios (STA WiFi not found, reconnect #509, redirect for AP to configuration) +* increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 + +## 0.5.58 +* improved stability +* improved WiFi initial connection - especially if station WiFi is not available +* removed new operators from web.h (reduce dynamic allocation) +* improved sun calculation #515, #505 +* fixed WiFi auto reconnect #509 +* added disable night communication flag to MQTT #505 +* changed MQTT publish of `available` and `available_text` to sunset #468 + +## 0.5.57 +* improved stability +* added icons to index.html, added WiFi-strength symbol on each page +* moved packet stats and sun to system.html +* refactored communication offset (adjustable in minutes now) + +## 0.5.56 +* factory reset formats entire little fs +* renamed sunrise / sunset on index.html to start / stop communication +* show system information only if called directly from menu +* beautified system.html + +## 0.5.55 +* fixed static IP save + +## 0.5.54 +* changed sunrise / sunset calculation, angle is now `-3.5` instead of original `-0.83` +* improved scheduler (removed -1 from `reload`) #483 +* improved reboot flag in `app.h` +* fixed #493 no MQTT payload once display is defined + +## 0.5.53 +* Mono-Display: show values in offline mode #498 +* improved WiFi class #483 +* added communication enable / disable (to test multiple DTUs with the same inverter) +* fix factory reset #495 + +## 0.5.52 +* improved ahoyWifi class +* added interface class for app +* refactored web and webApi -> RestApi +* fix calcSunrise was not called every day +* added MQTT RX counter to index.html +* all values are displayed on /live even if they are 0 +* added MQTT /status to show status over all inverters + +## 0.5.51 +* improved scheduler, @beegee3 #483 +* refactored get NTP time, @beegee3 #483 +* generate `bin.gz` only for 1M device ESP8285 +* fix calcSunrise was not called every day +* increased number of allowed characters for MQTT user, broker and password, @DanielR92 +* added NRF24 info to Systeminfo, @DanielR92 +* added timezone for monochrome displays, @gh-fx2 +* added support for second inverter for monochrome displays, @gh-fx2 + +## 0.5.50 +* fixed scheduler, uptime and timestamp counted too fast +* added / renamed automatically build outputs +* fixed MQTT ESP uptime on reconnect (not zero any more) +* changed uptime on index.html to count each second, synced with ESP each 10 seconds + +## 0.5.49 +* fixed AP mode on brand new ESP modules +* fixed `last_success` MQTT message +* fixed MQTT inverter available status at sunset +* reordered enqueue commands after boot up to prevent same payload length for successive commands +* added automatic build for Nokia5110 and SSD1306 displays (ESP8266) + +## 0.5.48 +* added MQTT message send at sunset +* added monochrome display support +* added `once` and `onceAt` to scheduler to make code cleaner +* improved sunrise / sunset calculation + +## 0.5.47 +* refactored ahoyWifi class: AP is opened on every boot, once station connection is successful the AP will be closed +* improved NTP sync after boot, faster sync +* fix NRF24 details only on valid SPI connection + +## 0.5.46 +* fix sunrise / sunset calculation +* improved setup.html: `reboot on save` is checked as default + +## 0.5.45 +* changed MQTT last will topic from `status` to `mqtt` +* fix sunrise / sunset calculation +* fix time of serial web console + +## 0.5.44 +* marked some MQTT messages as retained +* moved global functions to global location (no duplicates) +* changed index.html interval to static 10 seconds +* fix static IP +* fix NTP with static IP +* print MQTT info only if MQTT was configured + +## 0.5.43 +* updated REST API and MQTT (both of them use the same functionality) +* added ESP-heap information as MQTT message +* changed output name of automatic development build to fixed name (to have a static link from https://ahoydtu.de) +* updated user manual to latest MQTT and API changes + +## 0.5.42 +* fix web logout (auto logout) +* switched MQTT library + +# RELEASE 0.5.41 - 2022-11-22 + +# RELEASE 0.5.28 - 2022-10-30 + +# RELEASE 0.5.17 - 2022-09-06 + +# RELEASE 0.5.16 - 2022-09-04 -full version log: [Development Log](https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md) diff --git a/src/defines.h b/src/defines.h index bf111d99..edcde7a0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 83 +#define VERSION_PATCH 84 //------------------------------------- typedef struct { diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 369d9ead..ea6f331e 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -397,6 +397,10 @@ class PubMqtt { std::array name; std::array uniq_id; std::array buf; + topic.fill(0); + name.fill(0); + uniq_id.fill(0); + buf.fill(0); const char *devCls, *stateCls; if (!total) { if (rec->assign[mDiscovery.sub].ch == CH0) @@ -420,7 +424,7 @@ class PubMqtt { DynamicJsonDocument doc2(512); constexpr static char* unitTotal[] = {"W", "kWh", "Wh", "W"}; - doc2[F("name")] = name; + doc2[F("name")] = String(name.data()); doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic.data()); doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(mDiscovery.sub, rec)) : (unitTotal[mDiscovery.sub])); doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id.data(); @@ -437,7 +441,6 @@ class PubMqtt { else // total values snprintf(topic.data(), topic.size(), "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); size_t size = measureJson(doc2) + 1; - buf.fill(0); serializeJson(doc2, buf.data(), size); publish(topic.data(), buf.data(), true, false); From f5009993463bda5280a4dcb075c76cfca74f5d2d Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 19 Feb 2024 23:09:32 +0100 Subject: [PATCH 62/79] 0.8.84 - 2024-02-19 * merge PR: more gracefull handling of complete retransmits #1433 --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index e55145c5..98e1437c 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,7 @@ ## 0.8.84 - 2024-02-19 * fix homeassistant autodiscovery #1432 +* merge PR: more gracefull handling of complete retransmits #1433 # RELEASE 0.8.83 - 2024-02-16 From b6afec1c3ad2ee97fcaa4ca72616e5732e6538bd Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 22 Feb 2024 23:36:07 +0100 Subject: [PATCH 63/79] 0.8.85 - 2024-02-22 * possible fix of MqTT fix "total values are sent to often" #1421 * fix translation #1442 * availability check only related to live data #1035 #1437 --- src/CHANGES.md | 5 +++++ src/app.cpp | 3 +-- src/defines.h | 2 +- src/hm/hmInverter.h | 12 +++--------- src/publisher/pubMqttIvData.h | 7 +++++-- src/web/html/serial.html | 2 +- src/web/lang.json | 8 +++++++- 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 98e1437c..003c8cef 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.85 - 2024-02-22 +* possible fix of MqTT fix "total values are sent to often" #1421 +* fix translation #1442 +* availability check only related to live data #1035 #1437 + ## 0.8.84 - 2024-02-19 * fix homeassistant autodiscovery #1432 * merge PR: more gracefull handling of complete retransmits #1433 diff --git a/src/app.cpp b/src/app.cpp index 0bead49e..f53af865 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -472,6 +472,7 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { continue; } + changed = true; record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); for(uint8_t ch = 0; ch <= iv->channels; ch++) { uint8_t pos = 0; @@ -494,10 +495,8 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { iv->setValue(pos, rec, 0.0f); } iv->resetAlarms(); - iv->doCalculations(); } - changed = true; } if(changed) diff --git a/src/defines.h b/src/defines.h index edcde7a0..fc4988e6 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 84 +#define VERSION_PATCH 85 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 50b4267c..b7fb00a1 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -407,23 +407,17 @@ class Inverter { bool isAvailable() { bool avail = false; - if((recordMeas.ts == 0) && (recordInfo.ts == 0) && (recordConfig.ts == 0) && (recordAlarm.ts == 0)) + if(recordMeas.ts == 0) return false; - if((*timestamp - recordMeas.ts) < INVERTER_INACT_THRES_SEC) - avail = true; - if((*timestamp - recordInfo.ts) < INVERTER_INACT_THRES_SEC) - avail = true; - if((*timestamp - recordConfig.ts) < INVERTER_INACT_THRES_SEC) - avail = true; - if((*timestamp - recordAlarm.ts) < INVERTER_INACT_THRES_SEC) + if(((*timestamp) - recordMeas.ts) < INVERTER_INACT_THRES_SEC) avail = true; if(avail) { if(status < InverterStatus::PRODUCING) status = InverterStatus::STARTING; } else { - if((*timestamp - recordMeas.ts) > INVERTER_OFF_THRES_SEC) { + if(((*timestamp) - recordMeas.ts) > INVERTER_OFF_THRES_SEC) { if(status != InverterStatus::OFF) { status = InverterStatus::OFF; actPowerLimit = 0xffff; // power limit will be read once inverter becomes available diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index c3ae3814..c15c9799 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -75,6 +75,7 @@ class PubMqttIvData { mTotalFound = false; mSendTotalYd = true; mAllTotalFound = true; + mAtLeastOneWasntSent = false; if(!mSendList->empty()) { mCmd = mSendList->front().cmd; mIvSend = mSendList->front().iv; @@ -122,7 +123,7 @@ class PubMqttIvData { mIv->isProducing(); // recalculate status mState = SEND_DATA; - } else if(mSendTotals && mTotalFound) { + } else if(mSendTotals && mTotalFound && mAtLeastOneWasntSent) { if(mYldTotalStore > mTotal[2]) mSendTotalYd = false; // don't send yield total if last value was greater else @@ -177,6 +178,7 @@ class PubMqttIvData { } if (MqttSentStatus::LAST_SUCCESS_SENT == rec->mqttSentStatus) { + mAtLeastOneWasntSent = true; if(InverterDevInform_All == mCmd) { snprintf(mSubTopic.data(), mSubTopic.size(), "%s/firmware", mIv->config->name); snprintf(mVal.data(), mVal.size(), "{\"version\":%d,\"build_year\":\"%d\",\"build_month_day\":%d,\"build_hour_min\":%d,\"bootloader\":%d}", @@ -282,7 +284,8 @@ class PubMqttIvData { uint8_t mCmd = 0; uint8_t mLastIvId = 0; - bool mSendTotals = false, mTotalFound = false, mAllTotalFound = false, mSendTotalYd = false; + bool mSendTotals = false, mTotalFound = false, mAllTotalFound = false; + bool mSendTotalYd = false, mAtLeastOneWasntSent = false; float mTotal[5], mYldTotalStore = 0; Inverter<> *mIv = nullptr, *mIvSend = nullptr; diff --git a/src/web/html/serial.html b/src/web/html/serial.html index 83e614c8..ff63772c 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -35,7 +35,7 @@ var hrs = parseInt(up / 3600) % 24; var min = parseInt(up / 60) % 60; var sec = up % 60; - document.getElementById("uptime").innerHTML = days + " Days, " + document.getElementById("uptime").innerHTML = days + " {#DAYS}, " + ("0"+hrs).substr(-2) + ":" + ("0"+min).substr(-2) + ":" + ("0"+sec).substr(-2); diff --git a/src/web/lang.json b/src/web/lang.json index 066370c5..727eadcd 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -898,6 +898,12 @@ "en": "uptime", "de": "Laufzeit" } +, + { + "token": "DAYS", + "en": "days", + "de": "Tage" + } ] }, { @@ -986,7 +992,7 @@ { "token": "NIGHT_TIME", "en": "Night time, inverter polling disabled", - "de": "Wechselrichterabfrage deaktivert (Nacht)" + "de": "Wechselrichterabfrage deaktiviert (Nacht)" }, { "token": "PAUSED_AT", From 6d887e15402f88565aa2bd4f7f3c78b41a735332 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 24 Feb 2024 00:23:29 +0100 Subject: [PATCH 64/79] 0.8.86 * RestAPI check for parent element to be JsonObject #1449 * fix translation #1448 #1442 * fix reset values when inverter status is 'not available' #1035 #1437 --- src/CHANGES.md | 5 ++++ src/app.cpp | 2 +- src/defines.h | 2 +- src/web/RestApi.h | 52 +++++++++++++++++++++------------------- src/web/html/serial.html | 6 ++--- src/web/lang.json | 18 ++++++++++++-- 6 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 003c8cef..58c229c1 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.86 - 2024-02-23 +* RestAPI check for parent element to be JsonObject #1449 +* fix translation #1448 #1442 +* fix reset values when inverter status is 'not available' #1035 #1437 + ## 0.8.85 - 2024-02-22 * possible fix of MqTT fix "total values are sent to often" #1421 * fix translation #1442 diff --git a/src/app.cpp b/src/app.cpp index f53af865..bad880f5 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -468,7 +468,7 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { continue; // skip to next inverter if (checkAvail) { - if (!iv->isAvailable()) + if (iv->isAvailable()) continue; } diff --git a/src/defines.h b/src/defines.h index fc4988e6..5f4344b5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 85 +#define VERSION_PATCH 86 //------------------------------------- typedef struct { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 09bba06e..622ea2d8 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -141,7 +141,7 @@ class RestApi { DPRINTLN(DBG_VERBOSE, "onApiPostBody"); if(0 == index) { - if(NULL != mTmpBuf) + if(nullptr != mTmpBuf) delete[] mTmpBuf; mTmpBuf = new uint8_t[total+1]; mTmpSize = total; @@ -154,36 +154,40 @@ class RestApi { DynamicJsonDocument json(1000); - DeserializationError err = deserializeJson(json, reinterpret_cast(mTmpBuf), mTmpSize); - JsonObject obj = json.as(); - AsyncJsonResponse* response = new AsyncJsonResponse(false, 200); JsonObject root = response->getRoot(); - root[F("success")] = (err) ? false : true; - if(!err) { - String path = request->url().substring(5); - if(path == "ctrl") - root[F("success")] = setCtrl(obj, root, request->client()->remoteIP().toString().c_str()); - else if(path == "setup") - root[F("success")] = setSetup(obj, root, request->client()->remoteIP().toString().c_str()); - else { - root[F("success")] = false; - root[F("error")] = F(PATH_NOT_FOUND) + path; - } - } else { - switch (err.code()) { - case DeserializationError::Ok: break; - case DeserializationError::IncompleteInput: root[F("error")] = F(INCOMPLETE_INPUT); break; - case DeserializationError::InvalidInput: root[F("error")] = F(INVALID_INPUT); break; - case DeserializationError::NoMemory: root[F("error")] = F(NOT_ENOUGH_MEM); break; - default: root[F("error")] = F(DESER_FAILED); break; + DeserializationError err = deserializeJson(json, reinterpret_cast(mTmpBuf), mTmpSize); + if(!json.is()) + root[F("error")] = F(DESER_FAILED); + else { + JsonObject obj = json.as(); + + root[F("success")] = (err) ? false : true; + if(!err) { + String path = request->url().substring(5); + if(path == "ctrl") + root[F("success")] = setCtrl(obj, root, request->client()->remoteIP().toString().c_str()); + else if(path == "setup") + root[F("success")] = setSetup(obj, root, request->client()->remoteIP().toString().c_str()); + else { + root[F("success")] = false; + root[F("error")] = F(PATH_NOT_FOUND) + path; + } + } else { + switch (err.code()) { + case DeserializationError::Ok: break; + case DeserializationError::IncompleteInput: root[F("error")] = F(INCOMPLETE_INPUT); break; + case DeserializationError::InvalidInput: root[F("error")] = F(INVALID_INPUT); break; + case DeserializationError::NoMemory: root[F("error")] = F(NOT_ENOUGH_MEM); break; + default: root[F("error")] = F(DESER_FAILED); break; + } } } response->setLength(); request->send(response); delete[] mTmpBuf; - mTmpBuf = NULL; + mTmpBuf = nullptr; } void getNotFound(JsonObject obj, String url) { @@ -974,7 +978,7 @@ class RestApi { uint32_t mTimezoneOffset = 0; uint32_t mHeapFree = 0, mHeapFreeBlk = 0; uint8_t mHeapFrag = 0; - uint8_t *mTmpBuf = NULL; + uint8_t *mTmpBuf = nullptr; uint32_t mTmpSize = 0; }; diff --git a/src/web/html/serial.html b/src/web/html/serial.html index ff63772c..a3e48a04 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -65,7 +65,7 @@ }); document.getElementById("scroll").addEventListener("click", function() { mAutoScroll = !mAutoScroll; - this.value = (mAutoScroll) ? "autoscroll" : "manual scroll"; + this.value = (mAutoScroll) ? "{#BTN_AUTOSCROLL}" : "{#BTN_MANUALSCROLL}"; }); document.getElementById("copy").addEventListener("click", function() { con.value = version + " - " + build + "\n---------------\n" + con.value; @@ -80,10 +80,10 @@ try { return document.execCommand("copy"); // Security exception may be thrown by some browsers. } catch (ex) { - alert("Copy to clipboard failed" + ex); + alert("CLIPBOARD_FAILED " + ex); } finally { document.body.removeChild(ta); - alert("Copied to clipboard"); + alert("{#COPIED_TO_CLIPBOARD}"); } } }); diff --git a/src/web/lang.json b/src/web/lang.json index 727eadcd..af888682 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -883,6 +883,11 @@ "en": "autoscroll", "de": "automatisch scrollen" }, + { + "token": "BTN_MANUALSCROLL", + "en": "manual scroll", + "de": "manuell scrollen" + }, { "token": "BTN_COPY", "en": "copy", @@ -897,12 +902,21 @@ "token": "UPTIME", "en": "uptime", "de": "Laufzeit" - } -, + }, { "token": "DAYS", "en": "days", "de": "Tage" + }, + { + "token": "COPIED_TO_CLIPBOARD", + "en": "Copied to clipboard", + "de": "in die Zwischenablage kopiert" + }, + { + "token": "CLIPBOARD_FAILED", + "en": "Copy failed", + "de": "kopieren fehlgeschlagen" } ] }, From e2ab5dacd4cfd1c4bd6ca7fc88276e178712edaa Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 24 Feb 2024 01:30:26 +0100 Subject: [PATCH 65/79] 0.8.86 * update workflow --- .github/workflows/compile_development.yml | 26 +++++++++++++++++++++++ scripts/buildManifest.py | 20 ++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index c15bd883..bd692598 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -164,9 +164,35 @@ jobs: env: VERSION: ${{ steps.version_name.outputs.name }} + + - name: Create ESP Web Tools Manifest + working-directory: src + run: python ../scripts/buildManifest.py + + - name: Copy install html + run: mv ../scripts/gh-action-dev-build-flash.html firmware/install.html + + - name: Copy Changes.md + run: mv CHANGES.md firmware/CHANGES.md + + - name: Rename firmware directory run: mv firmware ${{ steps.version_name.outputs.name }} + - name: delete environment Artifacts + uses: geekyeggo/delete-artifact@v4 + with: + name: dev-* + + - name: Create Artifact + uses: actions/upload-artifact@v4 + with: + name: dev-${{ steps.version_name.outputs.name }} + path: | + ${{ steps.version_name.outputs.name }}/* + manual/User_Manual.md + manual/Getting_Started.md + - name: Deploy uses: nogsantos/scp-deploy@master with: diff --git a/scripts/buildManifest.py b/scripts/buildManifest.py index 2664a39f..36e47ac0 100644 --- a/scripts/buildManifest.py +++ b/scripts/buildManifest.py @@ -36,9 +36,27 @@ def buildManifest(path, infile, outfile): esp32["parts"].append({"path": "ESP32/bootloader.bin", "offset": 4096}) esp32["parts"].append({"path": "ESP32/partitions.bin", "offset": 32768}) esp32["parts"].append({"path": "ESP32/ota.bin", "offset": 57344}) - esp32["parts"].append({"path": "ESP32/" + version[1] + "_" + sha + "_esp32.bin", "offset": 65536}) + esp32["parts"].append({"path": "ESP32/" + version[1] + "_" + sha + "_esp32-wroom32.bin", "offset": 65536}) data["builds"].append(esp32) + esp32s2 = {} + esp32s2["chipFamily"] = "ESP32-S2" + esp32s2["parts"] = [] + esp32s2["parts"].append({"path": "ESP32-S2/bootloader.bin", "offset": 4096}) + esp32s2["parts"].append({"path": "ESP32-S2/partitions.bin", "offset": 32768}) + esp32s2["parts"].append({"path": "ESP32-S2/ota.bin", "offset": 57344}) + esp32s2["parts"].append({"path": "ESP32-S2/" + version[1] + "_" + sha + "_esp32-s2-mini.bin", "offset": 65536}) + data["builds"].append(esp32s2) + + esp32s3 = {} + esp32s3["chipFamily"] = "ESP32-S3" + esp32s3["parts"] = [] + esp32s3["parts"].append({"path": "ESP32/bootloader.bin", "offset": 4096}) + esp32s3["parts"].append({"path": "ESP32/partitions.bin", "offset": 32768}) + esp32s3["parts"].append({"path": "ESP32/ota.bin", "offset": 57344}) + esp32s3["parts"].append({"path": "ESP32-S3/" + version[1] + "_" + sha + "_opendtufusion.bin", "offset": 65536}) + data["builds"].append(esp32s3) + esp8266 = {} esp8266["chipFamily"] = "ESP8266" esp8266["parts"] = [] From d4f49792454036aa0f9f4b0f953d9eb3d565d295 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 24 Feb 2024 01:42:33 +0100 Subject: [PATCH 66/79] 0.8.86 * fix workflow --- .github/workflows/compile_development.yml | 6 +++--- scripts/buildManifest.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index bd692598..3f89770c 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v4 build-en: - name: Build Environments (English) + name: Build (English) needs: check runs-on: ubuntu-latest continue-on-error: true @@ -77,7 +77,7 @@ jobs: path: firmware/* build-de: - name: Build Environments (German) + name: Build (German) needs: check runs-on: ubuntu-latest continue-on-error: true @@ -138,7 +138,7 @@ jobs: path: firmware/* deploy: - name: Deploy Environments + name: Update Artifacts / Deploy needs: [build-en, build-de] runs-on: ubuntu-latest continue-on-error: false diff --git a/scripts/buildManifest.py b/scripts/buildManifest.py index 36e47ac0..b91145cd 100644 --- a/scripts/buildManifest.py +++ b/scripts/buildManifest.py @@ -65,7 +65,7 @@ def buildManifest(path, infile, outfile): jsonString = json.dumps(data, indent=2) - fp = open(path + "firmware/" + outfile, "w") + fp = open(path + "../firmware/" + outfile, "w") fp.write(jsonString) fp.close() From e7d9a8ebcb2a1ca1bece6540a1598be2173f2bd7 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 24 Feb 2024 01:49:04 +0100 Subject: [PATCH 67/79] 0.8.86 * fix workflow --- .github/workflows/compile_development.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 3f89770c..7f539871 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v4 build-en: - name: Build (English) + name: Build (EN) needs: check runs-on: ubuntu-latest continue-on-error: true @@ -77,7 +77,7 @@ jobs: path: firmware/* build-de: - name: Build (German) + name: Build (DE) needs: check runs-on: ubuntu-latest continue-on-error: true @@ -170,10 +170,10 @@ jobs: run: python ../scripts/buildManifest.py - name: Copy install html - run: mv ../scripts/gh-action-dev-build-flash.html firmware/install.html + run: mv scripts/gh-action-dev-build-flash.html firmware/install.html - name: Copy Changes.md - run: mv CHANGES.md firmware/CHANGES.md + run: mv src/CHANGES.md firmware/CHANGES.md - name: Rename firmware directory From 4f71ac014c3b866cd123e5783c35b8e85246ade4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 25 Feb 2024 17:16:54 +0100 Subject: [PATCH 68/79] 0.8.87 * fix translations #1455 #1442 --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/web/html/index.html | 4 ++-- src/web/html/serial.html | 2 +- src/web/lang.json | 10 ++++++++++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 58c229c1..4ca494f2 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.87 - 2024-02-25 +* fix translations #1455 #1442 + ## 0.8.86 - 2024-02-23 * RestAPI check for parent element to be JsonObject #1449 * fix translation #1448 #1442 diff --git a/src/defines.h b/src/defines.h index 5f4344b5..d3179469 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 86 +#define VERSION_PATCH 87 //------------------------------------- typedef struct { diff --git a/src/web/html/index.html b/src/web/html/index.html index 2611db5b..954ee012 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -70,9 +70,9 @@ var min = parseInt(up / 60) % 60; var sec = up % 60; var e = document.getElementById("uptime"); - e.innerHTML = days + " Day"; + e.innerHTML = days + " {#DAY}"; if(1 != days) - e.innerHTML += "s"; + e.innerHTML += "{#S}"; e.innerHTML += ", " + ("0"+hrs).substr(-2) + ":" + ("0"+min).substr(-2) + ":" + ("0"+sec).substr(-2); diff --git a/src/web/html/serial.html b/src/web/html/serial.html index a3e48a04..835f1766 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -80,7 +80,7 @@ try { return document.execCommand("copy"); // Security exception may be thrown by some browsers. } catch (ex) { - alert("CLIPBOARD_FAILED " + ex); + alert("{#CLIPBOARD_FAILED} " + ex); } finally { document.body.removeChild(ta); alert("{#COPIED_TO_CLIPBOARD}"); diff --git a/src/web/lang.json b/src/web/lang.json index af888682..7d9cdb43 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -993,6 +993,16 @@ "en": "Error", "de": "Fehler" }, + { + "token": "DAY", + "en": "day", + "de": "Tag" + }, + { + "token": "S", + "en": "s", + "de": "e" + }, { "token": "NTP_UNREACH", "en": "NTP timeserver unreachable", From 3b58522fd58df0ce14ba1ca615abd0ab18b758d2 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 29 Feb 2024 00:01:09 +0100 Subject: [PATCH 69/79] 0.8.88 * fix MqTT statistic data overflow #1458 * add HMS-400-1T support (serial number 1125...) #1460 * removed `yield efficiency` because the inverter already calculates correct #1243 --- src/CHANGES.md | 5 +++++ src/config/settings.h | 9 --------- src/defines.h | 2 +- src/hm/hmInverter.h | 4 ++-- src/hm/hmSystem.h | 8 ++++---- src/platformio.ini | 2 +- src/publisher/pubMqttIvData.h | 2 +- src/web/RestApi.h | 1 - src/web/html/setup.html | 9 +++------ src/web/lang.json | 5 ----- src/web/web.h | 1 - 11 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 4ca494f2..c5650f0d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.88 - 2024-02-28 +* fix MqTT statistic data overflow #1458 +* add HMS-400-1T support (serial number 1125...) #1460 +* removed `yield efficiency` because the inverter already calculates correct #1243 + ## 0.8.87 - 2024-02-25 * fix translations #1455 #1442 diff --git a/src/config/settings.h b/src/config/settings.h index 18725b48..9c9b48c2 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -161,7 +161,6 @@ typedef struct { bool rstValsCommStop; bool rstMaxValsMidNight; bool startWithoutTime; - float yieldEffiency; bool readGrid; } cfgInst_t; @@ -452,7 +451,6 @@ class settings { mCfg.inst.rstValsCommStop = false; mCfg.inst.startWithoutTime = false; mCfg.inst.rstMaxValsMidNight = false; - mCfg.inst.yieldEffiency = 1.0f; mCfg.inst.readGrid = true; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { @@ -763,7 +761,6 @@ class settings { obj[F("rstComStop")] = (bool)mCfg.inst.rstValsCommStop; obj[F("strtWthtTime")] = (bool)mCfg.inst.startWithoutTime; obj[F("rstMaxMidNight")] = (bool)mCfg.inst.rstMaxValsMidNight; - obj[F("yldEff")] = mCfg.inst.yieldEffiency; obj[F("rdGrid")] = (bool)mCfg.inst.readGrid; } else { @@ -774,13 +771,7 @@ class settings { getVal(obj, F("rstComStop"), &mCfg.inst.rstValsCommStop); getVal(obj, F("strtWthtTime"), &mCfg.inst.startWithoutTime); getVal(obj, F("rstMaxMidNight"), &mCfg.inst.rstMaxValsMidNight); - getVal(obj, F("yldEff"), &mCfg.inst.yieldEffiency); getVal(obj, F("rdGrid"), &mCfg.inst.readGrid); - - if(mCfg.inst.yieldEffiency < 0.5) - mCfg.inst.yieldEffiency = 1.0f; - else if(mCfg.inst.yieldEffiency > 1.0f) - mCfg.inst.yieldEffiency = 1.0f; } JsonArray ivArr; diff --git a/src/defines.h b/src/defines.h index d3179469..8dcfe988 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 87 +#define VERSION_PATCH 88 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b7fb00a1..1890d142 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -300,9 +300,9 @@ class Inverter { // temperature, Qvar, and power factor are a signed values rec->record[pos] = ((REC_TYP)((int16_t)val)) / (REC_TYP)(div); } else if (FLD_YT == rec->assign[pos].fieldId) { - rec->record[pos] = ((REC_TYP)(val) / (REC_TYP)(div) * generalConfig->yieldEffiency) + ((REC_TYP)config->yieldCor[rec->assign[pos].ch-1]); + rec->record[pos] = ((REC_TYP)(val) / (REC_TYP)(div)) + ((REC_TYP)config->yieldCor[rec->assign[pos].ch-1]); } else if (FLD_YD == rec->assign[pos].fieldId) { - float actYD = (REC_TYP)(val) / (REC_TYP)(div) * generalConfig->yieldEffiency; + float actYD = (REC_TYP)(val) / (REC_TYP)(div); uint8_t idx = rec->assign[pos].ch - 1; if (mLastYD[idx] > actYD) mOffYD[idx] += mLastYD[idx]; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 7e79f30a..e9b839be 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -31,6 +31,7 @@ class HmSystem { if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 + case 0x25: // HMS-400 case 0x22: case 0x21: iv->type = INV_TYPE_1CH; break; @@ -51,15 +52,14 @@ class HmSystem { } if(iv->config->serial.b[5] == 0x11) { - if((iv->config->serial.b[4] & 0x0f) == 0x04) { + if(((iv->config->serial.b[4] & 0x0f) == 0x04) || ((iv->config->serial.b[4] & 0x0f) == 0x05)) { iv->ivGen = IV_HMS; iv->ivRadioType = INV_RADIO_TYPE_CMT; } else { iv->ivGen = IV_HM; iv->ivRadioType = INV_RADIO_TYPE_NRF; } - } - else if((iv->config->serial.b[4] & 0x03) == 0x02) { // MI 3rd Gen -> same as HM + } else if((iv->config->serial.b[4] & 0x03) == 0x02) { // MI 3rd Gen -> same as HM iv->ivGen = IV_HM; iv->ivRadioType = INV_RADIO_TYPE_NRF; } else { // MI 2nd Gen @@ -82,7 +82,7 @@ class HmSystem { DPRINT(DBG_INFO, "added inverter "); if(iv->config->serial.b[5] == 0x11) { - if((iv->config->serial.b[4] & 0x0f) == 0x04) + if(((iv->config->serial.b[4] & 0x0f) == 0x04) || ((iv->config->serial.b[4] & 0x0f) == 0x05)) DBGPRINT("HMS"); else DBGPRINT("HM"); diff --git a/src/platformio.ini b/src/platformio.ini index f949aa37..7130bf4c 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -350,7 +350,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index c15c9799..ac8b3bf0 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -293,7 +293,7 @@ class PubMqttIvData { bool mRTRDataHasBeenSent = false; std::array mSubTopic; - std::array mVal; + std::array mVal; std::queue *mSendList = nullptr; }; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 622ea2d8..0120375a 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -484,7 +484,6 @@ class RestApi { obj[F("strtWthtTm")] = (bool)mConfig->inst.startWithoutTime; obj[F("rdGrid")] = (bool)mConfig->inst.readGrid; obj[F("rstMaxMid")] = (bool)mConfig->inst.rstMaxValsMidNight; - obj[F("yldEff")] = mConfig->inst.yieldEffiency; } void getInverter(JsonObject obj, uint8_t id) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 47d935b9..57dc6a8c 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -157,10 +157,6 @@
{#INV_READ_GRID_PROFILE}
-
-
{#INV_YIELD_EFF}
-
-
@@ -605,7 +601,7 @@ } function ivGlob(obj) { - for(var i of [["invInterval", "interval"], ["yldEff", "yldEff"]]) + for(var i of [["invInterval", "interval"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; for(var i of ["Mid", "ComStop", "NotAvail", "MaxMid"]) document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i]; @@ -786,7 +782,8 @@ case 0x1000: nrf = true; break; case 0x1100: switch(sn & 0x000f) { - case 0x0004: nrf = false; break; + case 0x0004: + case 0x0005: nrf = false; break; default: nrf = true; break; } break; diff --git a/src/web/lang.json b/src/web/lang.json index 7d9cdb43..eefd0516 100644 --- a/src/web/lang.json +++ b/src/web/lang.json @@ -323,11 +323,6 @@ "en": "Read Grid Profile", "de": "Grid-Profil auslesen" }, - { - "token": "INV_YIELD_EFF", - "en": "Yield Efficiency (default 1.0)", - "de": "Ertragseffizienz (Standard 1.0)" - }, { "token": "NTP_INTERVAL", "en": "NTP Interval (in minutes, min. 5 minutes)", diff --git a/src/web/web.h b/src/web/web.h index 8495ba23..de4938f1 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -483,7 +483,6 @@ class Web { mConfig->inst.startWithoutTime = (request->arg("strtWthtTm") == "on"); mConfig->inst.readGrid = (request->arg("rdGrid") == "on"); mConfig->inst.rstMaxValsMidNight = (request->arg("invRstMaxMid") == "on"); - mConfig->inst.yieldEffiency = (request->arg("yldEff")).toFloat(); // pinout From ec88dd19a56c061e51ea7da433f10cfeca19f1b2 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 29 Feb 2024 00:02:15 +0100 Subject: [PATCH 70/79] 0.8.88 platformio.ini fix --- src/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformio.ini b/src/platformio.ini index 7130bf4c..f949aa37 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -350,7 +350,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - -DARDUINO_USB_CDC_ON_BOOT=1 + #-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize From 2bc6610a83f7f570c85be0472512ff86ab02c2d1 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 29 Feb 2024 00:04:45 +0100 Subject: [PATCH 71/79] 0.8.88 * merge PR: Remove hint to INV_RESET_MIDNIGHT resp. INV_PAUSE_DURING_NIGHT #1431 --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index c5650f0d..2cd2300f 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,7 @@ * fix MqTT statistic data overflow #1458 * add HMS-400-1T support (serial number 1125...) #1460 * removed `yield efficiency` because the inverter already calculates correct #1243 +* merge PR: Remove hint to INV_RESET_MIDNIGHT resp. INV_PAUSE_DURING_NIGHT #1431 ## 0.8.87 - 2024-02-25 * fix translations #1455 #1442 From 58044c34aa16d1ffa08e935d0c5fe3c1261e104b Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 3 Dec 2023 15:51:33 +0100 Subject: [PATCH 72/79] remove redundant check for nullpointer (cherry picked from commit a1de637793bdc14627c68fc1b03d61d5189758cd) (cherry picked from commit 7ba88180c50d7d0b6c971a477987bb5ded5aa9d8) (cherry picked from commit 6888d571834ad5cf4b32a00536501e88112f7049) (cherry picked from commit 8a8b8a61f354992823a77feca3a5193f8c53880e) --- src/hm/hmInverter.h | 50 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 1890d142..4252800d 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -288,32 +288,30 @@ class Inverter { uint8_t end = ptr + rec->assign[pos].num; uint16_t div = rec->assign[pos].div; - if(NULL != rec) { - if(CMD_CALC != div) { - uint32_t val = 0; - do { - val <<= 8; - val |= buf[ptr]; - } while(++ptr != end); - - if ((FLD_T == rec->assign[pos].fieldId) || (FLD_Q == rec->assign[pos].fieldId) || (FLD_PF == rec->assign[pos].fieldId)) { - // temperature, Qvar, and power factor are a signed values - rec->record[pos] = ((REC_TYP)((int16_t)val)) / (REC_TYP)(div); - } else if (FLD_YT == rec->assign[pos].fieldId) { - rec->record[pos] = ((REC_TYP)(val) / (REC_TYP)(div)) + ((REC_TYP)config->yieldCor[rec->assign[pos].ch-1]); - } else if (FLD_YD == rec->assign[pos].fieldId) { - float actYD = (REC_TYP)(val) / (REC_TYP)(div); - uint8_t idx = rec->assign[pos].ch - 1; - if (mLastYD[idx] > actYD) - mOffYD[idx] += mLastYD[idx]; - mLastYD[idx] = actYD; - rec->record[pos] = mOffYD[idx] + actYD; - } else { - if ((REC_TYP)(div) > 1) - rec->record[pos] = (REC_TYP)(val) / (REC_TYP)(div); - else - rec->record[pos] = (REC_TYP)(val); - } + if(CMD_CALC != div) { + uint32_t val = 0; + do { + val <<= 8; + val |= buf[ptr]; + } while(++ptr != end); + + if ((FLD_T == rec->assign[pos].fieldId) || (FLD_Q == rec->assign[pos].fieldId) || (FLD_PF == rec->assign[pos].fieldId)) { + // temperature, Qvar, and power factor are a signed values + rec->record[pos] = ((REC_TYP)((int16_t)val)) / (REC_TYP)(div); + } else if (FLD_YT == rec->assign[pos].fieldId) { + rec->record[pos] = ((REC_TYP)(val) / (REC_TYP)(div)) + ((REC_TYP)config->yieldCor[rec->assign[pos].ch-1]); + } else if (FLD_YD == rec->assign[pos].fieldId) { + float actYD = (REC_TYP)(val) / (REC_TYP)(div); + uint8_t idx = rec->assign[pos].ch - 1; + if (mLastYD[idx] > actYD) + mOffYD[idx] += mLastYD[idx]; + mLastYD[idx] = actYD; + rec->record[pos] = mOffYD[idx] + actYD; + } else { + if ((REC_TYP)(div) > 1) + rec->record[pos] = (REC_TYP)(val) / (REC_TYP)(div); + else + rec->record[pos] = (REC_TYP)(val); } } From 199d4b38732d00380e40f8d2065a279b526398f5 Mon Sep 17 00:00:00 2001 From: you69man Date: Fri, 8 Dec 2023 15:49:12 +0100 Subject: [PATCH 73/79] use mChList[] instead of switch-case (cherry picked from commit fdaf80e964a6ecb2423b0c1d8d03bb0184904ab8) (cherry picked from commit 48c832be5eb05a96204fa1ec70fdf198e06ac94d) (cherry picked from commit effe05a616615d709455d32c46c2254c8cfe399e) --- src/hm/Heuristic.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index cc42df4f..59c35aec 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -217,15 +217,12 @@ class Heuristic { } inline uint8_t id2Ch(uint8_t id) { - switch(id) { - case 0: return 3; - case 1: return 23; - case 2: return 40; - case 3: return 61; - case 4: return 75; - } - return 3; // standard + if (id < RF_MAX_CHANNEL_ID) + return mChList[id]; + else + return 3; // standard } + uint8_t mChList[RF_MAX_CHANNEL_ID] = {03, 23, 40, 61, 75}; }; From 363aac5d0227a8c70d5a4d09c2cf37d83e43f140 Mon Sep 17 00:00:00 2001 From: you69man Date: Sun, 17 Dec 2023 12:11:49 +0100 Subject: [PATCH 74/79] used INVERTERTYPE:: instead of mInverter[0] for global setup --- src/hm/hmSystem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index e9b839be..c4219435 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -16,8 +16,8 @@ class HmSystem { HmSystem() {} void setup(uint32_t *timestamp, cfgInst_t *config, IApp *app) { - mInverter[0].timestamp = timestamp; - mInverter[0].generalConfig = config; + INVERTERTYPE::timestamp = timestamp; + INVERTERTYPE::generalConfig = config; //mInverter[0].app = app; } From c9a9d6b7733a18d4efb1aeaa190cae091ceaad07 Mon Sep 17 00:00:00 2001 From: you69man Date: Sat, 23 Dec 2023 12:31:47 +0100 Subject: [PATCH 75/79] remove unnecessary config entry 'enabled' for cfgInst_t --- src/config/settings.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/settings.h b/src/config/settings.h index 9c9b48c2..fe0053a9 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -152,7 +152,7 @@ typedef struct { } cfgIv_t; typedef struct { - bool enabled; +// bool enabled; cfgIv_t iv[MAX_NUM_INVERTERS]; uint16_t sendInterval; @@ -755,7 +755,7 @@ class settings { void jsonInst(JsonObject obj, bool set = false) { if(set) { obj[F("intvl")] = mCfg.inst.sendInterval; - obj[F("en")] = (bool)mCfg.inst.enabled; +// obj[F("en")] = (bool)mCfg.inst.enabled; obj[F("rstMidNight")] = (bool)mCfg.inst.rstYieldMidNight; obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail; obj[F("rstComStop")] = (bool)mCfg.inst.rstValsCommStop; @@ -765,7 +765,7 @@ class settings { } else { getVal(obj, F("intvl"), &mCfg.inst.sendInterval); - getVal(obj, F("en"), &mCfg.inst.enabled); +// getVal(obj, F("en"), &mCfg.inst.enabled); getVal(obj, F("rstMidNight"), &mCfg.inst.rstYieldMidNight); getVal(obj, F("rstNotAvail"), &mCfg.inst.rstValsNotAvail); getVal(obj, F("rstComStop"), &mCfg.inst.rstValsCommStop); From b143eb371b2d88333704c626108fd4d5651092af Mon Sep 17 00:00:00 2001 From: you69man Date: Sat, 23 Dec 2023 16:16:36 +0100 Subject: [PATCH 76/79] remove strncpy warning in scheduler.h Warning was: output truncated before terminating nul copying 5 bytes from a string of the same length --- src/utils/scheduler.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/scheduler.h b/src/utils/scheduler.h index 16009778..0f7cea7b 100644 --- a/src/utils/scheduler.h +++ b/src/utils/scheduler.h @@ -125,8 +125,8 @@ namespace ah { mTicker[i].timeout = timeout; mTicker[i].reload = reload; mTicker[i].isTimestamp = isTimestamp; - memset(mTicker[i].name, 0, 6); - strncpy(mTicker[i].name, name, (strlen(name) < 6) ? strlen(name) : 5); + strncpy(mTicker[i].name, name, 5); + mTicker[i].name[5]=0; if(mMax == i) mMax = i + 1; return i; From dd8f8c138b72aecb796992637052237edc8c0138 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 3 Dec 2023 16:37:18 +0100 Subject: [PATCH 77/79] fix typos --- src/CHANGES.md | 4 ++-- src/defines.h | 2 +- src/hm/Communication.h | 2 +- src/hm/Heuristic.h | 2 +- src/publisher/pubMqttIvData.h | 2 +- src/web/RestApi.h | 2 +- src/web/html/includes/nav.html | 6 +++--- src/web/html/style.css | 2 +- src/web/web.h | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 2cd2300f..09ba13f2 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -265,7 +265,7 @@ ## 0.8.39 - 2024-01-01 * fix MqTT dis_night_comm in the morning #1309 #1286 -* seperated offset for sunrise and sunset #1308 +* separated offset for sunrise and sunset #1308 * powerlimit (active power control) now has one decimal place (MqTT / API) #1199 * merge Prometheus metrics fix #1310 * merge MI grid profile request #1306 @@ -478,7 +478,7 @@ ## 0.7.61 - 2023-10-01 * merged `hmPayload` and `hmsPayload` into single class * merged generic radio functions into new parent class `radio.h` -* moved radio statistics into the inverter - each inverter has now seperate statistics which can be accessed by click on the footer in `/live` +* moved radio statistics into the inverter - each inverter has now separate statistics which can be accessed by click on the footer in `/live` * fix compiler warnings #1191 * fix ePaper logo during night time #1151 diff --git a/src/defines.h b/src/defines.h index 8dcfe988..67e902bd 100644 --- a/src/defines.h +++ b/src/defines.h @@ -109,7 +109,7 @@ enum { typedef struct { uint32_t rxFail; - uint32_t rxFailNoAnser; + uint32_t rxFailNoAnswer; uint32_t rxSuccess; uint32_t frmCnt; uint32_t txCnt; diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 8c7fbe6d..b616f317 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -622,7 +622,7 @@ class Communication : public CommQueue<> { else if(q->iv->mGotFragment || mCompleteRetry) q->iv->radioStatistics.rxFail++; // got no complete payload else - q->iv->radioStatistics.rxFailNoAnser++; // got nothing + q->iv->radioStatistics.rxFailNoAnswer++; // got nothing mWaitTime.startTimeMonitor(1); // maybe remove, side effects unknown bool keep = false; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 59c35aec..1220692e 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -153,7 +153,7 @@ class Heuristic { DBGPRINT(F(", f: ")); DBGPRINT(String(iv->radioStatistics.rxFail)); DBGPRINT(F(", n: ")); - DBGPRINT(String(iv->radioStatistics.rxFailNoAnser)); + DBGPRINT(String(iv->radioStatistics.rxFailNoAnswer)); DBGPRINT(F(" | p: ")); // better debugging for helpers... if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) DBGPRINTLN(String(iv->config->powerLevel-10)); diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index ac8b3bf0..6ddd63a9 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -222,7 +222,7 @@ class PubMqttIvData { mIv->radioStatistics.txCnt, mIv->radioStatistics.rxSuccess, mIv->radioStatistics.rxFail, - mIv->radioStatistics.rxFailNoAnser, + mIv->radioStatistics.rxFailNoAnswer, mIv->radioStatistics.retransmits, mIv->radioStatistics.ivLoss, mIv->radioStatistics.ivSent, diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 0120375a..f6917077 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -426,7 +426,7 @@ class RestApi { obj[F("name")] = String(iv->config->name); obj[F("rx_success")] = iv->radioStatistics.rxSuccess; obj[F("rx_fail")] = iv->radioStatistics.rxFail; - obj[F("rx_fail_answer")] = iv->radioStatistics.rxFailNoAnser; + obj[F("rx_fail_answer")] = iv->radioStatistics.rxFailNoAnswer; obj[F("frame_cnt")] = iv->radioStatistics.frmCnt; obj[F("tx_cnt")] = iv->radioStatistics.txCnt; obj[F("retransmits")] = iv->radioStatistics.retransmits; diff --git a/src/web/html/includes/nav.html b/src/web/html/includes/nav.html index 447bf411..bab64829 100644 --- a/src/web/html/includes/nav.html +++ b/src/web/html/includes/nav.html @@ -10,15 +10,15 @@ {#NAV_HISTORY} {#NAV_WEBSERIAL} {#NAV_SETTINGS} - + Update System - + REST API {#NAV_DOCUMENTATION} {#NAV_ABOUT} Custom Link - + Login Logout diff --git a/src/web/html/style.css b/src/web/html/style.css index 2d6a03c7..74cf4e8e 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -139,7 +139,7 @@ svg.icon { background-color: var(--nav-active); } -span.seperator { +span.separator { width: 100%; height: 1px; margin: 5px 0 5px; diff --git a/src/web/web.h b/src/web/web.h index de4938f1..0a4f0ed5 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -661,7 +661,7 @@ class Web { { "max_power", "gauge", metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->getMaxPower();} }, { "radio_rx_success", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxSuccess;} }, { "radio_rx_fail", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxFail;} }, - { "radio_rx_fail_answer", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxFailNoAnser;} }, + { "radio_rx_fail_answer", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxFailNoAnswer;} }, { "radio_frame_cnt", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.frmCnt;} }, { "radio_tx_cnt", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.txCnt;} }, { "radio_retransmits", "counter" ,metricConstInverterFormat, [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.retransmits;} }, From 49508ba78e694476883d3bf96207ec4305ee93ed Mon Sep 17 00:00:00 2001 From: you69man Date: Sat, 24 Feb 2024 14:20:07 +0100 Subject: [PATCH 78/79] fix two warnings 1) C++ forbids converting a string constant to 'char*' 2) suggest paranthesis around '&&' within '||' --- src/hm/Communication.h | 2 +- src/publisher/pubMqtt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index b616f317..5fd3b487 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -117,7 +117,7 @@ class Communication : public CommQueue<> { //q->iv->radioStatistics.txCnt++; q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout); - if(!mIsRetransmit && (q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) + if((!mIsRetransmit && (q->cmd == AlarmData)) || (q->cmd == GridOnProFilePara)) incrAttempt((q->cmd == AlarmData)? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); mIsRetransmit = false; diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index ea6f331e..4b09b649 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -423,7 +423,7 @@ class PubMqtt { } DynamicJsonDocument doc2(512); - constexpr static char* unitTotal[] = {"W", "kWh", "Wh", "W"}; + constexpr static const char* unitTotal[] = {"W", "kWh", "Wh", "W"}; doc2[F("name")] = String(name.data()); doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic.data()); doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(mDiscovery.sub, rec)) : (unitTotal[mDiscovery.sub])); From 0d7c67dbcecaee200ccee505a5a2a8a4b3153c62 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 2 Mar 2024 01:25:59 +0100 Subject: [PATCH 79/79] 0.8.89 * merge PR: Collection of small fixes #1465 * fix: show esp type on `/history` #1463 * improved HMS-400-1T support (serial number 1125...) #1460 --- src/CHANGES.md | 5 +++++ src/defines.h | 2 +- src/hm/hmSystem.h | 3 ++- src/web/html/history.html | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 09ba13f2..f5aa9cd9 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.89 - 2024-03-02 +* merge PR: Collection of small fixes #1465 +* fix: show esp type on `/history` #1463 +* improved HMS-400-1T support (serial number 1125...) #1460 + ## 0.8.88 - 2024-02-28 * fix MqTT statistic data overflow #1458 * add HMS-400-1T support (serial number 1125...) #1460 diff --git a/src/defines.h b/src/defines.h index 67e902bd..b7ee4406 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 88 +#define VERSION_PATCH 89 //------------------------------------- typedef struct { diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index c4219435..3b43b9f0 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -31,11 +31,12 @@ class HmSystem { if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 - case 0x25: // HMS-400 case 0x22: case 0x21: iv->type = INV_TYPE_1CH; break; + case 0x25: // HMS-400 - 1 channel but payload like 2ch + case 0x44: // HMS-1000 case 0x42: case 0x41: iv->type = INV_TYPE_2CH; diff --git a/src/web/html/history.html b/src/web/html/history.html index 7e317b59..6372ab82 100644 --- a/src/web/html/history.html +++ b/src/web/html/history.html @@ -80,6 +80,7 @@ function parsePowerHistory(obj){ if (null != obj) { parseNav(obj.generic); + parseESP(obj.generic); parseHistory(obj,"pwr", pwrExeOnce) document.getElementById("pwrLast").innerHTML = mLastValue document.getElementById("pwrMaxDay").innerHTML = obj.maxDay