diff --git a/src/CHANGES.md b/src/CHANGES.md index a0e1e35b..1e9b48e1 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,16 @@ (starting from release version `0.5.66`) +## 0.5.74 +* improved payload handling (retransmit all fragments on CRC error) +* improved `isAvailable`, checkes 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 Expeptions 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) diff --git a/src/app.cpp b/src/app.cpp index d0e2da51..d698bba8 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -3,11 +3,6 @@ // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ //----------------------------------------------------------------------------- -#if defined(ESP32) && defined(F) -#undef F -#define F(sl) (sl) -#endif - #include "app.h" #include #include "utils/sun.h" @@ -43,7 +38,7 @@ void app::setup() { mWifi.setup(mConfig, &mTimestamp, std::bind(&app::onWifi, this, std::placeholders::_1)); #if !defined(AP_ONLY) - everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi)); + everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL"); #endif mSys->addInverters(&mConfig->inst); @@ -136,48 +131,49 @@ void app::onWifi(bool gotIp) { regularTickers(); // reinstall regular tickers if (gotIp) { mInnerLoopCb = std::bind(&app::loopStandard, this); - mSendTickerId = every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval); + mSendTickerId = every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); mMqttReconnect = true; - once(std::bind(&app::tickNtpUpdate, this), 2); + once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); } else { mInnerLoopCb = std::bind(&app::loopWifi, this); - everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi)); + everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL"); } } //----------------------------------------------------------------------------- void app::regularTickers(void) { DPRINTLN(DBG_DEBUG, F("regularTickers")); - everySec(std::bind(&WebType::tickSecond, &mWeb)); + everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc"); // Plugins #if defined(ENA_NOKIA) || defined(ENA_SSD1306) || defined(ENA_SH1106) everySec(std::bind(&MonoDisplayType::tickerSecond, &mMonoDisplay)); #endif - every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval); + every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart"); } //----------------------------------------------------------------------------- void app::tickNtpUpdate(void) { uint32_t nxtTrig = 5; // default: check again in 5 sec - if (mWifi.getNtpTime()) { + if (mWifi.getNtpTime(&nxtTrig)) { if (mMqttReconnect && mMqttEnabled) { mMqtt.connect(); - everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt)); - everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt)); + everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS"); + everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM"); uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight if(mConfig->mqtt.rstYieldMidNight) - onceAt(std::bind(&app::tickMidnight, this), nxtTrig); + onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "midNi"); mMqttReconnect = false; } - nxtTrig = 43200; // check again in 12 h + nxtTrig = 43200; + if((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) { mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600; tickCalcSunrise(); } } - once(std::bind(&app::tickNtpUpdate, this), nxtTrig); + once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp"); } //----------------------------------------------------------------------------- @@ -191,7 +187,7 @@ void app::tickCalcSunrise(void) { tickIVCommunication(); uint32_t nxtTrig = mSunset + mConfig->sun.offsetSec + 60; // set next trigger to communication stop, +60 for safety that it is certain past communication stop - onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig); + onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig, "Sunri"); if (mMqttEnabled) tickSun(); } @@ -212,7 +208,7 @@ void app::tickIVCommunication(void) { } } if (nxtTrig != 0) - onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig); + onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); } if (mMqttEnabled) tickComm(); @@ -222,14 +218,14 @@ void app::tickIVCommunication(void) { void app::tickSun(void) { // only used and enabled by MQTT (see setup()) if (!mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec, mConfig->sun.disNightCom)) - once(std::bind(&app::tickSun, this), 1); // MQTT not connected, retry + once(std::bind(&app::tickSun, this), 1, "mqSun"); // MQTT not connected, retry } //----------------------------------------------------------------------------- void app::tickComm(void) { // only used and enabled by MQTT (see setup()) if (!mMqtt.tickerComm(!mIVCommunicationOn)) - once(std::bind(&app::tickComm, this), 1); // MQTT not connected, retry + once(std::bind(&app::tickComm, this), 1, "mqCom"); // MQTT not connected, retry } //----------------------------------------------------------------------------- @@ -268,7 +264,7 @@ void app::tickSend(void) { void app::tickMidnight(void) { // only used and enabled by MQTT (see setup()) uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight - onceAt(std::bind(&app::tickMidnight, this), nxtTrig); + onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "mid2"); mMqtt.tickerMidnight(); } @@ -285,8 +281,6 @@ void app::resetSystem(void) { #ifdef AP_ONLY mTimestamp = 1; -#else - mTimestamp = 0; #endif mSunrise = 0; @@ -329,8 +323,7 @@ void app::updateLed(void) { if(mConfig->led.led0 != 0xff) { Inverter<> *iv = mSys->getInverterByPos(0); if (NULL != iv) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - if(iv->isProducing(mTimestamp, rec)) + if(iv->isProducing(mTimestamp)) digitalWrite(mConfig->led.led0, LOW); // LED on else digitalWrite(mConfig->led.led0, HIGH); // LED off diff --git a/src/app.h b/src/app.h index b66f4abf..7a0cd38e 100644 --- a/src/app.h +++ b/src/app.h @@ -102,7 +102,7 @@ class app : public IApp, public ah::Scheduler { } void setRebootFlag() { - once(std::bind(&app::tickReboot, this), 3); + once(std::bind(&app::tickReboot, this), 3, "rboot"); } const char *getVersion() { @@ -126,7 +126,7 @@ class app : public IApp, public ah::Scheduler { } void setMqttDiscoveryFlag() { - once(std::bind(&PubMqttType::sendDiscoveryConfig, &mMqtt), 1); + once(std::bind(&PubMqttType::sendDiscoveryConfig, &mMqtt), 1, "disCf"); } void setMqttPowerLimitAck(Inverter<> *iv) { @@ -174,10 +174,16 @@ class app : public IApp, public ah::Scheduler { getStat(max); } + void getSchedulerNames(void) { + printSchedulers(); + } + void setTimestamp(uint32_t newTime) { DPRINTLN(DBG_DEBUG, F("setTimestamp: ") + String(newTime)); - if(0 == newTime) - mWifi.getNtpTime(); + if(0 == newTime) { + uint32_t tmp; + mWifi.getNtpTime(&tmp); + } else Scheduler::setTimestamp(newTime); } diff --git a/src/appInterface.h b/src/appInterface.h index c2d191b2..a8e37a75 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -31,6 +31,7 @@ class IApp { virtual String getTimeStr(uint32_t offset) = 0; virtual uint32_t getTimezoneOffset() = 0; virtual void getSchedulerInfo(uint8_t *max) = 0; + virtual void getSchedulerNames() = 0; virtual bool getRebootRequestState() = 0; virtual bool getSettingsValid() = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 28045bb6..5a83c699 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -162,10 +162,11 @@ class settings { if(!LittleFS.begin(LITTLFS_FALSE)) { DPRINTLN(DBG_INFO, F(".. format ..")); LittleFS.format(); - if(LittleFS.begin(LITTLFS_TRUE)) + if(LittleFS.begin(LITTLFS_TRUE)) { DPRINTLN(DBG_INFO, F(".. success")); - else + } else { DPRINTLN(DBG_INFO, F(".. failed")); + } } else diff --git a/src/defines.h b/src/defines.h index e9ca58b2..d0fe6bf1 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 73 +#define VERSION_PATCH 74 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 8ce0e390..18b0869c 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -164,7 +164,7 @@ class Inverter { if (getFwVersion() == 0) enqueCommand(InverterDevInform_All); // firmware version enqueCommand(RealTimeRunData_Debug); // live data - if (actPowerLimit == 0xffff) + if ((actPowerLimit == 0xffff) && isConnected) enqueCommand(SystemConfigPara); // power limit info } return _commandQueue.front().get()->getCmd(); @@ -220,9 +220,11 @@ class Inverter { return 0; } - bool setDevControlRequest() { - if(isConnected) + bool setDevControlRequest(uint8_t cmd) { + if(isConnected) { mDevControlRequest = true; + devControlCmd = cmd; + } return isConnected; } @@ -333,16 +335,23 @@ class Inverter { } } - bool isAvailable(uint32_t timestamp, record_t<> *rec) { - DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isAvailable")); - return ((timestamp - rec->ts) < INACT_THRES_SEC); + bool isAvailable(uint32_t timestamp) { + if((timestamp - recordMeas.ts) < INACT_THRES_SEC) + return true; + if((timestamp - recordInfo.ts) < INACT_THRES_SEC) + return true; + if((timestamp - recordConfig.ts) < INACT_THRES_SEC) + return true; + if((timestamp - recordAlarm.ts) < INACT_THRES_SEC) + return true; + return false; } - bool isProducing(uint32_t timestamp, record_t<> *rec) { + bool isProducing(uint32_t timestamp) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isProducing")); - if(isAvailable(timestamp, rec)) { - uint8_t pos = getPosByChFld(CH0, FLD_PAC, rec); - return (getValue(pos, rec) > INACT_PWR_THRESH); + if(isAvailable(timestamp)) { + uint8_t pos = getPosByChFld(CH0, FLD_PAC, &recordMeas); + return (getValue(pos, &recordMeas) > INACT_PWR_THRESH); } return false; } diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 2c4b6f07..ee84263b 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -89,6 +89,7 @@ class HmRadio { mRxLoopCnt = RF_LOOP_CNT; mSendCnt = 0; + mRetransmits = 0; mSerialDebug = false; mIrqRcvd = false; @@ -194,7 +195,7 @@ class HmRadio { return mRfChLst[mTxChIdx]; } - void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data) { + void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) { DPRINTLN(DBG_INFO, F("sendControlPacket cmd: 0x") + String(cmd, HEX)); sendCmdPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME, false); uint8_t cnt = 0; @@ -215,12 +216,12 @@ class HmRadio { // crc over all mTxBuf[10 + cnt] = ah::crc8(mTxBuf, 10 + cnt); - sendPacket(invId, mTxBuf, 10 + cnt + 1, true); + sendPacket(invId, mTxBuf, 10 + cnt + 1, isRetransmit, true); } - void sendTimePacket(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId) { + void sendTimePacket(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit) { DPRINTLN(DBG_DEBUG, F("sendTimePacket 0x") + String(cmd, HEX)); - sendCmdPacket(invId, TX_REQ_INFO, ALL_FRAMES, false); + sendCmdPacket(invId, TX_REQ_INFO, ALL_FRAMES, isRetransmit, false); mTxBuf[10] = cmd; // cid mTxBuf[11] = 0x00; CP_U32_LittleEndian(&mTxBuf[12], ts); @@ -233,10 +234,10 @@ class HmRadio { mTxBuf[25] = (crc ) & 0xff; mTxBuf[26] = ah::crc8(mTxBuf, 26); - sendPacket(invId, mTxBuf, 27, true); + sendPacket(invId, mTxBuf, 27, isRetransmit, true); } - void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool calcCrc = true) { + void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool isRetransmit, bool calcCrc = true) { DPRINTLN(DBG_VERBOSE, F("sendCmdPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); mTxBuf[0] = mid; // message id @@ -245,7 +246,7 @@ class HmRadio { mTxBuf[9] = pid; if(calcCrc) { mTxBuf[10] = ah::crc8(mTxBuf, 10); - sendPacket(invId, mTxBuf, 11, false); + sendPacket(invId, mTxBuf, 11, isRetransmit, false); } } @@ -308,11 +309,12 @@ class HmRadio { uint32_t mSendCnt; + uint32_t mRetransmits; bool mSerialDebug; private: - void sendPacket(uint64_t invId, uint8_t buf[], uint8_t len, bool clear=false) { + void sendPacket(uint64_t invId, uint8_t buf[], uint8_t len, bool isRetransmit, bool clear=false) { //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket")); //DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt)); //dumpBuf("SEN ", buf, len); @@ -347,7 +349,10 @@ class HmRadio { mNrf24.startListening(); RESTORE_IRQ; - mSendCnt++; + if(isRetransmit) + mRetransmits++; + else + mSendCnt++; } uint8_t getTxNxtChannel(void) { diff --git a/src/hm/payload.h b/src/hm/payload.h index db607e10..093edbd3 100644 --- a/src/hm/payload.h +++ b/src/hm/payload.h @@ -103,14 +103,14 @@ class Payload : public Handler { if (iv->getDevControlRequest()) { if (mSerialDebug) DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request 0x") + String(iv->devControlCmd, HEX) + F(" power limit ") + String(iv->powerLimit[0])); - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); mPayload[iv->id].txCmd = iv->devControlCmd; //iv->clearCmdQueue(); //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); // + String(cmd, HEX)); - mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex); + mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false); mPayload[iv->id].txCmd = cmd; } } @@ -177,7 +177,9 @@ class Payload : public Handler { } if (!mPayload[iv->id].complete) { - if (!build(iv->id)) { // payload not complete + bool crcPass, pyldComplete; + crcPass = build(iv->id, &pyldComplete); + if (!crcPass && !pyldComplete) { // payload not complete if ((mPayload[iv->id].requested) && (retransmit)) { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. @@ -185,7 +187,7 @@ class Payload : public Handler { mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { DPRINTLN(DBG_INFO, F("retransmit power limit")); - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; @@ -193,12 +195,12 @@ class Payload : public Handler { DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX)); - mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex); + mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } else { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { if (mPayload[iv->id].len[i] == 0) { DPRINTLN(DBG_WARN, F("Frame ") + String(i + 1) + F(" missing: Request Retransmit")); - mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true); + mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true, true); break; // only request retransmit one frame per loop } yield(); @@ -208,6 +210,14 @@ class Payload : public Handler { } } } + } else if(!crcPass && pyldComplete) { // crc error on complete Payload + if (mPayload[iv->id].retransmits < mMaxRetrans) { + mPayload[iv->id].retransmits++; + DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); + mPayload[iv->id].txCmd = iv->getQueuedCmd(); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX)); + mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); + } } else { // payload complete DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); @@ -269,12 +279,21 @@ class Payload : public Handler { } private: - bool build(uint8_t id) { + bool build(uint8_t id, bool *complete) { DPRINTLN(DBG_VERBOSE, F("build")); uint16_t crc = 0xffff, crcRcv = 0x0000; if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + // check if all fragments are there + *complete = true; + for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { + if(mPayload[id].len[i] == 0) + *complete = false; + } + if(!*complete) + return false; + for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { if (mPayload[id].len[i] > 0) { if (i == (mPayload[id].maxPackId - 1)) { diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 90e26b76..bc3ecc7a 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -45,7 +45,6 @@ class PubMqtt { mVersion = version; mSys = sys; mUtcTimestamp = utcTs; - mExeOnce = true; mIntervalTimeout = 1; snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic); @@ -243,12 +242,9 @@ class PubMqtt { void onConnect(bool sessionPreset) { DPRINTLN(DBG_INFO, F("MQTT connected")); - if(mExeOnce) { - publish("version", mVersion, true); - publish("device", mDevName, true); - publish("ip_addr", WiFi.localIP().toString().c_str(), true); - mExeOnce = false; - } + publish("version", mVersion, true); + publish("device", mDevName, true); + publish("ip_addr", WiFi.localIP().toString().c_str(), true); tickerMinute(); publish(mLwtTopic, mLwtOnline, true, false); @@ -381,7 +377,7 @@ class PubMqtt { // inverter status uint8_t status = MQTT_STATUS_AVAIL_PROD; - if ((!iv->isAvailable(*mUtcTimestamp, rec)) || (!iv->config->enabled)) { + if ((!iv->isAvailable(*mUtcTimestamp)) || (!iv->config->enabled)) { status = MQTT_STATUS_NOT_AVAIL_NOT_PROD; if(iv->config->enabled) { // only change all-avail if inverter is enabled! totalComplete = false; @@ -390,7 +386,7 @@ class PubMqtt { } else { mIvAvail = true; - if (!iv->isProducing(*mUtcTimestamp, rec)) { + if (!iv->isProducing(*mUtcTimestamp)) { if (MQTT_STATUS_AVAIL_PROD == status) status = MQTT_STATUS_AVAIL_NOT_PROD; } @@ -566,7 +562,6 @@ class PubMqtt { subscriptionCb mSubscriptionCb; bool mIvAvail; // shows if at least one inverter is available uint8_t mLastIvState[MAX_NUM_INVERTERS]; - bool mExeOnce; uint16_t mIntervalTimeout; // last will topic and payload must be available trough lifetime of 'espMqttClient' diff --git a/src/publisher/pubSerial.h b/src/publisher/pubSerial.h index d1cc55aa..522a227d 100644 --- a/src/publisher/pubSerial.h +++ b/src/publisher/pubSerial.h @@ -28,8 +28,8 @@ class PubSerial { Inverter<> *iv = mSys->getInverterByPos(id); if (NULL != iv) { record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - if (iv->isAvailable(*mUtcTimestamp, rec)) { - DPRINTLN(DBG_INFO, F("Inverter: ") + String(id)); + if (iv->isAvailable(*mUtcTimestamp)) { + DPRINTLN(DBG_INFO, "Iv: " + String(id)); for (uint8_t i = 0; i < rec->length; i++) { if (0.0f != iv->getValue(i, rec)) { snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec)); diff --git a/src/utils/dbg.h b/src/utils/dbg.h index 17b334c9..7c956ef6 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -5,7 +5,7 @@ #ifndef __DBG_H__ #define __DBG_H__ -#if defined(ESP32) && defined(F) +#if defined(F) //defined(ESP32) && #undef F #define F(sl) (sl) #endif diff --git a/src/utils/scheduler.h b/src/utils/scheduler.h index bdd69038..280f4a66 100644 --- a/src/utils/scheduler.h +++ b/src/utils/scheduler.h @@ -20,8 +20,9 @@ namespace ah { uint32_t timeout; uint32_t reload; bool isTimestamp; - sP() : c(NULL), timeout(0), reload(0), isTimestamp(false) {} - sP(scdCb a, uint32_t tmt, uint32_t rl, bool its) : c(a), timeout(tmt), reload(rl), isTimestamp(its) {} + char name[6]; + sP() : c(NULL), timeout(0), reload(0), isTimestamp(false), name("\n") {} + sP(scdCb a, uint32_t tmt, uint32_t rl, bool its) : c(a), timeout(tmt), reload(rl), isTimestamp(its), name("\n") {} }; #define MAX_NUM_TICKER 30 @@ -64,15 +65,15 @@ namespace ah { } - void once(scdCb c, uint32_t timeout) { addTicker(c, timeout, 0, false); } - void onceAt(scdCb c, uint32_t timestamp) { addTicker(c, timestamp, 0, true); } - uint8_t every(scdCb c, uint32_t interval){ return addTicker(c, interval, interval, false); } + void once(scdCb c, uint32_t timeout, const char *name) { addTicker(c, timeout, 0, false, name); } + void onceAt(scdCb c, uint32_t timestamp, const char *name) { addTicker(c, timestamp, 0, true, name); } + uint8_t every(scdCb c, uint32_t interval, const char *name){ return addTicker(c, interval, interval, false, name); } - void everySec(scdCb c) { every(c, SCD_SEC); } - void everyMin(scdCb c) { every(c, SCD_MIN); } - void everyHour(scdCb c) { every(c, SCD_HOUR); } - void every12h(scdCb c) { every(c, SCD_12H); } - void everyDay(scdCb c) { every(c, SCD_DAY); } + void everySec(scdCb c, const char *name) { every(c, SCD_SEC, name); } + void everyMin(scdCb c, const char *name) { every(c, SCD_MIN, name); } + void everyHour(scdCb c, const char *name) { every(c, SCD_HOUR, name); } + void every12h(scdCb c, const char *name) { every(c, SCD_12H, name); } + void everyDay(scdCb c, const char *name) { every(c, SCD_DAY, name); } virtual void setTimestamp(uint32_t ts) { mTimestamp = ts; @@ -102,11 +103,19 @@ namespace ah { *max = mMax; } + void printSchedulers() { + for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) { + if (mTickerInUse[i]) { + DPRINTLN(DBG_INFO, String(mTicker[i].name) + ", tmt: " + String(mTicker[i].timeout) + ", rel: " + String(mTicker[i].reload)); + } + } + } + protected: uint32_t mTimestamp; private: - inline uint8_t addTicker(scdCb c, uint32_t timeout, uint32_t reload, bool isTimestamp) { + inline uint8_t addTicker(scdCb c, uint32_t timeout, uint32_t reload, bool isTimestamp, const char *name) { for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) { if (!mTickerInUse[i]) { mTickerInUse[i] = true; @@ -114,6 +123,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); if(mMax == i) mMax = i + 1; return i; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 7bf404db..5461746d 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -14,6 +14,11 @@ #include "../appInterface.h" +#if defined(F) //defined(ESP32) && + #undef F + #define F(sl) (sl) +#endif + template class RestApi { public: @@ -265,6 +270,7 @@ class RestApi { obj[F("rx_fail_answer")] = stat->rxFailNoAnser; obj[F("frame_cnt")] = stat->frmCnt; obj[F("tx_cnt")] = mSys->Radio.mSendCnt; + obj[F("retransmits")] = mSys->Radio.mRetransmits; } void getInverterList(JsonObject obj) { @@ -413,8 +419,8 @@ class RestApi { invObj[F("id")] = i; invObj[F("name")] = String(iv->config->name); invObj[F("version")] = String(iv->getFwVersion()); - invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp(), rec); - invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp(), rec); + invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp()); + invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp()); invObj[F("ts_last_success")] = iv->getLastTs(rec); } } @@ -546,13 +552,10 @@ class RestApi { return false; } - if(F("power") == jsonIn[F("cmd")]) { - iv->devControlCmd = (jsonIn[F("val")] == 1) ? TurnOn : TurnOff; - accepted = iv->setDevControlRequest(); - } else if(F("restart") == jsonIn[F("restart")]) { - iv->devControlCmd = Restart; - accepted = iv->setDevControlRequest(); - } + if(F("power") == jsonIn[F("cmd")]) + accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff); + else if(F("restart") == jsonIn[F("restart")]) + accepted = iv->setDevControlRequest(Restart); else if(0 == strncmp("limit_", jsonIn[F("cmd")].as(), 6)) { iv->powerLimit[0] = jsonIn["val"]; if(F("limit_persistent_relative") == jsonIn[F("cmd")]) @@ -563,10 +566,8 @@ class RestApi { iv->powerLimit[1] = RelativNonPersistent; else if(F("limit_nonpersistent_absolute") == jsonIn[F("cmd")]) iv->powerLimit[1] = AbsolutNonPersistent; - iv->devControlCmd = ActivePowerContr; - accepted = iv->setDevControlRequest(); - if(accepted) - mApp->ivSendHighPrio(iv); + + accepted = iv->setDevControlRequest(ActivePowerContr); } else if(F("dev") == jsonIn[F("cmd")]) { DPRINTLN(DBG_INFO, F("dev cmd")); @@ -580,7 +581,8 @@ class RestApi { if(!accepted) { jsonOut[F("error")] = F("inverter does not accept dev control request at this moment"); return false; - } + } else + mApp->ivSendHighPrio(iv); return true; } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index aad46232..1f9f81ea 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -30,14 +30,6 @@
- ERASE SETTINGS (not WiFi) -
- Upload JSON Settings -
- - -
-
Device Host Name @@ -196,7 +188,15 @@
- Download your settings (JSON file) (only saved values, passwords will be removed!) + ERASE SETTINGS (not WiFi) +
+ Upload / Store JSON Settings + + + + +
+ Download settings (JSON file) (only saved values, passwords will be removed!)
diff --git a/src/web/html/system.html b/src/web/html/system.html index 5419d7ba..75e05765 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -94,11 +94,12 @@ } main.append( + genTabRow("TX count", stat["tx_cnt"]), genTabRow("RX success", stat["rx_success"]), genTabRow("RX fail", stat["rx_fail"]), genTabRow("RX no answer", stat["rx_fail_answer"]), - genTabRow("RX frames received", stat["frame_cnt"]), - genTabRow("TX count", stat["tx_cnt"]) + genTabRow("RX fragments", stat["frame_cnt"]), + genTabRow("TX retransmits", stat["retransmits"]) ); } diff --git a/src/web/web.h b/src/web/web.h index 0756e009..e80ff76f 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -86,6 +86,7 @@ class Web { mWeb.on("/upload", HTTP_POST, std::bind(&Web::onUpload, this, std::placeholders::_1), std::bind(&Web::onUpload2, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)); mWeb.on("/serial", HTTP_GET, std::bind(&Web::onSerial, this, std::placeholders::_1)); + mWeb.on("/debug", HTTP_GET, std::bind(&Web::onDebug, this, std::placeholders::_1)); mEvts.onConnect(std::bind(&Web::onConnect, this, std::placeholders::_1)); @@ -189,12 +190,15 @@ class Web { msg.replace("\r\n", ""); if(mSerialAddTime) { if((9 + mSerialBufFill) <= WEB_SERIAL_BUF_SIZE) { - strncpy(&mSerialBuf[mSerialBufFill], mApp->getTimeStr(mApp->getTimezoneOffset()).c_str(), 9); - mSerialBufFill += 9; + if(mApp->getTimestamp() > 0) { + strncpy(&mSerialBuf[mSerialBufFill], mApp->getTimeStr(mApp->getTimezoneOffset()).c_str(), 9); + mSerialBufFill += 9; + } } else { mSerialBufFill = 0; - mEvts.send("webSerial, buffer overflow!", "serial", millis()); + mEvts.send("webSerial, buffer overflow!", "serial", millis()); + return; } mSerialAddTime = false; } @@ -209,7 +213,7 @@ class Web { } else { mSerialBufFill = 0; - mEvts.send("webSerial, buffer overflow!", "serial", millis()); + mEvts.send("webSerial, buffer overflow!", "serial", millis()); } } @@ -649,6 +653,12 @@ class Web { request->send(200, "text/json", "{success:true}"); }*/ + void onDebug(AsyncWebServerRequest *request) { + mApp->getSchedulerNames(); + AsyncWebServerResponse *response = request->beginResponse(200, F("text/html"), "ok"); + request->send(response); + } + void onSerial(AsyncWebServerRequest *request) { DPRINTLN(DBG_VERBOSE, F("onSerial")); diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index a743ddf5..c4fba044 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -11,7 +11,7 @@ // NTP CONFIG #define NTP_PACKET_SIZE 48 - +#define NTP_RETRIES 5 //----------------------------------------------------------------------------- ahoywifi::ahoywifi() : mApIp(192, 168, 4, 1) {} @@ -26,6 +26,7 @@ void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb) { mStaConn = DISCONNECTED; mCnt = 0; mScanActive = false; + mRetries = NTP_RETRIES; #if defined(ESP8266) wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1)); @@ -148,7 +149,17 @@ void ahoywifi::setupStation(void) { //----------------------------------------------------------------------------- -bool ahoywifi::getNtpTime(void) { +bool ahoywifi::getNtpTime(uint32_t *nxtTrig) { + if(0 != mRetries) { + DPRINTLN(DBG_INFO, "try to getNtpTime"); + *nxtTrig = 43200; // check again in 12h (if NTP was successful) + mRetries--; + } else if(0 != *mUtcTimestamp) { // time is availabe, but NTP not + *nxtTrig = 5; // check again 5s + mRetries = NTP_RETRIES; + return true; // true is necessary to enable all timers even if NTP was not reachable + } + if(GOT_IP != mStaConn) return false; @@ -267,6 +278,7 @@ void ahoywifi::connectionEvent(WiFiStatus_t status) { setupWifi(); // reconnect with AP / Station setup mAppWifiCb(false); DPRINTLN(DBG_INFO, "[WiFi] Connection Lost"); + mRetries = NTP_RETRIES; } break; diff --git a/src/wifi/ahoywifi.h b/src/wifi/ahoywifi.h index d8b503e4..72a80d7b 100644 --- a/src/wifi/ahoywifi.h +++ b/src/wifi/ahoywifi.h @@ -25,7 +25,7 @@ class ahoywifi { void setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb); void tickWifiLoop(void); - bool getNtpTime(void); + bool getNtpTime(uint32_t *nxtTrig); void scanAvailNetworks(void); void getAvailNetworks(JsonObject obj); @@ -68,6 +68,7 @@ class ahoywifi { uint8_t mLoopCnt; bool mScanActive; + uint8_t mRetries; }; #endif /*__AHOYWIFI_H__*/