diff --git a/src/app.cpp b/src/app.cpp index 0e0aec5f..44d8ab30 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -60,6 +60,7 @@ void app::setup() { #endif /* defined(ETHERNET) */ mCommunication.setup(&mTimestamp); + mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); mSys.setup(&mTimestamp, &mConfig->inst); for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mSys.addInverter(i, [this](Inverter<> *iv) { @@ -93,6 +94,7 @@ void app::setup() { if (mMqttEnabled) { mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime); mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1)); + mCommunication.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); //mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); //mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); } @@ -122,7 +124,7 @@ void app::setup() { //----------------------------------------------------------------------------- void app::loop(void) { ah::Scheduler::loop(); - bool processPayload = false; + //bool processPayload = false; mNrfRadio.loop(); #if defined(ESP32) @@ -403,8 +405,6 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { - DPRINTLN(DBG_INFO, "tickSend"); - if(!mIVCommunicationOn) { DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); return; @@ -413,8 +413,11 @@ void app::tickSend(void) { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); if(NULL != iv) { - iv->tickSend([this, iv](uint8_t cmd) { - mCommunication.add(iv, cmd); + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { + if(isDevControl) + mCommunication.addImportant(iv, cmd); + else + mCommunication.add(iv, cmd); }); }; } diff --git a/src/app.h b/src/app.h index d1a13a6a..d28c3bf6 100644 --- a/src/app.h +++ b/src/app.h @@ -12,12 +12,11 @@ #include "config/settings.h" #include "defines.h" #include "appInterface.h" -#include "hm/hmPayload.h" #include "hm/hmSystem.h" #include "hm/hmRadio.h" #include "hms/hmsRadio.h" -#include "hm/hmPayload.h" -#include "hm/miPayload.h" +//#include "hm/hmPayload.h" +//#include "hm/miPayload.h" #include "publisher/pubMqtt.h" #include "publisher/pubSerial.h" #include "utils/crc.h" @@ -42,8 +41,8 @@ #define ACOS(x) (degrees(acos(x))) typedef HmSystem HmSystemType; -typedef HmPayload PayloadType; -typedef MiPayload MiPayloadType; +//typedef HmPayload PayloadType; +//typedef MiPayload MiPayloadType; #ifdef ESP32 typedef CmtRadio CmtRadioType; #endif @@ -174,8 +173,8 @@ class app : public IApp, public ah::Scheduler { void ivSendHighPrio(Inverter<> *iv) { if(mIVCommunicationOn) { // only send commands if communication is enabled - if (iv->ivGen == IV_MI) - mMiPayload.ivSendHighPrio(iv); + //if (iv->ivGen == IV_MI) + // mMiPayload.ivSendHighPrio(iv); //else // mPayload.ivSendHighPrio(iv); } @@ -320,7 +319,7 @@ class app : public IApp, public ah::Scheduler { WebType mWeb; RestApiType mApi; //PayloadType mPayload; - MiPayloadType mMiPayload; + //MiPayloadType mMiPayload; PubSerialType mPubSerial; #if !defined(ETHERNET) //Improv mImprov; diff --git a/src/defines.h b/src/defines.h index 80ecf9c0..be59fb4f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -12,8 +12,8 @@ // VERSION //------------------------------------- #define VERSION_MAJOR 0 -#define VERSION_MINOR 7 -#define VERSION_PATCH 66 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index e65484e7..4cdf0beb 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,6 +10,9 @@ #include #include "../utils/crc.h" +typedef std::function *)> payloadListenerType; +typedef std::function *)> alarmListenerType; + class Communication : public CommQueue<> { public: void setup(uint32_t *timestamp) { @@ -21,6 +24,14 @@ class Communication : public CommQueue<> { CommQueue::addImportant(iv, cmd, delOnPop); } + void addPayloadListener(payloadListenerType cb) { + mCbPayload = cb; + } + + void addAlarmListener(alarmListenerType cb) { + mCbAlarm = cb; + } + void loop() { get([this](bool valid, const queue_s *q) { if(!valid) @@ -45,6 +56,7 @@ class Communication : public CommQueue<> { q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + 500; setAttempt(); mState = States::WAIT; @@ -59,7 +71,10 @@ class Communication : public CommQueue<> { case States::CHECK_FRAMES: { if(!q->iv->radio->get()) { // radio buffer empty cmdDone(); - DBGPRINTLN(F("request timeout")); + DPRINT(DBG_INFO, F("request timeout: ")); + DBGPRINT(String(millis() - mWaitTimeout + 500)); + DBGPRINTLN(F("ms")); + q->iv->radioStatistics.rxFailNoAnser++; // got nothing if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); @@ -74,12 +89,14 @@ class Communication : public CommQueue<> { packet_t *p = &q->iv->radio->mBufCtrl.front(); DPRINT_IVID(DBG_INFO, q->iv->id); - DPRINT(DBG_INFO, F("RX ")); + DBGPRINT(F("RX ")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); - DBGPRINT(F(" CH")); - DBGPRINT(String(p->ch)); + if(IV_HM == q->iv->ivGen) { + DBGPRINT(F(" CH")); + DBGPRINT(String(p->ch)); + } DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); @@ -91,8 +108,10 @@ class Communication : public CommQueue<> { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command parseFrame(p); nextState = States::CHECK_PACKAGE; - } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); + cmdDone(true); // remove done request + } } q->iv->radio->mBufCtrl.pop(); @@ -104,26 +123,40 @@ class Communication : public CommQueue<> { case States::CHECK_PACKAGE: if(0 == mMaxFrameId) { + setAttempt(); + DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("last frame missing: request retransmit")); + DBGPRINT(F("last 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) + break; + } - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + mMaxFrameId + 1), true); - setAttempt(); - mWaitTimeout = millis() + 100; + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; mState = States::WAIT; break; } for(uint8_t i = 0; i < mMaxFrameId; i++) { if(mLocalBuf[i].len == 0) { + setAttempt(); + DPRINT_IVID(DBG_WARN, q->iv->id); DBGPRINT(F("frame ")); DBGPRINT(String(i + 1)); - DBGPRINTLN(F(" missing: request retransmit")); + DBGPRINT(F(" missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - setAttempt(); - mWaitTimeout = millis() + 100; + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; mState = States::WAIT; return; } @@ -131,6 +164,9 @@ class Communication : public CommQueue<> { compilePayload(q); + if(NULL != mCbPayload) + (mCbPayload)(q->cmd, q->iv); + cmdDone(true); // remove done request mState = States::RESET; // everything ok, next request break; @@ -194,6 +230,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->iv->powerLimit[0])); DBGPRINT(F(" with PowerLimitControl ")); DBGPRINTLN(String(q->iv->powerLimit[1])); + q->iv->actPowerLimit = 0xffff; // unknown, readback current value } inline void compilePayload(const queue_s *q) { @@ -220,9 +257,9 @@ class Communication : public CommQueue<> { return; } - DPRINT_IVID(DBG_INFO, q->iv->id); + /*DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(q->cmd); + DBGHEXLN(q->cmd);*/ memset(mPayload, 0, 150); int8_t rssi = -127; @@ -247,6 +284,40 @@ class Communication : public CommQueue<> { DBGPRINT(String(len)); DBGPRINT(F("): ")); ah::dumpBuf(mPayload, len); + + record_t<> *rec = q->iv->getRecordStruct(q->cmd); + if(NULL == rec) { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + return; + } + if((rec->pyldLen != len) && (0 != rec->pyldLen)) { + DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); + DBGPRINT(String(rec->pyldLen)); + DBGPRINTLN(F(" bytes")); + q->iv->radioStatistics.rxFail++; + return; + } + + q->iv->radioStatistics.rxSuccess++; + + rec->ts = q->ts; + for (uint8_t i = 0; i < rec->length; i++) { + q->iv->addValue(i, mPayload, rec); + } + + q->iv->rssi = rssi; + q->iv->doCalculations(); + + if(AlarmData == q->cmd) { + uint8_t i = 0; + while(1) { + if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) + break; + if (NULL != mCbAlarm) + (mCbAlarm)(q->iv); + yield(); + } + } } private: @@ -267,6 +338,8 @@ class Communication : public CommQueue<> { std::array mLocalBuf; uint8_t mMaxFrameId; uint8_t mPayload[150]; + payloadListenerType mCbPayload = NULL; + alarmListenerType mCbAlarm = NULL; }; #endif /*__COMMUNICATION_H__*/ diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 72ab5c4c..acd81541 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -77,6 +77,15 @@ enum {CH0 = 0, CH1, CH2, CH3, CH4, CH5, CH6}; enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; +#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 + typedef struct { uint8_t fieldId; // field id diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 8dfb5156..5e3e4266 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -181,18 +181,23 @@ class Inverter { // TODO: cleanup } - void tickSend(std::function cb) { - if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) - cb(AlarmData); // get last alarms + void tickSend(std::function cb) { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + cb(AlarmData, false); // get last alarms else if(0 == getFwVersion()) - cb(InverterDevInform_All); // get firmware version + cb(InverterDevInform_All, false); // get firmware version else if(0 == getHwVersion()) - cb(InverterDevInform_Simple); // get hardware version + cb(InverterDevInform_Simple, false); // get hardware version + else if(actPowerLimit == 0xffff) + cb(SystemConfigPara, false); // power limit info else - cb(RealTimeRunData_Debug); // get live data + cb(RealTimeRunData_Debug, false); // get live data } - template + /*template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); DPRINT_IVID(DBG_INFO, id); @@ -240,7 +245,7 @@ class Inverter { enqueCommand(SystemConfigPara); // power limit info } return _commandQueue.front().get()->getCmd(); - } + }*/ void init(void) { @@ -305,10 +310,6 @@ class Inverter { mDevControlRequest = false; } - inline bool getDevControlRequest() { - return mDevControlRequest; - } - void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:addValue")); if(NULL != rec) { @@ -350,7 +351,7 @@ class Inverter { DPRINT(DBG_INFO, "alarm ID incremented to "); DBGPRINTLN(String(alarmMesIndex)); - enqueCommand(AlarmData); + //enqueCommand(AlarmData); } } } @@ -727,7 +728,7 @@ class Inverter { radioId.b[0] = 0x01; } - std::queue> _commandQueue; + //std::queue> _commandQueue; bool mDevControlRequest; // true if change needed }; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 7e76644d..461fd08e 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -118,8 +118,8 @@ class HmRadio : public Radio { mNrf24.startListening(); uint32_t startMicros = micros(); - uint32_t loopMillis = millis(); - while (millis()-loopMillis < 400) { + uint32_t loopMillis = millis() + 400; + while (millis() < loopMillis) { while (micros()-startMicros < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; @@ -277,7 +277,8 @@ class HmRadio : public Radio { mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; if(mSerialDebug) { - DPRINT(DBG_INFO, F("TX ")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); DBGPRINT(String(mRfChLst[mTxChIdx])); @@ -290,11 +291,6 @@ class HmRadio : public Radio { mNrf24.openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response mMillis = millis(); - - if(isRetransmit) - iv->radioStatistics.retransmits++; - else - iv->radioStatistics.txCnt++; } uint64_t getIvId(Inverter<> *iv) { diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 9d00ba20..ab54617d 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -8,15 +8,6 @@ #include "esp32_3wSpi.h" -#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 - // detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf #define CMT2300A_MASK_CFG_RETAIN 0x10 diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index c01a95bc..24c3c7cd 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -80,7 +80,8 @@ class CmtRadio : public Radio { updateCrcs(&len, appendCrc16); if(mSerialDebug) { - DPRINT(DBG_INFO, F("TX ")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("TX ")); DBGPRINT(String(mCmt.getFreqKhz()/1000.0f)); DBGPRINT(F("Mhz | ")); ah::dumpBuf(mTxBuf, len); @@ -94,11 +95,6 @@ class CmtRadio : public Radio { if(CMT_ERR_RX_IN_FIFO == status) mIrqRcvd = true; } - - if(isRetransmit) - iv->radioStatistics.retransmits++; - else - iv->radioStatistics.txCnt++; } uint64_t getIvId(Inverter<> *iv) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 225c26c8..e53c91da 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -683,7 +683,7 @@ class RestApi { } else if(F("dev") == jsonIn[F("cmd")]) { DPRINTLN(DBG_INFO, F("dev cmd")); - iv->enqueCommand(jsonIn[F("val")].as()); + //iv->enqueCommand(jsonIn[F("val")].as()); } else { jsonOut[F("error")] = F("unknown cmd: '") + jsonIn["cmd"].as() + "'"; diff --git a/src/web/html/serial.html b/src/web/html/serial.html index 10d1769e..3f9b4d94 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -7,9 +7,9 @@ {#HTML_NAV}
-
+
- +
console active:
@@ -42,7 +42,7 @@ if(true == exeOnce) { parseNav(obj); parseESP(obj); - window.setInterval("getAjax('/api/generic', parseGeneric)", 10000); + window.setInterval("getAjax('/api/generic', parseGeneric)", 5000); exeOnce = false; setTimeOffset(); } diff --git a/src/web/html/style.css b/src/web/html/style.css index cca955eb..95cbff3b 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -24,6 +24,11 @@ input[type=file] { width: 100%; } +textarea { + color: var(--fg); + background-color: var(--bg); +} + #live span { color: var(--fg2); }