From 1bc3a0f06f5a6e3fd5b0ad87c703110751b63afa Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 13 Nov 2023 23:54:55 +0100 Subject: [PATCH] 0.8.7 * fix ESP8266 inverter settings #1226 * send radio statistics via MqTT #1227 * made night communication inverter depended * added option to prevent adding values of inverter to total values (MqTT only) #1199 --- src/CHANGES.md | 6 +++ src/app.cpp | 92 +++++++++++++++++++---------------- src/app.h | 1 - src/config/settings.h | 26 ++++++---- src/defines.h | 2 +- src/hm/hmInverter.h | 2 + src/publisher/pubMqtt.h | 13 ++++- src/publisher/pubMqttDefs.h | 2 - src/publisher/pubMqttIvData.h | 68 ++++++++++++++++---------- src/web/RestApi.h | 80 ++++++++++++++++-------------- src/web/html/setup.html | 90 +++++++++++++++++++--------------- src/web/web.h | 2 - 12 files changed, 223 insertions(+), 161 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index bbe0bbc38..4fb9bf7ee 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,11 @@ # Development Changes +## 0.8.7 - 2023-11-13 +* fix ESP8266 inverter settings #1226 +* send radio statistics via MqTT #1227 +* made night communication inverter depended +* added option to prevent adding values of inverter to total values (MqTT only) #1199 + ## 0.8.6 - 2023-11-12 * merged PR #1225 * improved heuristics (prevent update of statitistic during testing) diff --git a/src/app.cpp b/src/app.cpp index 838c375fd..edd583065 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -4,9 +4,7 @@ //----------------------------------------------------------------------------- #include - #include "app.h" - #include "utils/sun.h" @@ -239,43 +237,50 @@ void app::tickCalcSunrise(void) { //----------------------------------------------------------------------------- void app::tickIVCommunication(void) { - mIVCommunicationOn = !mConfig->sun.disNightCom; // if sun.disNightCom is false, communication is always on - if (!mIVCommunicationOn) { // inverter communication only during the day - uint32_t nxtTrig; - if (mTimestamp < (mSunrise - mConfig->sun.offsetSec)) { // current time is before communication start, set next trigger to communication start - nxtTrig = mSunrise - mConfig->sun.offsetSec; - } else { - if (mTimestamp >= (mSunset + mConfig->sun.offsetSec)) { // current time is past communication stop, nothing to do. Next update will be done at midnight by tickCalcSunrise - nxtTrig = 0; - } else { // current time lies within communication start/stop time, set next trigger to communication stop - mIVCommunicationOn = true; - nxtTrig = mSunset + mConfig->sun.offsetSec; + bool restartTick = false; + bool zeroValues = false; + uint32_t nxtTrig = 0; + + Inverter<> *iv; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { + iv = mSys.getInverterByPos(i); + if(NULL == iv) + continue; + + iv->commEnabled = !iv->config->disNightCom; // if sun.disNightCom is false, communication is always on + if (!iv->commEnabled) { // inverter communication only during the day + if (mTimestamp < (mSunrise - mConfig->sun.offsetSec)) { // current time is before communication start, set next trigger to communication start + nxtTrig = mSunrise - mConfig->sun.offsetSec; + } else { + if (mTimestamp >= (mSunset + mConfig->sun.offsetSec)) { // current time is past communication stop, nothing to do. Next update will be done at midnight by tickCalcSunrise + nxtTrig = 0; + } else { // current time lies within communication start/stop time, set next trigger to communication stop + iv->commEnabled = true; + nxtTrig = mSunset + mConfig->sun.offsetSec; + } } + if (nxtTrig != 0) + restartTick = true; } - if (nxtTrig != 0) - onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); + + if ((!iv->commEnabled) && (mConfig->inst.rstValsCommStop)) + zeroValues = true; } - tickComm(); + + if(restartTick) // at least one inverter + onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); + + if (zeroValues) // at least one inverter + once(std::bind(&app::tickZeroValues, this), mConfig->nrf.sendInterval, "tZero"); } //----------------------------------------------------------------------------- void app::tickSun(void) { // 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)) once(std::bind(&app::tickSun, this), 1, "mqSun"); // MQTT not connected, retry } -//----------------------------------------------------------------------------- -void app::tickComm(void) { - if ((!mIVCommunicationOn) && (mConfig->inst.rstValsCommStop)) - once(std::bind(&app::tickZeroValues, this), mConfig->nrf.sendInterval, "tZero"); - - if (mMqttEnabled) { - if (!mMqtt.tickerComm(!mIVCommunicationOn)) - once(std::bind(&app::tickComm, this), 5, "mqCom"); // MQTT not connected, retry after 5s - } -} - //----------------------------------------------------------------------------- void app::tickZeroValues(void) { zeroIvValues(!CHECK_AVAIL, SKIP_YIELD_DAY); @@ -325,22 +330,24 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { - if(!mIVCommunicationOn) { - DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); - return; - } - for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); - if(NULL != iv) { - if(iv->config->enabled) { - iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { - if(isDevControl) - mCommunication.addImportant(iv, cmd); - else - mCommunication.add(iv, cmd); - }); + if(NULL == iv) + continue; + + if(iv->config->enabled) { + if(!iv->commEnabled) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("no communication to the inverter (night time)")); + continue; } + + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { + if(isDevControl) + mCommunication.addImportant(iv, cmd); + else + mCommunication.add(iv, cmd); + }); } } @@ -358,6 +365,8 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { continue; // skip to next inverter if (!iv->config->enabled) continue; // skip to next inverter + if (iv->commEnabled) + continue; // skip to next inverter if (checkAvail) { if (!iv->isAvailable()) @@ -415,7 +424,6 @@ void app::resetSystem(void) { mSendLastIvId = 0; mShowRebootRequest = false; - mIVCommunicationOn = true; mSavePending = false; mSaveReboot = false; diff --git a/src/app.h b/src/app.h index 0bb1c1706..0098c417d 100644 --- a/src/app.h +++ b/src/app.h @@ -307,7 +307,6 @@ class app : public IApp, public ah::Scheduler { Communication mCommunication; bool mShowRebootRequest; - bool mIVCommunicationOn; #if defined(ETHERNET) ahoyeth mEth; diff --git a/src/config/settings.h b/src/config/settings.h index 27aaf9530..76a42e23d 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 1 +#define CONFIG_VERSION 2 #define PROT_MASK_INDEX 0x0001 @@ -110,7 +110,6 @@ typedef struct { typedef struct { float lat; float lon; - bool disNightCom; // disable night communication uint16_t offsetSec; } cfgSun_t; @@ -145,6 +144,8 @@ typedef struct { char chName[6][MAX_NAME_LENGTH]; uint8_t frequency; uint8_t powerLevel; + bool disNightCom; // disable night communication + bool add2Total; // add values to total values - useful if one inverter is on battery to turn off } cfgIv_t; typedef struct { @@ -420,7 +421,6 @@ class settings { mCfg.sun.lat = 0.0; mCfg.sun.lon = 0.0; - mCfg.sun.disNightCom = false; mCfg.sun.offsetSec = 0; mCfg.serial.interval = SERIAL_INTERVAL; @@ -442,8 +442,10 @@ class settings { mCfg.inst.yieldEffiency = 0.955f; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value - mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value + mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + mCfg.inst.iv[i].disNightCom = false; + mCfg.inst.iv[i].add2Total = true; } mCfg.led.led0 = DEF_LED0; @@ -465,11 +467,15 @@ class settings { } void loadAddedDefaults() { - if(0 < mCfg.configVersion) { - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + if(mCfg.configVersion < 1) { mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value mCfg.inst.iv[i].frequency = 0x0; // 860MHz (backward compatibility) } + if(mCfg.configVersion < 2) { + mCfg.inst.iv[i].disNightCom = false; + mCfg.inst.iv[i].add2Total = true; + } } } @@ -601,12 +607,10 @@ class settings { if(set) { obj[F("lat")] = mCfg.sun.lat; obj[F("lon")] = mCfg.sun.lon; - obj[F("dis")] = mCfg.sun.disNightCom; obj[F("offs")] = mCfg.sun.offsetSec; } else { getVal(obj, F("lat"), &mCfg.sun.lat); getVal(obj, F("lon"), &mCfg.sun.lon); - getVal(obj, F("dis"), &mCfg.sun.disNightCom); getVal(obj, F("offs"), &mCfg.sun.offsetSec); } } @@ -734,6 +738,8 @@ class settings { obj[F("sn")] = cfg->serial.u64; obj[F("freq")] = cfg->frequency; obj[F("pa")] = cfg->powerLevel; + obj[F("dis")] = cfg->disNightCom; + obj[F("add")] = cfg->add2Total; for(uint8_t i = 0; i < 6; i++) { obj[F("yield")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; @@ -745,6 +751,8 @@ class settings { getVal(obj, F("sn"), &cfg->serial.u64); getVal(obj, F("freq"), &cfg->frequency); getVal(obj, F("pa"), &cfg->powerLevel); + getVal(obj, F("dis"), &cfg->disNightCom); + getVal(obj, F("add"), &cfg->add2Total); uint8_t size = 4; if(obj.containsKey(F("pwr"))) size = obj[F("pwr")].size(); diff --git a/src/defines.h b/src/defines.h index eeee3574f..fe9acf953 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 5 +#define VERSION_PATCH 7 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index f52bafe92..f3d149c44 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -130,6 +130,7 @@ class Inverter { int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') uint8_t txRfChId; // RF TX channel id uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime + bool commEnabled; // 'pause night communication' sets this field to false static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -150,6 +151,7 @@ class Inverter { alarmLastId = 0; rssi = -127; radio = NULL; + commEnabled = true; memset(&radioStatistics, 0, sizeof(statistics_t)); memset(txRfQuality, -6, 5); diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 48dbe1500..2c23c719d 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -134,7 +134,7 @@ class PubMqtt { #endif } - bool tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs, bool disNightCom) { + bool tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs) { if (!mClient.connected()) return false; @@ -142,7 +142,16 @@ class PubMqtt { publish(subtopics[MQTT_SUNSET], String(sunset).c_str(), true); publish(subtopics[MQTT_COMM_START], String(sunrise - offs).c_str(), true); publish(subtopics[MQTT_COMM_STOP], String(sunset + offs).c_str(), true); - publish(subtopics[MQTT_DIS_NIGHT_COMM], ((disNightCom) ? dict[STR_TRUE] : dict[STR_FALSE]), true); + + Inverter<> *iv; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + iv = mSys->getInverterByPos(i); + if(NULL == iv) + continue; + + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/dis_night_comm", iv->config->name); + publish(mSubTopic, ((iv->commEnabled) ? dict[STR_TRUE] : dict[STR_FALSE]), true); + } return true; } diff --git a/src/publisher/pubMqttDefs.h b/src/publisher/pubMqttDefs.h index ca8bf01e1..c97daa78f 100644 --- a/src/publisher/pubMqttDefs.h +++ b/src/publisher/pubMqttDefs.h @@ -48,7 +48,6 @@ enum { MQTT_SUNSET, MQTT_COMM_START, MQTT_COMM_STOP, - MQTT_DIS_NIGHT_COMM, MQTT_COMM_DISABLED, MQTT_COMM_DIS_TS, MQTT_VERSION, @@ -69,7 +68,6 @@ const char* const subtopics[] PROGMEM = { "sunset", "comm_start", "comm_stop", - "dis_night_comm", "comm_disabled", "comm_dis_ts", "version", diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 053e359ee..0ac6d3069 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -31,11 +31,11 @@ class PubMqttIvData { memset(mIvLastRTRpub, 0, MAX_NUM_INVERTERS * sizeof(uint32_t)); mRTRDataHasBeenSent = false; - mTable[IDLE] = &PubMqttIvData::stateIdle; - mTable[START] = &PubMqttIvData::stateStart; - mTable[FIND_NXT_IV] = &PubMqttIvData::stateFindNxtIv; - mTable[SEND_DATA] = &PubMqttIvData::stateSend; - mTable[SEND_TOTALS] = &PubMqttIvData::stateSendTotals; + mTable[IDLE] = &PubMqttIvData::stateIdle; + mTable[START] = &PubMqttIvData::stateStart; + mTable[FIND_NXT_IV] = &PubMqttIvData::stateFindNxtIv; + mTable[SEND_DATA] = &PubMqttIvData::stateSend; + mTable[SEND_TOTALS] = &PubMqttIvData::stateSendTotals; } void loop() { @@ -142,25 +142,27 @@ class PubMqttIvData { // calculate total values for RealTimeRunData_Debug if (CH0 == rec->assign[mPos].ch) { if(mIv->status > InverterStatus::STARTING) { - mTotalFound = true; - switch (rec->assign[mPos].fieldId) { - case FLD_PAC: - mTotal[0] += mIv->getValue(mPos, rec); - break; - case FLD_YT: - mTotal[1] += mIv->getValue(mPos, rec); - break; - case FLD_YD: { - float val = mIv->getValue(mPos, rec); - if(0 == val) // inverter restarted during day - mSendTotalYd = false; - else - mTotal[2] += val; - break; + if(mIv->config->add2Total) { + mTotalFound = true; + switch (rec->assign[mPos].fieldId) { + case FLD_PAC: + mTotal[0] += mIv->getValue(mPos, rec); + break; + case FLD_YT: + mTotal[1] += mIv->getValue(mPos, rec); + break; + case FLD_YD: { + float val = mIv->getValue(mPos, rec); + if(0 == val) // inverter restarted during day + mSendTotalYd = false; + else + mTotal[2] += val; + break; + } + case FLD_PDC: + mTotal[3] += mIv->getValue(mPos, rec); + break; } - case FLD_PDC: - mTotal[3] += mIv->getValue(mPos, rec); - break; } } else mAllTotalFound = false; @@ -178,12 +180,25 @@ class PubMqttIvData { mPublish(mSubTopic, mVal, retained, qos); } mPos++; - } else + } else { + sendRadioStat(rec->length); mState = FIND_NXT_IV; + } } else mState = FIND_NXT_IV; } + inline void sendRadioStat(uint8_t start) { + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/radio_stat", mIv->config->name); + snprintf(mVal, 100, "{\"tx\":%d,\"success\":%d,\"fail\":%d,\"no_answer\":%d,\"retransmits\":%d}", + mIv->radioStatistics.txCnt, + mIv->radioStatistics.rxSuccess, + mIv->radioStatistics.rxFail, + mIv->radioStatistics.rxFailNoAnser, + mIv->radioStatistics.retransmits); + mPublish(mSubTopic, mVal, false, QOS_0); + } + void stateSendTotals() { uint8_t fieldId; mRTRDataHasBeenSent = true; @@ -221,7 +236,8 @@ class PubMqttIvData { } else { mSendList->pop(); mZeroValues = false; - mState = START; + mPos = 0; + mState = IDLE; } } @@ -242,7 +258,7 @@ class PubMqttIvData { bool mRTRDataHasBeenSent; char mSubTopic[32 + MAX_NAME_LENGTH + 1]; - char mVal[40]; + char mVal[100]; bool mZeroValues; // makes sure that yield day is sent even if no inverter is online std::queue *mSendList; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 53adb23fa..fa2aaf224 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -339,27 +339,30 @@ class RestApi { Inverter<> *iv; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { iv = mSys->getInverterByPos(i); - if(NULL != iv) { - JsonObject obj2 = invArr.createNestedObject(); - obj2[F("enabled")] = (bool)iv->config->enabled; - obj2[F("id")] = i; - obj2[F("name")] = String(iv->config->name); - obj2[F("serial")] = String(iv->config->serial.u64, HEX); - obj2[F("channels")] = iv->channels; - obj2[F("freq")] = iv->config->frequency; - if(0xff == iv->config->powerLevel) { - if((IV_HMT == iv->ivGen) || (IV_HMS == iv->ivGen)) - obj2[F("pa")] = 30; // 20dBm - else - obj2[F("pa")] = 1; // low - } else - obj2[F("pa")] = iv->config->powerLevel; - - for(uint8_t j = 0; j < iv->channels; j ++) { - obj2[F("ch_yield_cor")][j] = (double)iv->config->yieldCor[j]; - obj2[F("ch_name")][j] = iv->config->chName[j]; - obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j]; - } + if(NULL == iv) + continue; + + JsonObject obj2 = invArr.createNestedObject(); + obj2[F("enabled")] = (bool)iv->config->enabled; + obj2[F("id")] = i; + obj2[F("name")] = String(iv->config->name); + obj2[F("serial")] = String(iv->config->serial.u64, HEX); + obj2[F("channels")] = iv->channels; + obj2[F("freq")] = iv->config->frequency; + obj2[F("disnightcom")] = (bool)iv->config->disNightCom; + obj2[F("add2total")] = (bool)iv->config->add2Total; + if(0xff == iv->config->powerLevel) { + if((IV_HMT == iv->ivGen) || (IV_HMS == iv->ivGen)) + obj2[F("pa")] = 30; // 20dBm + else + obj2[F("pa")] = 1; // low + } else + obj2[F("pa")] = iv->config->powerLevel; + + for(uint8_t j = 0; j < iv->channels; j ++) { + obj2[F("ch_yield_cor")][j] = (double)iv->config->yieldCor[j]; + obj2[F("ch_name")][j] = iv->config->chName[j]; + obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j]; } } obj[F("interval")] = String(mConfig->nrf.sendInterval); @@ -501,7 +504,6 @@ class RestApi { void getSun(JsonObject obj) { obj[F("lat")] = mConfig->sun.lat ? String(mConfig->sun.lat, 5) : ""; obj[F("lon")] = mConfig->sun.lat ? String(mConfig->sun.lon, 5) : ""; - obj[F("disnightcom")] = mConfig->sun.disNightCom; obj[F("offs")] = mConfig->sun.offsetSec; } @@ -583,24 +585,28 @@ class RestApi { obj[F("ts_sunrise")] = mApp->getSunrise(); obj[F("ts_sunset")] = mApp->getSunset(); obj[F("ts_offset")] = mConfig->sun.offsetSec; - obj[F("disNightComm")] = mConfig->sun.disNightCom; JsonArray inv = obj.createNestedArray(F("inverter")); Inverter<> *iv; + bool disNightCom = false; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { iv = mSys->getInverterByPos(i); - if(NULL != iv) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - JsonObject invObj = inv.createNestedObject(); - invObj[F("enabled")] = (bool)iv->config->enabled; - invObj[F("id")] = i; - invObj[F("name")] = String(iv->config->name); - invObj[F("cur_pwr")] = ah::round3(iv->getChannelFieldValue(CH0, FLD_PAC, rec)); - invObj[F("is_avail")] = iv->isAvailable(); - invObj[F("is_producing")] = iv->isProducing(); - invObj[F("ts_last_success")] = iv->getLastTs(rec); - } + if(NULL == iv) + continue; + + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + JsonObject invObj = inv.createNestedObject(); + invObj[F("enabled")] = (bool)iv->config->enabled; + invObj[F("id")] = i; + invObj[F("name")] = String(iv->config->name); + invObj[F("cur_pwr")] = ah::round3(iv->getChannelFieldValue(CH0, FLD_PAC, rec)); + invObj[F("is_avail")] = iv->isAvailable(); + invObj[F("is_producing")] = iv->isProducing(); + invObj[F("ts_last_success")] = iv->getLastTs(rec); + if(iv->config->disNightCom) + disNightCom = true; } + obj[F("disNightComm")] = disNightCom; JsonArray warn = obj.createNestedArray(F("warnings")); if(!mRadioNrf->isChipConnected() && mConfig->nrf.enabled) @@ -729,8 +735,10 @@ class RestApi { } mApp->initInverter(jsonIn[F("id")]); - iv->config->frequency = jsonIn[F("freq")]; - iv->config->powerLevel = jsonIn[F("pa")]; + iv->config->frequency = jsonIn[F("freq")]; + iv->config->powerLevel = jsonIn[F("pa")]; + iv->config->disNightCom = jsonIn[F("disnightcom")]; + iv->config->add2Total = jsonIn[F("add2total")]; mApp->saveSettings(false); // without reboot } else { jsonOut[F("error")] = F("unknown cmd"); diff --git a/src/web/html/setup.html b/src/web/html/setup.html index a21aa0738..b9933cea6 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -140,38 +140,33 @@
Inverter
- -
-

General

-
-
-
Interval [s]
-
+
Interval [s]
+
-
Reset values and YieldDay at midnight
-
+
Reset values and YieldDay at midnight
+
-
Reset values when inverter polling pauses at sunset
-
+
Reset values when inverter polling pauses at sunset
+
-
Reset values when inverter status is 'not available'
-
+
Reset values when inverter status is 'not available'
+
-
Reset 'max' values at midnight
-
+
Reset 'max' values at midnight
+
-
Start without time sync (useful in AP-Only-Mode)
-
+
Start without time sync (useful in AP-Only-Mode)
+
-
Yield Efficiency (should be between 0.95 and 0.96)
-
+
Yield Efficiency (should be between 0.95 and 0.96)
+
@@ -223,10 +218,6 @@
Offset (pre sunrise, post sunset)
-
-
Pause polling inverters during night
-
-
@@ -434,6 +425,7 @@ [47, "GPIO47"], [48, "GPIO48"], ]; + /*ENDIF_ESP32*/ var nrfPa = [ [0, "MIN (recommended)"], [1, "LOW"], @@ -442,6 +434,8 @@ ]; var esp32cmtPa = []; var esp32cmtFreq = []; + + /*IF_ESP32*/ var freqFmt = new Intl.NumberFormat('en-US', { minimumIntegerDigits: 3, minimumFractionDigits: 2 @@ -645,6 +639,7 @@ add.ch_yield_cor = []; add.freq = 12; add.pa = 30; + add.add2total = true; var e = document.getElementById("inverter"); e.innerHTML = ""; // remove all childs @@ -674,23 +669,27 @@ } var cbEn = ml("input", {name: "enable", type: "checkbox"}, null); - if(obj.enabled) - cbEn.checked = true; + var cbDisNightCom = ml("input", {name: "disnightcom", type: "checkbox"}, null); + var cbAddTotal = ml("input", {name: "add2total", type: "checkbox"}, null); + cbEn.checked = (obj.enabled); + cbDisNightCom.checked = (obj.disnightcom); + cbAddTotal.checked = (obj.add2total); + var ser = ml("input", {name: "ser", class: "text", type: "number", max: 138999999999, value: obj.serial}, null); var html = ml("div", {}, [ - tabs(["General", "Inputs", "Radio"]), + tabs(["General", "Inputs", "Radio", "Advanced"]), ml("div", {id: "divGeneral", class: "tab-content"}, [ ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Enable"), - ml("div", {class: "col-8"}, cbEn) + ml("div", {class: "col-2"}, "Enable"), + ml("div", {class: "col-10"}, cbEn) ]), ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Serial"), - ml("div", {class: "col-8"}, ser) + ml("div", {class: "col-2 mt-2"}, "Serial"), + ml("div", {class: "col-10"}, ser) ]), ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Name"), - ml("div", {class: "col-8"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) + ml("div", {class: "col-2 mt-2"}, "Name"), + ml("div", {class: "col-10"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) ]) ]), ml("div", {id: "divInputs", class: "tab-content hide"}, [ @@ -704,21 +703,31 @@ ml("input", {type: "hidden", name: "isnrf"}, null), ml("div", {id: "setcmt"}, [ ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Frequency"), - ml("div", {class: "col-8"}, sel("freq", esp32cmtFreq, obj.freq)) + ml("div", {class: "col-3 mt-2"}, "Frequency"), + ml("div", {class: "col-9"}, sel("freq", esp32cmtFreq, obj.freq)) ]), ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Power Level"), - ml("div", {class: "col-8"}, sel("cmtpa", esp32cmtPa, obj.pa)) + ml("div", {class: "col-3 mt-2"}, "Power Level"), + ml("div", {class: "col-9"}, sel("cmtpa", esp32cmtPa, obj.pa)) ]), ]), ml("div", {id: "setnrf"}, ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Power Level"), - ml("div", {class: "col-8"}, sel("nrfpa", nrfPa, obj.pa)) + ml("div", {class: "col-3 mt-2"}, "Power Level"), + ml("div", {class: "col-9"}, sel("nrfpa", nrfPa, obj.pa)) ]), ), ]), + ml("div", {id: "divAdvanced", class: "tab-content hide"}, [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-10"}, "Pause communication during night (lat. and lon. need to be set)"), + ml("div", {class: "col-2"}, cbDisNightCom) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-10"}, "Include inverter to sum of total (should be checked by default)"), + ml("div", {class: "col-2"}, cbAddTotal) + ]) + ]), ml("div", {class: "row mt-5"}, [ ml("div", {class: "col-8", id: "res"}, ""), ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "save", class: "btn", onclick: function() { ivSave(); }}, null)) @@ -758,7 +767,7 @@ }) }); - modal("Edit inverter", html); + modal("Edit inverter " + obj.name, html); ser.dispatchEvent(new Event('change')); function ivSave() { @@ -781,6 +790,8 @@ else o.pa = document.getElementsByName("cmtpa")[0].value; o.freq = document.getElementsByName("freq")[0].value; + o.disnightcom = document.getElementsByName("disnightcom")[0].checked; + o.add2total = document.getElementsByName("add2total")[0].checked; getAjax("/api/setup", cb, "POST", JSON.stringify(o)); } @@ -841,7 +852,6 @@ function parseSun(obj) { document.getElementsByName("sunLat")[0].value = obj["lat"]; document.getElementsByName("sunLon")[0].value = obj["lon"]; - document.getElementsByName("sunDisNightCom")[0].checked = obj["disnightcom"]; const sel = document.getElementsByName("sunOffs")[0]; for(var i = 0; i <= 60; i++) { sel.appendChild(opt(i, i + " minutes", (i == (obj["offs"] / 60)))); diff --git a/src/web/web.h b/src/web/web.h index c37db811a..ae2fc091e 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -535,12 +535,10 @@ class Web { if (request->arg("sunLat") == "" || (request->arg("sunLon") == "")) { mConfig->sun.lat = 0.0; mConfig->sun.lon = 0.0; - mConfig->sun.disNightCom = false; mConfig->sun.offsetSec = 0; } else { mConfig->sun.lat = request->arg("sunLat").toFloat(); mConfig->sun.lon = request->arg("sunLon").toFloat(); - mConfig->sun.disNightCom = (request->arg("sunDisNightCom") == "on"); mConfig->sun.offsetSec = request->arg("sunOffs").toInt() * 60; }