Browse Source

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)
pull/635/head
lumapu 2 years ago
parent
commit
3adcb68d98
  1. 10
      src/CHANGES.md
  2. 45
      src/app.cpp
  3. 14
      src/app.h
  4. 1
      src/appInterface.h
  5. 5
      src/config/settings.h
  6. 2
      src/defines.h
  7. 29
      src/hm/hmInverter.h
  8. 23
      src/hm/hmRadio.h
  9. 33
      src/hm/payload.h
  10. 15
      src/publisher/pubMqtt.h
  11. 4
      src/publisher/pubSerial.h
  12. 2
      src/utils/dbg.h
  13. 33
      src/utils/scheduler.h
  14. 30
      src/web/RestApi.h
  15. 18
      src/web/html/setup.html
  16. 5
      src/web/html/system.html
  17. 18
      src/web/web.h
  18. 16
      src/wifi/ahoywifi.cpp
  19. 3
      src/wifi/ahoywifi.h

10
src/CHANGES.md

@ -2,6 +2,16 @@
(starting from release version `0.5.66`) (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 ## 0.5.73
* improved payload handling (request / retransmit) #464 * improved payload handling (request / retransmit) #464
* included alarm ID parse to serial console (in development) * included alarm ID parse to serial console (in development)

45
src/app.cpp

@ -3,11 +3,6 @@
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ // 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 "app.h"
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include "utils/sun.h" #include "utils/sun.h"
@ -43,7 +38,7 @@ void app::setup() {
mWifi.setup(mConfig, &mTimestamp, std::bind(&app::onWifi, this, std::placeholders::_1)); mWifi.setup(mConfig, &mTimestamp, std::bind(&app::onWifi, this, std::placeholders::_1));
#if !defined(AP_ONLY) #if !defined(AP_ONLY)
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi)); everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
#endif #endif
mSys->addInverters(&mConfig->inst); mSys->addInverters(&mConfig->inst);
@ -136,48 +131,49 @@ void app::onWifi(bool gotIp) {
regularTickers(); // reinstall regular tickers regularTickers(); // reinstall regular tickers
if (gotIp) { if (gotIp) {
mInnerLoopCb = std::bind(&app::loopStandard, this); 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; mMqttReconnect = true;
once(std::bind(&app::tickNtpUpdate, this), 2); once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2");
} }
else { else {
mInnerLoopCb = std::bind(&app::loopWifi, this); mInnerLoopCb = std::bind(&app::loopWifi, this);
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi)); everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::regularTickers(void) { void app::regularTickers(void) {
DPRINTLN(DBG_DEBUG, F("regularTickers")); DPRINTLN(DBG_DEBUG, F("regularTickers"));
everySec(std::bind(&WebType::tickSecond, &mWeb)); everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc");
// Plugins // Plugins
#if defined(ENA_NOKIA) || defined(ENA_SSD1306) || defined(ENA_SH1106) #if defined(ENA_NOKIA) || defined(ENA_SSD1306) || defined(ENA_SH1106)
everySec(std::bind(&MonoDisplayType::tickerSecond, &mMonoDisplay)); everySec(std::bind(&MonoDisplayType::tickerSecond, &mMonoDisplay));
#endif #endif
every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval); every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart");
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::tickNtpUpdate(void) { void app::tickNtpUpdate(void) {
uint32_t nxtTrig = 5; // default: check again in 5 sec uint32_t nxtTrig = 5; // default: check again in 5 sec
if (mWifi.getNtpTime()) { if (mWifi.getNtpTime(&nxtTrig)) {
if (mMqttReconnect && mMqttEnabled) { if (mMqttReconnect && mMqttEnabled) {
mMqtt.connect(); mMqtt.connect();
everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt)); everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS");
everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt)); everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM");
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight
if(mConfig->mqtt.rstYieldMidNight) if(mConfig->mqtt.rstYieldMidNight)
onceAt(std::bind(&app::tickMidnight, this), nxtTrig); onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "midNi");
mMqttReconnect = false; mMqttReconnect = false;
} }
nxtTrig = 43200; // check again in 12 h nxtTrig = 43200;
if((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) { 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; mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
tickCalcSunrise(); 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(); 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 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) if (mMqttEnabled)
tickSun(); tickSun();
} }
@ -212,7 +208,7 @@ void app::tickIVCommunication(void) {
} }
} }
if (nxtTrig != 0) if (nxtTrig != 0)
onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig); onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom");
} }
if (mMqttEnabled) if (mMqttEnabled)
tickComm(); tickComm();
@ -222,14 +218,14 @@ void app::tickIVCommunication(void) {
void app::tickSun(void) { void app::tickSun(void) {
// only used and enabled by MQTT (see setup()) // only used and enabled by MQTT (see setup())
if (!mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec, mConfig->sun.disNightCom)) 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) { void app::tickComm(void) {
// only used and enabled by MQTT (see setup()) // only used and enabled by MQTT (see setup())
if (!mMqtt.tickerComm(!mIVCommunicationOn)) 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) { void app::tickMidnight(void) {
// only used and enabled by MQTT (see setup()) // only used and enabled by MQTT (see setup())
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight 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(); mMqtt.tickerMidnight();
} }
@ -285,8 +281,6 @@ void app::resetSystem(void) {
#ifdef AP_ONLY #ifdef AP_ONLY
mTimestamp = 1; mTimestamp = 1;
#else
mTimestamp = 0;
#endif #endif
mSunrise = 0; mSunrise = 0;
@ -329,8 +323,7 @@ void app::updateLed(void) {
if(mConfig->led.led0 != 0xff) { if(mConfig->led.led0 != 0xff) {
Inverter<> *iv = mSys->getInverterByPos(0); Inverter<> *iv = mSys->getInverterByPos(0);
if (NULL != iv) { if (NULL != iv) {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); if(iv->isProducing(mTimestamp))
if(iv->isProducing(mTimestamp, rec))
digitalWrite(mConfig->led.led0, LOW); // LED on digitalWrite(mConfig->led.led0, LOW); // LED on
else else
digitalWrite(mConfig->led.led0, HIGH); // LED off digitalWrite(mConfig->led.led0, HIGH); // LED off

14
src/app.h

@ -102,7 +102,7 @@ class app : public IApp, public ah::Scheduler {
} }
void setRebootFlag() { void setRebootFlag() {
once(std::bind(&app::tickReboot, this), 3); once(std::bind(&app::tickReboot, this), 3, "rboot");
} }
const char *getVersion() { const char *getVersion() {
@ -126,7 +126,7 @@ class app : public IApp, public ah::Scheduler {
} }
void setMqttDiscoveryFlag() { void setMqttDiscoveryFlag() {
once(std::bind(&PubMqttType::sendDiscoveryConfig, &mMqtt), 1); once(std::bind(&PubMqttType::sendDiscoveryConfig, &mMqtt), 1, "disCf");
} }
void setMqttPowerLimitAck(Inverter<> *iv) { void setMqttPowerLimitAck(Inverter<> *iv) {
@ -174,10 +174,16 @@ class app : public IApp, public ah::Scheduler {
getStat(max); getStat(max);
} }
void getSchedulerNames(void) {
printSchedulers();
}
void setTimestamp(uint32_t newTime) { void setTimestamp(uint32_t newTime) {
DPRINTLN(DBG_DEBUG, F("setTimestamp: ") + String(newTime)); DPRINTLN(DBG_DEBUG, F("setTimestamp: ") + String(newTime));
if(0 == newTime) if(0 == newTime) {
mWifi.getNtpTime(); uint32_t tmp;
mWifi.getNtpTime(&tmp);
}
else else
Scheduler::setTimestamp(newTime); Scheduler::setTimestamp(newTime);
} }

1
src/appInterface.h

@ -31,6 +31,7 @@ class IApp {
virtual String getTimeStr(uint32_t offset) = 0; virtual String getTimeStr(uint32_t offset) = 0;
virtual uint32_t getTimezoneOffset() = 0; virtual uint32_t getTimezoneOffset() = 0;
virtual void getSchedulerInfo(uint8_t *max) = 0; virtual void getSchedulerInfo(uint8_t *max) = 0;
virtual void getSchedulerNames() = 0;
virtual bool getRebootRequestState() = 0; virtual bool getRebootRequestState() = 0;
virtual bool getSettingsValid() = 0; virtual bool getSettingsValid() = 0;

5
src/config/settings.h

@ -162,10 +162,11 @@ class settings {
if(!LittleFS.begin(LITTLFS_FALSE)) { if(!LittleFS.begin(LITTLFS_FALSE)) {
DPRINTLN(DBG_INFO, F(".. format ..")); DPRINTLN(DBG_INFO, F(".. format .."));
LittleFS.format(); LittleFS.format();
if(LittleFS.begin(LITTLFS_TRUE)) if(LittleFS.begin(LITTLFS_TRUE)) {
DPRINTLN(DBG_INFO, F(".. success")); DPRINTLN(DBG_INFO, F(".. success"));
else } else {
DPRINTLN(DBG_INFO, F(".. failed")); DPRINTLN(DBG_INFO, F(".. failed"));
}
} }
else else

2
src/defines.h

@ -13,7 +13,7 @@
//------------------------------------- //-------------------------------------
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 5 #define VERSION_MINOR 5
#define VERSION_PATCH 73 #define VERSION_PATCH 74
//------------------------------------- //-------------------------------------
typedef struct { typedef struct {

29
src/hm/hmInverter.h

@ -164,7 +164,7 @@ class Inverter {
if (getFwVersion() == 0) if (getFwVersion() == 0)
enqueCommand<InfoCommand>(InverterDevInform_All); // firmware version enqueCommand<InfoCommand>(InverterDevInform_All); // firmware version
enqueCommand<InfoCommand>(RealTimeRunData_Debug); // live data enqueCommand<InfoCommand>(RealTimeRunData_Debug); // live data
if (actPowerLimit == 0xffff) if ((actPowerLimit == 0xffff) && isConnected)
enqueCommand<InfoCommand>(SystemConfigPara); // power limit info enqueCommand<InfoCommand>(SystemConfigPara); // power limit info
} }
return _commandQueue.front().get()->getCmd(); return _commandQueue.front().get()->getCmd();
@ -220,9 +220,11 @@ class Inverter {
return 0; return 0;
} }
bool setDevControlRequest() { bool setDevControlRequest(uint8_t cmd) {
if(isConnected) if(isConnected) {
mDevControlRequest = true; mDevControlRequest = true;
devControlCmd = cmd;
}
return isConnected; return isConnected;
} }
@ -333,16 +335,23 @@ class Inverter {
} }
} }
bool isAvailable(uint32_t timestamp, record_t<> *rec) { bool isAvailable(uint32_t timestamp) {
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isAvailable")); if((timestamp - recordMeas.ts) < INACT_THRES_SEC)
return ((timestamp - rec->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")); DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isProducing"));
if(isAvailable(timestamp, rec)) { if(isAvailable(timestamp)) {
uint8_t pos = getPosByChFld(CH0, FLD_PAC, rec); uint8_t pos = getPosByChFld(CH0, FLD_PAC, &recordMeas);
return (getValue(pos, rec) > INACT_PWR_THRESH); return (getValue(pos, &recordMeas) > INACT_PWR_THRESH);
} }
return false; return false;
} }

23
src/hm/hmRadio.h

@ -89,6 +89,7 @@ class HmRadio {
mRxLoopCnt = RF_LOOP_CNT; mRxLoopCnt = RF_LOOP_CNT;
mSendCnt = 0; mSendCnt = 0;
mRetransmits = 0;
mSerialDebug = false; mSerialDebug = false;
mIrqRcvd = false; mIrqRcvd = false;
@ -194,7 +195,7 @@ class HmRadio {
return mRfChLst[mTxChIdx]; 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)); DPRINTLN(DBG_INFO, F("sendControlPacket cmd: 0x") + String(cmd, HEX));
sendCmdPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME, false); sendCmdPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME, false);
uint8_t cnt = 0; uint8_t cnt = 0;
@ -215,12 +216,12 @@ class HmRadio {
// crc over all // crc over all
mTxBuf[10 + cnt] = ah::crc8(mTxBuf, 10 + cnt); 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)); 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[10] = cmd; // cid
mTxBuf[11] = 0x00; mTxBuf[11] = 0x00;
CP_U32_LittleEndian(&mTxBuf[12], ts); CP_U32_LittleEndian(&mTxBuf[12], ts);
@ -233,10 +234,10 @@ class HmRadio {
mTxBuf[25] = (crc ) & 0xff; mTxBuf[25] = (crc ) & 0xff;
mTxBuf[26] = ah::crc8(mTxBuf, 26); 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)); DPRINTLN(DBG_VERBOSE, F("sendCmdPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX));
memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE);
mTxBuf[0] = mid; // message id mTxBuf[0] = mid; // message id
@ -245,7 +246,7 @@ class HmRadio {
mTxBuf[9] = pid; mTxBuf[9] = pid;
if(calcCrc) { if(calcCrc) {
mTxBuf[10] = ah::crc8(mTxBuf, 10); 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 mSendCnt;
uint32_t mRetransmits;
bool mSerialDebug; bool mSerialDebug;
private: 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, F("hmRadio.h:sendPacket"));
//DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt)); //DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt));
//dumpBuf("SEN ", buf, len); //dumpBuf("SEN ", buf, len);
@ -347,7 +349,10 @@ class HmRadio {
mNrf24.startListening(); mNrf24.startListening();
RESTORE_IRQ; RESTORE_IRQ;
mSendCnt++; if(isRetransmit)
mRetransmits++;
else
mSendCnt++;
} }
uint8_t getTxNxtChannel(void) { uint8_t getTxNxtChannel(void) {

33
src/hm/payload.h

@ -103,14 +103,14 @@ class Payload : public Handler<payloadListenerType> {
if (iv->getDevControlRequest()) { if (iv->getDevControlRequest()) {
if (mSerialDebug) if (mSerialDebug)
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request 0x") + String(iv->devControlCmd, HEX) + F(" power limit ") + String(iv->powerLimit[0])); 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; mPayload[iv->id].txCmd = iv->devControlCmd;
//iv->clearCmdQueue(); //iv->clearCmdQueue();
//iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit //iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
} else { } else {
uint8_t cmd = iv->getQueuedCmd(); uint8_t cmd = iv->getQueuedCmd();
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); // + String(cmd, HEX)); 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; mPayload[iv->id].txCmd = cmd;
} }
} }
@ -177,7 +177,9 @@ class Payload : public Handler<payloadListenerType> {
} }
if (!mPayload[iv->id].complete) { 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 ((mPayload[iv->id].requested) && (retransmit)) {
if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) {
// This is required to prevent retransmissions without answer. // This is required to prevent retransmissions without answer.
@ -185,7 +187,7 @@ class Payload : public Handler<payloadListenerType> {
mPayload[iv->id].retransmits = mMaxRetrans; mPayload[iv->id].retransmits = mMaxRetrans;
} else if(iv->devControlCmd == ActivePowerContr) { } else if(iv->devControlCmd == ActivePowerContr) {
DPRINTLN(DBG_INFO, F("retransmit power limit")); 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 { } else {
if (mPayload[iv->id].retransmits < mMaxRetrans) { if (mPayload[iv->id].retransmits < mMaxRetrans) {
mPayload[iv->id].retransmits++; mPayload[iv->id].retransmits++;
@ -193,12 +195,12 @@ class Payload : public Handler<payloadListenerType> {
DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit")); DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit"));
mPayload[iv->id].txCmd = iv->getQueuedCmd(); mPayload[iv->id].txCmd = iv->getQueuedCmd();
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX)); 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 { } else {
for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) {
if (mPayload[iv->id].len[i] == 0) { if (mPayload[iv->id].len[i] == 0) {
DPRINTLN(DBG_WARN, F("Frame ") + String(i + 1) + F(" missing: Request Retransmit")); 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 break; // only request retransmit one frame per loop
} }
yield(); yield();
@ -208,6 +210,14 @@ class Payload : public Handler<payloadListenerType> {
} }
} }
} }
} 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 } else { // payload complete
DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); 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)); DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX));
@ -269,12 +279,21 @@ class Payload : public Handler<payloadListenerType> {
} }
private: private:
bool build(uint8_t id) { bool build(uint8_t id, bool *complete) {
DPRINTLN(DBG_VERBOSE, F("build")); DPRINTLN(DBG_VERBOSE, F("build"));
uint16_t crc = 0xffff, crcRcv = 0x0000; uint16_t crc = 0xffff, crcRcv = 0x0000;
if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES)
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++) { for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) {
if (mPayload[id].len[i] > 0) { if (mPayload[id].len[i] > 0) {
if (i == (mPayload[id].maxPackId - 1)) { if (i == (mPayload[id].maxPackId - 1)) {

15
src/publisher/pubMqtt.h

@ -45,7 +45,6 @@ class PubMqtt {
mVersion = version; mVersion = version;
mSys = sys; mSys = sys;
mUtcTimestamp = utcTs; mUtcTimestamp = utcTs;
mExeOnce = true;
mIntervalTimeout = 1; mIntervalTimeout = 1;
snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic); snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic);
@ -243,12 +242,9 @@ class PubMqtt {
void onConnect(bool sessionPreset) { void onConnect(bool sessionPreset) {
DPRINTLN(DBG_INFO, F("MQTT connected")); DPRINTLN(DBG_INFO, F("MQTT connected"));
if(mExeOnce) { publish("version", mVersion, true);
publish("version", mVersion, true); publish("device", mDevName, true);
publish("device", mDevName, true); publish("ip_addr", WiFi.localIP().toString().c_str(), true);
publish("ip_addr", WiFi.localIP().toString().c_str(), true);
mExeOnce = false;
}
tickerMinute(); tickerMinute();
publish(mLwtTopic, mLwtOnline, true, false); publish(mLwtTopic, mLwtOnline, true, false);
@ -381,7 +377,7 @@ class PubMqtt {
// inverter status // inverter status
uint8_t status = MQTT_STATUS_AVAIL_PROD; 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; status = MQTT_STATUS_NOT_AVAIL_NOT_PROD;
if(iv->config->enabled) { // only change all-avail if inverter is enabled! if(iv->config->enabled) { // only change all-avail if inverter is enabled!
totalComplete = false; totalComplete = false;
@ -390,7 +386,7 @@ class PubMqtt {
} }
else { else {
mIvAvail = true; mIvAvail = true;
if (!iv->isProducing(*mUtcTimestamp, rec)) { if (!iv->isProducing(*mUtcTimestamp)) {
if (MQTT_STATUS_AVAIL_PROD == status) if (MQTT_STATUS_AVAIL_PROD == status)
status = MQTT_STATUS_AVAIL_NOT_PROD; status = MQTT_STATUS_AVAIL_NOT_PROD;
} }
@ -566,7 +562,6 @@ class PubMqtt {
subscriptionCb mSubscriptionCb; subscriptionCb mSubscriptionCb;
bool mIvAvail; // shows if at least one inverter is available bool mIvAvail; // shows if at least one inverter is available
uint8_t mLastIvState[MAX_NUM_INVERTERS]; uint8_t mLastIvState[MAX_NUM_INVERTERS];
bool mExeOnce;
uint16_t mIntervalTimeout; uint16_t mIntervalTimeout;
// last will topic and payload must be available trough lifetime of 'espMqttClient' // last will topic and payload must be available trough lifetime of 'espMqttClient'

4
src/publisher/pubSerial.h

@ -28,8 +28,8 @@ class PubSerial {
Inverter<> *iv = mSys->getInverterByPos(id); Inverter<> *iv = mSys->getInverterByPos(id);
if (NULL != iv) { if (NULL != iv) {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
if (iv->isAvailable(*mUtcTimestamp, rec)) { if (iv->isAvailable(*mUtcTimestamp)) {
DPRINTLN(DBG_INFO, F("Inverter: ") + String(id)); DPRINTLN(DBG_INFO, "Iv: " + String(id));
for (uint8_t i = 0; i < rec->length; i++) { for (uint8_t i = 0; i < rec->length; i++) {
if (0.0f != iv->getValue(i, rec)) { 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)); snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));

2
src/utils/dbg.h

@ -5,7 +5,7 @@
#ifndef __DBG_H__ #ifndef __DBG_H__
#define __DBG_H__ #define __DBG_H__
#if defined(ESP32) && defined(F) #if defined(F) //defined(ESP32) &&
#undef F #undef F
#define F(sl) (sl) #define F(sl) (sl)
#endif #endif

33
src/utils/scheduler.h

@ -20,8 +20,9 @@ namespace ah {
uint32_t timeout; uint32_t timeout;
uint32_t reload; uint32_t reload;
bool isTimestamp; bool isTimestamp;
sP() : c(NULL), timeout(0), reload(0), isTimestamp(false) {} char name[6];
sP(scdCb a, uint32_t tmt, uint32_t rl, bool its) : c(a), timeout(tmt), reload(rl), isTimestamp(its) {} 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 #define MAX_NUM_TICKER 30
@ -64,15 +65,15 @@ namespace ah {
} }
void once(scdCb c, uint32_t timeout) { addTicker(c, timeout, 0, false); } void once(scdCb c, uint32_t timeout, const char *name) { addTicker(c, timeout, 0, false, name); }
void onceAt(scdCb c, uint32_t timestamp) { addTicker(c, timestamp, 0, true); } void onceAt(scdCb c, uint32_t timestamp, const char *name) { addTicker(c, timestamp, 0, true, name); }
uint8_t every(scdCb c, uint32_t interval){ return addTicker(c, interval, interval, false); } 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 everySec(scdCb c, const char *name) { every(c, SCD_SEC, name); }
void everyMin(scdCb c) { every(c, SCD_MIN); } void everyMin(scdCb c, const char *name) { every(c, SCD_MIN, name); }
void everyHour(scdCb c) { every(c, SCD_HOUR); } void everyHour(scdCb c, const char *name) { every(c, SCD_HOUR, name); }
void every12h(scdCb c) { every(c, SCD_12H); } void every12h(scdCb c, const char *name) { every(c, SCD_12H, name); }
void everyDay(scdCb c) { every(c, SCD_DAY); } void everyDay(scdCb c, const char *name) { every(c, SCD_DAY, name); }
virtual void setTimestamp(uint32_t ts) { virtual void setTimestamp(uint32_t ts) {
mTimestamp = ts; mTimestamp = ts;
@ -102,11 +103,19 @@ namespace ah {
*max = mMax; *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: protected:
uint32_t mTimestamp; uint32_t mTimestamp;
private: 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++) { for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) {
if (!mTickerInUse[i]) { if (!mTickerInUse[i]) {
mTickerInUse[i] = true; mTickerInUse[i] = true;
@ -114,6 +123,8 @@ namespace ah {
mTicker[i].timeout = timeout; mTicker[i].timeout = timeout;
mTicker[i].reload = reload; mTicker[i].reload = reload;
mTicker[i].isTimestamp = isTimestamp; mTicker[i].isTimestamp = isTimestamp;
memset(mTicker[i].name, 0, 6);
strncpy(mTicker[i].name, name, (strlen(name) < 6) ? strlen(name) : 5);
if(mMax == i) if(mMax == i)
mMax = i + 1; mMax = i + 1;
return i; return i;

30
src/web/RestApi.h

@ -14,6 +14,11 @@
#include "../appInterface.h" #include "../appInterface.h"
#if defined(F) //defined(ESP32) &&
#undef F
#define F(sl) (sl)
#endif
template<class HMSYSTEM> template<class HMSYSTEM>
class RestApi { class RestApi {
public: public:
@ -265,6 +270,7 @@ class RestApi {
obj[F("rx_fail_answer")] = stat->rxFailNoAnser; obj[F("rx_fail_answer")] = stat->rxFailNoAnser;
obj[F("frame_cnt")] = stat->frmCnt; obj[F("frame_cnt")] = stat->frmCnt;
obj[F("tx_cnt")] = mSys->Radio.mSendCnt; obj[F("tx_cnt")] = mSys->Radio.mSendCnt;
obj[F("retransmits")] = mSys->Radio.mRetransmits;
} }
void getInverterList(JsonObject obj) { void getInverterList(JsonObject obj) {
@ -413,8 +419,8 @@ class RestApi {
invObj[F("id")] = i; invObj[F("id")] = i;
invObj[F("name")] = String(iv->config->name); invObj[F("name")] = String(iv->config->name);
invObj[F("version")] = String(iv->getFwVersion()); invObj[F("version")] = String(iv->getFwVersion());
invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp(), rec); invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp());
invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp(), rec); invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp());
invObj[F("ts_last_success")] = iv->getLastTs(rec); invObj[F("ts_last_success")] = iv->getLastTs(rec);
} }
} }
@ -546,13 +552,10 @@ class RestApi {
return false; return false;
} }
if(F("power") == jsonIn[F("cmd")]) { if(F("power") == jsonIn[F("cmd")])
iv->devControlCmd = (jsonIn[F("val")] == 1) ? TurnOn : TurnOff; accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff);
accepted = iv->setDevControlRequest(); else if(F("restart") == jsonIn[F("restart")])
} else if(F("restart") == jsonIn[F("restart")]) { accepted = iv->setDevControlRequest(Restart);
iv->devControlCmd = Restart;
accepted = iv->setDevControlRequest();
}
else if(0 == strncmp("limit_", jsonIn[F("cmd")].as<const char*>(), 6)) { else if(0 == strncmp("limit_", jsonIn[F("cmd")].as<const char*>(), 6)) {
iv->powerLimit[0] = jsonIn["val"]; iv->powerLimit[0] = jsonIn["val"];
if(F("limit_persistent_relative") == jsonIn[F("cmd")]) if(F("limit_persistent_relative") == jsonIn[F("cmd")])
@ -563,10 +566,8 @@ class RestApi {
iv->powerLimit[1] = RelativNonPersistent; iv->powerLimit[1] = RelativNonPersistent;
else if(F("limit_nonpersistent_absolute") == jsonIn[F("cmd")]) else if(F("limit_nonpersistent_absolute") == jsonIn[F("cmd")])
iv->powerLimit[1] = AbsolutNonPersistent; iv->powerLimit[1] = AbsolutNonPersistent;
iv->devControlCmd = ActivePowerContr;
accepted = iv->setDevControlRequest(); accepted = iv->setDevControlRequest(ActivePowerContr);
if(accepted)
mApp->ivSendHighPrio(iv);
} }
else if(F("dev") == jsonIn[F("cmd")]) { else if(F("dev") == jsonIn[F("cmd")]) {
DPRINTLN(DBG_INFO, F("dev cmd")); DPRINTLN(DBG_INFO, F("dev cmd"));
@ -580,7 +581,8 @@ class RestApi {
if(!accepted) { if(!accepted) {
jsonOut[F("error")] = F("inverter does not accept dev control request at this moment"); jsonOut[F("error")] = F("inverter does not accept dev control request at this moment");
return false; return false;
} } else
mApp->ivSendHighPrio(iv);
return true; return true;
} }

18
src/web/html/setup.html

@ -30,14 +30,6 @@
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
<a class="btn" href="/erase">ERASE SETTINGS (not WiFi)</a>
<fieldset>
<legend class="des">Upload JSON Settings</legend>
<form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
<input type="file" name="upload">
<input type="button" class="btn" value="Upload" onclick="hide()">
</form>
</fieldset>
<form method="post" action="/save"> <form method="post" action="/save">
<fieldset> <fieldset>
<legend class="des">Device Host Name</legend> <legend class="des">Device Host Name</legend>
@ -196,7 +188,15 @@
</div> </div>
<div class="hr mb-3 mt-3"></div> <div class="hr mb-3 mt-3"></div>
<div class="mb-4"> <div class="mb-4">
<a href="/get_setup" target="_blank">Download your settings (JSON file)</a> (only saved values, passwords will be removed!) <a class="btn" href="/erase">ERASE SETTINGS (not WiFi)</a>
<fieldset>
<legend class="des">Upload / Store JSON Settings</legend>
<form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
<input type="file" name="upload">
<input type="button" class="btn" value="Upload" onclick="hide()">
</form>
</fieldset>
<a class="btn" href="/get_setup" target="_blank">Download settings (JSON file)</a> (only saved values, passwords will be removed!)
</div> </div>
</form> </form>
</div> </div>

5
src/web/html/system.html

@ -94,11 +94,12 @@
} }
main.append( main.append(
genTabRow("TX count", stat["tx_cnt"]),
genTabRow("RX success", stat["rx_success"]), genTabRow("RX success", stat["rx_success"]),
genTabRow("RX fail", stat["rx_fail"]), genTabRow("RX fail", stat["rx_fail"]),
genTabRow("RX no answer", stat["rx_fail_answer"]), genTabRow("RX no answer", stat["rx_fail_answer"]),
genTabRow("RX frames received", stat["frame_cnt"]), genTabRow("RX fragments", stat["frame_cnt"]),
genTabRow("TX count", stat["tx_cnt"]) genTabRow("TX retransmits", stat["retransmits"])
); );
} }

18
src/web/web.h

@ -86,6 +86,7 @@ class Web {
mWeb.on("/upload", HTTP_POST, std::bind(&Web::onUpload, this, std::placeholders::_1), 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)); 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("/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)); mEvts.onConnect(std::bind(&Web::onConnect, this, std::placeholders::_1));
@ -189,12 +190,15 @@ class Web {
msg.replace("\r\n", "<rn>"); msg.replace("\r\n", "<rn>");
if(mSerialAddTime) { if(mSerialAddTime) {
if((9 + mSerialBufFill) <= WEB_SERIAL_BUF_SIZE) { if((9 + mSerialBufFill) <= WEB_SERIAL_BUF_SIZE) {
strncpy(&mSerialBuf[mSerialBufFill], mApp->getTimeStr(mApp->getTimezoneOffset()).c_str(), 9); if(mApp->getTimestamp() > 0) {
mSerialBufFill += 9; strncpy(&mSerialBuf[mSerialBufFill], mApp->getTimeStr(mApp->getTimezoneOffset()).c_str(), 9);
mSerialBufFill += 9;
}
} }
else { else {
mSerialBufFill = 0; mSerialBufFill = 0;
mEvts.send("webSerial, buffer overflow!", "serial", millis()); mEvts.send("webSerial, buffer overflow!<rn>", "serial", millis());
return;
} }
mSerialAddTime = false; mSerialAddTime = false;
} }
@ -209,7 +213,7 @@ class Web {
} }
else { else {
mSerialBufFill = 0; mSerialBufFill = 0;
mEvts.send("webSerial, buffer overflow!", "serial", millis()); mEvts.send("webSerial, buffer overflow!<rn>", "serial", millis());
} }
} }
@ -649,6 +653,12 @@ class Web {
request->send(200, "text/json", "{success:true}"); 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) { void onSerial(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onSerial")); DPRINTLN(DBG_VERBOSE, F("onSerial"));

16
src/wifi/ahoywifi.cpp

@ -11,7 +11,7 @@
// NTP CONFIG // NTP CONFIG
#define NTP_PACKET_SIZE 48 #define NTP_PACKET_SIZE 48
#define NTP_RETRIES 5
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ahoywifi::ahoywifi() : mApIp(192, 168, 4, 1) {} ahoywifi::ahoywifi() : mApIp(192, 168, 4, 1) {}
@ -26,6 +26,7 @@ void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb) {
mStaConn = DISCONNECTED; mStaConn = DISCONNECTED;
mCnt = 0; mCnt = 0;
mScanActive = false; mScanActive = false;
mRetries = NTP_RETRIES;
#if defined(ESP8266) #if defined(ESP8266)
wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1)); 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) if(GOT_IP != mStaConn)
return false; return false;
@ -267,6 +278,7 @@ void ahoywifi::connectionEvent(WiFiStatus_t status) {
setupWifi(); // reconnect with AP / Station setup setupWifi(); // reconnect with AP / Station setup
mAppWifiCb(false); mAppWifiCb(false);
DPRINTLN(DBG_INFO, "[WiFi] Connection Lost"); DPRINTLN(DBG_INFO, "[WiFi] Connection Lost");
mRetries = NTP_RETRIES;
} }
break; break;

3
src/wifi/ahoywifi.h

@ -25,7 +25,7 @@ class ahoywifi {
void setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb); void setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb);
void tickWifiLoop(void); void tickWifiLoop(void);
bool getNtpTime(void); bool getNtpTime(uint32_t *nxtTrig);
void scanAvailNetworks(void); void scanAvailNetworks(void);
void getAvailNetworks(JsonObject obj); void getAvailNetworks(JsonObject obj);
@ -68,6 +68,7 @@ class ahoywifi {
uint8_t mLoopCnt; uint8_t mLoopCnt;
bool mScanActive; bool mScanActive;
uint8_t mRetries;
}; };
#endif /*__AHOYWIFI_H__*/ #endif /*__AHOYWIFI_H__*/

Loading…
Cancel
Save