Browse Source

Merge branch 'development03' into Zero-Export

pull/1155/head
DanielR92 2 years ago
parent
commit
06bb525e6e
  1. 5
      src/CHANGES.md
  2. 2
      src/app.cpp
  3. 3
      src/config/config.h
  4. 4
      src/config/settings.h
  5. 2
      src/defines.h
  6. 4
      src/hm/CommQueue.h
  7. 128
      src/hm/Communication.h
  8. 6
      src/hm/Heuristic.h
  9. 89
      src/hm/hmInverter.h
  10. 21
      src/hm/hmRadio.h
  11. 4
      src/hm/radio.h
  12. 18
      src/platformio.ini
  13. 5
      src/utils/helper.cpp
  14. 2
      src/utils/helper.h
  15. 1
      src/web/RestApi.h
  16. 5
      src/web/html/setup.html
  17. 6
      src/web/web.h

5
src/CHANGES.md

@ -1,5 +1,10 @@
# Development Changes
## 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

2
src/app.cpp

@ -154,7 +154,7 @@ void app::regularTickers(void) {
everySec(std::bind(&ZeroExportType::tickerSecond, &mzExport), "zExport");
#endif
every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart");
every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart");
#if !defined(ETHERNET)
//everySec([this]() { mImprov.tickSerial(); }, "impro");
#endif

3
src/config/config.h

@ -142,9 +142,6 @@
#define MAX_NUM_INVERTERS 4
#endif
// default serial interval
#define SERIAL_INTERVAL 5
// default send interval
#define SEND_INTERVAL 15

4
src/config/settings.h

@ -114,7 +114,6 @@ typedef struct {
} cfgSun_t;
typedef struct {
uint16_t interval;
bool showIv;
bool debug;
} cfgSerial_t;
@ -446,7 +445,6 @@ class settings {
mCfg.sun.lon = 0.0;
mCfg.sun.offsetSec = 0;
mCfg.serial.interval = SERIAL_INTERVAL;
mCfg.serial.showIv = false;
mCfg.serial.debug = false;
@ -656,11 +654,9 @@ class settings {
void jsonSerial(JsonObject obj, bool set = false) {
if(set) {
obj[F("intvl")] = mCfg.serial.interval;
obj[F("show")] = mCfg.serial.showIv;
obj[F("debug")] = mCfg.serial.debug;
} else {
getVal<uint16_t>(obj, F("intvl"), &mCfg.serial.interval);
getVal<bool>(obj, F("show"), &mCfg.serial.showIv);
getVal<bool>(obj, F("debug"), &mCfg.serial.debug);
}

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 8
#define VERSION_PATCH 8
#define VERSION_PATCH 9
//-------------------------------------
typedef struct {

4
src/hm/CommQueue.h

@ -85,6 +85,10 @@ class CommQueue {
mQueue[mRdPtr].attempts--;
}
void incrAttempt(void) {
mQueue[mRdPtr].attempts++;
}
void inc(uint8_t *ptr) {
if(++(*ptr) >= N)
*ptr = 0;

128
src/hm/Communication.h

@ -11,9 +11,10 @@
#include "../utils/crc.h"
#include "Heuristic.h"
#define MI_TIMEOUT 250
#define DEFAULT_TIMEOUT 500
#define SINGLEFR_TIMEOUT 60
#define MI_TIMEOUT 250 // timeout for MI type requests
#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received
#define DEFAULT_TIMEOUT 500 // timeout for regular requests
#define SINGLEFR_TIMEOUT 65 // timeout for single frame requests
#define MAX_BUFFER 250
typedef std::function<void(uint8_t, Inverter<> *)> payloadListenerType;
@ -43,7 +44,8 @@ class Communication : public CommQueue<> {
if(!valid)
return; // empty
uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT;
uint16_t timeout = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT) : MI_TIMEOUT;
uint16_t timeout_min = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT) : MI_TIMEOUT;
bool testMode = false;
switch(mState) {
@ -55,11 +57,13 @@ class Communication : public CommQueue<> {
mLocalBuf[i].len = 0;
}
if(q->iv->radio->isSerialDebug())
mHeu.printStatus(q->iv);
mHeu.getTxCh(q->iv);
testMode = mHeu.getTestModeEnabled();
mGotFragment = false;
mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));}
q->iv->mGotFragment = false;
q->iv->mGotLastMsg = false;
mFirstTry = mFirstTry ? false : (((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000));
if(NULL == q->iv->radio)
cmdDone(true); // can't communicate while radio is not defined!
mState = States::START;
@ -84,11 +88,29 @@ class Communication : public CommQueue<> {
if(!testMode)
q->iv->radioStatistics.txCnt++;
mWaitTimeout = millis() + timeout;
mWaitTimeout_min = millis() + timeout_min;
setAttempt();
mState = States::WAIT;
break;
case States::WAIT:
if(millis() > mWaitTimeout_min) {
if(!q->iv->mGotFragment) { // nothing received yet?
if(q->iv->mGotLastMsg) {
//mState = States::CHECK_FRAMES;
mWaitTimeout = mWaitTimeout_min;
}
} else if(mFirstTry) {
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINTLN(F("second try"));
mFirstTry = false;
if(!testMode)
q->iv->radioStatistics.retransmits++; // got nothing
mState = States::START;
break;
}
}
if(millis() < mWaitTimeout)
return;
mState = States::CHECK_FRAMES;
@ -102,7 +124,7 @@ class Communication : public CommQueue<> {
DBGPRINT(String(millis() - mWaitTimeout + timeout));
DBGPRINTLN(F("ms"));
if(!mGotFragment && !mFirstTry) {
if(!q->iv->mGotFragment) {
if(!testMode)
q->iv->radioStatistics.rxFailNoAnser++; // got nothing
mHeu.setGotNothing(q->iv);
@ -118,7 +140,6 @@ class Communication : public CommQueue<> {
break;
}
mGotFragment = true;
mFirstTry = false; // for correct reset
States nextState = States::RESET;
while(!q->iv->radio->mBufCtrl.empty()) {
@ -140,7 +161,7 @@ class Communication : public CommQueue<> {
DBGPRINT(F(", "));
DBGPRINT(String(p->rssi));
DBGPRINT(F("dBm | "));
ah::dumpBuf(p->packet, p->len);
ah::dumpBuf(p->packet, p->len, 1, 8, "#"+String(q->iv->id));
if(checkIvSerial(&p->packet[1], q->iv)) {
if(!testMode)
@ -178,40 +199,39 @@ class Communication : public CommQueue<> {
break;
case States::CHECK_PACKAGE:
uint8_t framnr = 0;
if(0 == mMaxFrameId) {
setAttempt();
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("frame missing: request retransmit ("));
DBGPRINT(String(q->attempts));
DBGPRINTLN(F(" attempts left)"));
uint8_t i = 0;
while(i < MAX_PAYLOAD_ENTRIES) {
if(mLocalBuf[i].len == 0)
if(mLocalBuf[i].len == 0) {
framnr = i+1;
break;
}
i++;
}
sendRetransmit(q, i);
return;
}
if(!framnr) {
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(mLocalBuf[i].len == 0) {
framnr = i+1;
break;
}
}
}
if(framnr) {
setAttempt();
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("frame "));
DBGPRINT(String(i + 1));
DBGPRINT(String(framnr));
DBGPRINT(F(" missing: request retransmit ("));
DBGPRINT(String(q->attempts));
DBGPRINTLN(F(" attempts left)"));
sendRetransmit(q, i);
sendRetransmit(q, framnr-1);
return;
}
}
mHeu.setGotAll(q->iv);
compilePayload(q, testMode);
@ -413,9 +433,6 @@ class Communication : public CommQueue<> {
inline void miHwDecode(packet_t *p, const queue_s *q) {
record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure
rec->ts = q->ts;
//mPayload[iv->id].gotFragment = true;
uint8_t multi_parts = 0;
/*
Polling the device software and hardware version number command
start byte Command word routing address target address User data check end byte
@ -458,14 +475,13 @@ class Communication : public CommQueue<> {
q->iv->isConnected = true;
//if(mSerialDebug) {
DPRINT_IVID(DBG_INFO, q->iv->id);
DPRINT(DBG_INFO,F("HW_VER is "));
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->ts = q->ts;
q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1);
//mPayload[iv->id].multi_parts +=4;
multi_parts +=4;
q->iv->miMultiParts +=4;
} else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10
DPRINT_IVID(DBG_INFO, q->iv->id);
if ( p->packet[9] == 0x01 ) {
@ -486,19 +502,19 @@ class Communication : public CommQueue<> {
//if(mSerialDebug) {
DPRINT(DBG_INFO,F("HW_FB_TLmValue "));
DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15]));
DPRINT(DBG_INFO,F("HW_FB_ReSPRT "));
DBGPRINT(F("HW_FB_ReSPRT "));
DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17]));
DPRINT(DBG_INFO,F("HW_GridSamp_ResValule "));
DBGPRINT(F("HW_GridSamp_ResValule "));
DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19]));
DPRINT(DBG_INFO,F("HW_ECapValue "));
DBGPRINT(F("HW_ECapValue "));
DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21]));
DPRINT(DBG_INFO,F("Matching_APPFW_PN "));
DBGPRINT(F("Matching_APPFW_PN "));
DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25]));
//}
//notify(InverterDevInform_Simple, iv);
//mPayload[iv->id].multi_parts +=2;
multi_parts +=2;
//notify(InverterDevInform_All, iv);
if(NULL != mCbPayload)
(mCbPayload)(InverterDevInform_All, q->iv);
q->iv->miMultiParts +=2;
} else {
DBGPRINTLN(F("3rd gen. inverter!"));
}
@ -515,21 +531,24 @@ class Communication : public CommQueue<> {
//if(mSerialDebug) {
DPRINT(DBG_INFO,F("APPFW_MINVER "));
DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11]));
DPRINT(DBG_INFO,F("HWInfoAddr "));
DBGPRINT(F("HWInfoAddr "));
DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13]));
DPRINT(DBG_INFO,F("PNInfoCRC_gusv "));
DBGPRINT(F("PNInfoCRC_gusv "));
DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15]));
//}
//mPayload[iv->id].multi_parts++;
multi_parts++;
if(NULL != mCbPayload)
(mCbPayload)(InverterDevInform_Simple, q->iv);
q->iv->miMultiParts++;
}
if(multi_parts > 5) {
if(q->iv->miMultiParts > 5) {
cmdDone(true);
mState = States::RESET;
q->iv->radioStatistics.rxSuccess++;
mHeu.setGotAll(q->iv);
q->iv->miMultiParts = 0;
} else {
mHeu.setGotFragment(q->iv);
mState = States::WAIT;
}
/*if (mPayload[iv->id].multi_parts > 5) {
@ -568,9 +587,8 @@ class Communication : public CommQueue<> {
q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10);
q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan)));
//mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi;
if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi;
if (datachan == 1)
q->iv->rssi = p->rssi;
else if(q->iv->rssi > p->rssi)
q->iv->rssi = p->rssi;
@ -597,6 +615,7 @@ class Communication : public CommQueue<> {
} 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);
//use also miMultiParts here for better statistics?
mHeu.setGotFragment(q->iv);
} else { // first data msg for 1ch, 2nd for 2ch
miComplete(q->iv);
@ -604,25 +623,24 @@ class Communication : public CommQueue<> {
}
inline void miNextRequest(uint8_t cmd, const queue_s *q) {
//setAttempt();
incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types...
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("next request ("));
DBGPRINT(String(q->attempts));
DBGPRINT(F(" attempts left): 0x"));
DBGHEXLN(cmd);
if(q->attempts) {
//if(q->attempts) {
q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true);
q->iv->radioStatistics.retransmits++;
mWaitTimeout = millis() + MI_TIMEOUT;
//chgCmd(Inverter<> *iv, uint8_t cmd, bool delOnPop = true)
chgCmd(cmd);
mState = States::WAIT;
} else {
/*} else {
add(q, true);
cmdDone();
mState = States::RESET;
}
}*/
}
inline 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) {
@ -699,13 +717,10 @@ class Communication : public CommQueue<> {
inline void miComplete(Inverter<> *iv) {
//if ( mPayload[iv->id].complete )
// return; //if we got second message as well in repreated attempt
//mPayload[iv->id].complete = true;
//if (mSerialDebug) {
if (iv->radio->isSerialDebug()) {
DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINTLN(F("got all data msgs"));
//}
}
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0));
@ -752,8 +767,9 @@ class Communication : public CommQueue<> {
States mState = States::RESET;
uint32_t *mTimestamp;
uint32_t mWaitTimeout = 0;
uint32_t mWaitTimeout_min = 0;
std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf;
bool mGotFragment = false;
//bool mGotFragment = false;
bool mFirstTry = false;
uint8_t mMaxFrameId;
uint8_t mPayload[MAX_BUFFER];

6
src/hm/Heuristic.h

@ -62,7 +62,7 @@ class Heuristic {
void printStatus(Inverter<> *iv) {
DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINT(F("CH qualities:"));
DBGPRINT(F("Radio infos:"));
for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) {
DBGPRINT(F(" "));
DBGPRINT(String(iv->txRfQuality[i]));
@ -74,7 +74,9 @@ class Heuristic {
DBGPRINT(F(", f: "));
DBGPRINT(String(iv->radioStatistics.rxFail));
DBGPRINT(F(", n: "));
DBGPRINTLN(String(iv->radioStatistics.rxFailNoAnser));
DBGPRINT(String(iv->radioStatistics.rxFailNoAnser));
DBGPRINT(F(" | p: ")); // better debugging for helpers...
DBGPRINTLN(String(iv->config->powerLevel));
}
bool getTestModeEnabled(void) {

89
src/hm/hmInverter.h

@ -125,6 +125,10 @@ class Inverter {
uint16_t alarmCnt; // counts the total number of occurred alarms
uint16_t alarmLastId; // lastId which was received
int8_t rssi; // RSSI
uint8_t miMultiParts; // helper info for MI multiframe msgs
uint8_t outstandingFrames; // helper info to count difference between expected and received frames
bool mGotFragment; // shows if inverter has sent at least one fragment
bool mGotLastMsg; // shows if inverter has already finished transmission cycle
Radio *radio; // pointer to associated radio class
statistics_t radioStatistics; // information about transmitted, failed, ... packets
int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h')
@ -150,8 +154,11 @@ class Inverter {
alarmCnt = 0;
alarmLastId = 0;
rssi = -127;
miMultiParts = 0;
mGotLastMsg = false;
radio = NULL;
commEnabled = true;
memset(&radioStatistics, 0, sizeof(statistics_t));
memset(txRfQuality, -6, 5);
@ -587,14 +594,40 @@ class Inverter {
static String getAlarmStr(uint16_t alarmCode) {
switch (alarmCode) { // breaks are intentionally missing!
case 1: return String(F("Inverter start"));
case 2: return String(F("DTU command failed"));
case 73: return String(F("Temperature >80°C")); // https://github.com/tbnobody/OpenDTU/discussions/590#discussioncomment-6049750
case 2: return String(F("Time calibration"));
case 3: return String(F("EEPROM reading and writing error during operation"));
case 4: return String(F("Offline"));
case 11: return String(F("Grid voltage surge"));
case 12: return String(F("Grid voltage sharp drop"));
case 13: return String(F("Grid frequency mutation"));
case 14: return String(F("Grid phase mutation"));
case 15: return String(F("Grid transient fluctuation"));
case 36: return String(F("INV overvoltage or overcurrent"));
case 46: return String(F("FB overvoltage"));
case 47: return String(F("FB overcurrent"));
case 48: return String(F("FB clamp overvoltage"));
case 49: return String(F("FB clamp overvoltage"));
case 61: return String(F("Calibration parameter error"));
case 62: return String(F("System configuration parameter error"));
case 63: return String(F("Abnormal power generation data"));
case 71: return String(F("Grid overvoltage load reduction (VW) function enable"));
case 72: return String(F("Power grid over-frequency load reduction (FW) function enable"));
case 73: return String(F("Over-temperature load reduction (TW) function enable"));
case 95: return String(F("PV-1: Module in suspected shadow"));
case 96: return String(F("PV-2: Module in suspected shadow"));
case 97: return String(F("PV-3: Module in suspected shadow"));
case 98: return String(F("PV-4: Module in suspected shadow"));
case 121: return String(F("Over temperature protection"));
case 122: return String(F("Microinverter is suspected of being stolen"));
case 123: return String(F("Locked by remote control"));
case 124: return String(F("Shut down by remote control"));
case 125: return String(F("Grid configuration parameter error"));
case 126: return String(F("Software error code 126"));
case 126: return String(F("EEPROM reading and writing error"));
case 127: return String(F("Firmware error"));
case 128: return String(F("Software error code 128"));
case 128: return String(F("Hardware configuration error"));
case 129: return String(F("Abnormal bias"));
case 130: return String(F("Offline"));
case 141: return String(F("Grid: Grid overvoltage"));
@ -606,7 +639,12 @@ class Inverter {
case 147: return String(F("Grid: Power grid outage"));
case 148: return String(F("Grid: Grid disconnection"));
case 149: return String(F("Grid: Island detected"));
case 150: return String(F("DCI exceeded"));
case 171: return String(F("Grid: Abnormal phase difference between phase to phase"));
case 181: return String(F("Abnormal insulation impedance"));
case 182: return String(F("Abnormal grounding"));
case 205: return String(F("MPPT-A: Input overvoltage"));
case 206: return String(F("MPPT-B: Input overvoltage"));
case 207: return String(F("MPPT-A: Input undervoltage"));
@ -625,24 +663,33 @@ class Inverter {
case 220: return String(F("PV-3: Input undervoltage"));
case 221: return String(F("PV-4: Input overvoltage"));
case 222: return String(F("PV-4: Input undervoltage"));
case 301: return String(F("Hardware error code 301"));
case 302: return String(F("Hardware error code 302"));
case 303: return String(F("Hardware error code 303"));
case 304: return String(F("Hardware error code 304"));
case 305: return String(F("Hardware error code 305"));
case 306: return String(F("Hardware error code 306"));
case 307: return String(F("Hardware error code 307"));
case 308: return String(F("Hardware error code 308"));
case 301: return String(F("FB short circuit failure"));
case 302: return String(F("FB short circuit failure"));
case 303: return String(F("FB overcurrent protection failure"));
case 304: return String(F("FB overcurrent protection failure"));
case 305: return String(F("FB clamp circuit failure"));
case 306: return String(F("FB clamp circuit failure"));
case 307: return String(F("INV power device failure"));
case 308: return String(F("INV overcurrent or overvoltage protection failure"));
case 309: return String(F("Hardware error code 309"));
case 310: return String(F("Hardware error code 310"));
case 311: return String(F("Hardware error code 311"));
case 312: return String(F("Hardware error code 312"));
case 313: return String(F("Hardware error code 313"));
case 314: return String(F("Hardware error code 314"));
case 5041: return String(F("Error code-04 Port 1"));
case 5042: return String(F("Error code-04 Port 2"));
case 5043: return String(F("Error code-04 Port 3"));
case 5044: return String(F("Error code-04 Port 4"));
case 5011: return String(F("PV-1: MOSFET overcurrent (II)"));
case 5012: return String(F("PV-2: MOSFET overcurrent (II)"));
case 5013: return String(F("PV-3: MOSFET overcurrent (II)"));
case 5014: return String(F("PV-4: MOSFET overcurrent (II)"));
case 5020: return String(F("H-bridge MOSFET overcurrent or H-bridge overvoltage"));
case 5041: return String(F("PV-1: current overcurrent (II)"));
case 5042: return String(F("PV-2: current overcurrent (II)"));
case 5043: return String(F("PV-3: current overcurrent (II)"));
case 5044: return String(F("PV-4: current overcurrent (II)"));
case 5051: return String(F("PV Input 1 Overvoltage/Undervoltage"));
case 5052: return String(F("PV Input 2 Overvoltage/Undervoltage"));
case 5053: return String(F("PV Input 3 Overvoltage/Undervoltage"));
@ -652,10 +699,18 @@ class Inverter {
case 5080: return String(F("Grid Overvoltage/Undervoltage"));
case 5090: return String(F("Grid Overfrequency/Underfrequency"));
case 5100: return String(F("Island detected"));
case 5110: return String(F("GFDI"));
case 5120: return String(F("EEPROM reading and writing error"));
case 5141:
case 5142:
case 5143:
case 5144:
return String(F("FB clamp overvoltage"));
case 5150: return String(F("10 min value grid overvoltage"));
case 5160: return String(F("Grid transient fluctuation"));
case 5200: return String(F("Firmware error"));
case 8310: return String(F("Shut down"));
case 8310: return String(F("Shut down by remote control"));
case 8320: return String(F("Locked by remote control"));
case 9000: return String(F("Microinverter is suspected of being stolen"));
default: return String(F("Unknown"));
}

21
src/hm/hmRadio.h

@ -252,17 +252,25 @@ class HmRadio : public Radio {
p.millis = millis() - mMillis;
mNrf24.read(p.packet, p.len);
if (p.packet[0] != 0x00) {
if(!checkIvSerial(&p.packet[1], mLastIv)) {
DPRINT(DBG_WARN, "RX other inverter: ");
ah::dumpBuf(p.packet, p.len);
return false;
}
mLastIv->mGotFragment = true;
mBufCtrl.push(p);
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
else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command
isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received
else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore fragment number zero and MI status messages //#0 was p.packet[0] != 0x00 &&
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
}
}
yield();
}
if(isLastPackage)
mLastIv->mGotLastMsg = true;
return isLastPackage;
}
@ -280,7 +288,7 @@ class HmRadio : public Radio {
DBGPRINT(" CH");
DBGPRINT(String(mTxChIdx));
DBGPRINT(F(" | "));
ah::dumpBuf(mTxBuf, len);
ah::dumpBuf(mTxBuf, len, 1, 4, "#"+String(iv->id));
}
mNrf24.stopListening();
@ -300,10 +308,19 @@ class HmRadio : public Radio {
return iv->ivGen;
}
inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) {
for(uint8_t i = 0; i < 4; i++) {
if(buf[3-i] != iv->radioId.b[i])
return false;
}
return true;
}
uint64_t DTU_RADIO_ID;
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;
bool mGotLastMsg = false;
uint32_t mMillis;
SPIClass* mSpi;

4
src/hm/radio.h

@ -38,6 +38,10 @@ class Radio {
mSerialDebug = true;
}
bool isSerialDebug() {
return mSerialDebug;
}
void sendCmdPacket(Inverter<> *iv, uint8_t mid, uint8_t pid, bool isRetransmit, bool appendCrc16=true) {
initPacket(getIvId(iv), mid, pid);
sendPacket(iv, 10, isRetransmit, appendCrc16);

18
src/platformio.ini

@ -25,9 +25,9 @@ extra_scripts =
lib_deps =
https://github.com/yubox-node-org/ESPAsyncWebServer
nrf24/RF24 @ 1.4.7
nrf24/RF24 @ 1.4.8
paulstoffregen/Time @ ^1.6.1
https://github.com/bertmelis/espMqttClient#v1.4.5
https://github.com/bertmelis/espMqttClient#v1.5.0
bblanchon/ArduinoJson @ ^6.21.3
https://github.com/JChristensen/Timezone @ ^1.2.4
olikraus/U8g2 @ ^2.35.7
@ -71,7 +71,7 @@ monitor_filters =
esp8266_exception_decoder
[env:esp32-wroom32]
platform = espressif32@6.3.2
platform = espressif32@6.4.0
board = lolin_d32
build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD
@ -79,7 +79,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-wroom32-prometheus]
platform = espressif32@6.3.2
platform = espressif32@6.4.0
board = lolin_d32
build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD
@ -93,9 +93,9 @@ board = esp32dev
lib_deps =
khoih-prog/AsyncWebServer_ESP32_W5500
khoih-prog/AsyncUDP_ESP32_W5500
nrf24/RF24 @ ^1.4.7
nrf24/RF24 @ ^1.4.8
paulstoffregen/Time @ ^1.6.1
https://github.com/bertmelis/espMqttClient#v1.4.4
https://github.com/bertmelis/espMqttClient#v1.5.0
bblanchon/ArduinoJson @ ^6.21.3
https://github.com/JChristensen/Timezone @ ^1.2.4
olikraus/U8g2 @ ^2.35.7
@ -110,7 +110,7 @@ monitor_filters =
esp32_exception_decoder
[env:esp32-s2-mini]
platform = espressif32@6.3.2
platform = espressif32@6.4.0
board = lolin_s2_mini
build_flags = ${env.build_flags}
-DUSE_HSPI_FOR_EPD
@ -124,7 +124,7 @@ monitor_filters =
esp32_exception_decoder
[env:opendtufusion]
platform = espressif32@6.3.2
platform = espressif32@6.4.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env.build_flags}
@ -147,7 +147,7 @@ monitor_filters =
esp32_exception_decoder, colorize
[env:opendtufusion-dev]
platform = espressif32@6.3.2
platform = espressif32@6.4.0
board = esp32-s3-devkitc-1
upload_protocol = esp-builtin
build_flags = ${env.build_flags}

5
src/utils/helper.cpp

@ -86,9 +86,12 @@ namespace ah {
return ret;
}
void dumpBuf(uint8_t buf[], uint8_t len) {
void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl, uint8_t lastRepl, String repl) {
for(uint8_t i = 0; i < len; i++) {
if(i < firstRepl || i > lastRepl)
DHEX(buf[i]);
else
DBGPRINT(repl);
DBGPRINT(" ");
}
DBGPRINTLN("");

2
src/utils/helper.h

@ -45,7 +45,7 @@ namespace ah {
String getDateTimeStrFile(time_t t);
String getTimeStr(time_t t);
uint64_t Serial2u64(const char *val);
void dumpBuf(uint8_t buf[], uint8_t len);
void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0, String repl = "");
}
#endif /*__HELPER_H__*/

1
src/web/RestApi.h

@ -574,7 +574,6 @@ class RestApi {
}
void getSerial(JsonObject obj) {
obj[F("interval")] = (uint16_t)mConfig->serial.interval;
obj[F("show_live_data")] = mConfig->serial.showIv;
obj[F("debug")] = mConfig->serial.debug;
}

5
src/web/html/setup.html

@ -49,10 +49,6 @@
<div class="col-8 col-sm-3">Serial Debug</div>
<div class="col-4 col-sm-9"><input type="checkbox" name="serDbg"/></div>
</div>
<div class="row mb-3">
<div class="col-12 col-sm-3 my-2">Interval [s]</div>
<div class="col-12 col-sm-9"><input type="number" name="serIntvl" title="Invalid input"/></div>
</div>
</fieldset>
</div>
@ -984,7 +980,6 @@
function parseSerial(obj) {
for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"]])
document.getElementsByName(i[0])[0].checked = obj[i[1]];
document.getElementsByName("serIntvl")[0].value = obj["interval"];
}
function parseDisplay(obj, type, system) {

6
src/web/web.h

@ -582,14 +582,8 @@ class Web {
#endif
// serial console
if (request->arg("serIntvl") != "") {
mConfig->serial.interval = request->arg("serIntvl").toInt() & 0xffff;
mConfig->serial.debug = (request->arg("serDbg") == "on");
mConfig->serial.showIv = (request->arg("serEn") == "on");
// Needed to log TX buffers to serial console
// mSys->Radio.mSerialDebug = mConfig->serial.debug;
}
// display
mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on");

Loading…
Cancel
Save