mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-17 02:46:11 +02:00
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
This commit is contained in:
parent
a82777b2a1
commit
1bc3a0f06f
12 changed files with 223 additions and 161 deletions
|
@ -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)
|
||||
|
|
64
src/app.cpp
64
src/app.cpp
|
@ -4,9 +4,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#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;
|
||||
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
|
||||
mIVCommunicationOn = true;
|
||||
iv->commEnabled = true;
|
||||
nxtTrig = mSunset + mConfig->sun.offsetSec;
|
||||
}
|
||||
}
|
||||
if (nxtTrig != 0)
|
||||
onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom");
|
||||
restartTick = true;
|
||||
}
|
||||
tickComm();
|
||||
|
||||
if ((!iv->commEnabled) && (mConfig->inst.rstValsCommStop))
|
||||
zeroValues = true;
|
||||
}
|
||||
|
||||
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,15 +330,18 @@ 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(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);
|
||||
|
@ -342,7 +350,6 @@ void app::tickSend(void) {
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateLed();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -307,7 +307,6 @@ class app : public IApp, public ah::Scheduler {
|
|||
Communication mCommunication;
|
||||
|
||||
bool mShowRebootRequest;
|
||||
bool mIVCommunicationOn;
|
||||
|
||||
#if defined(ETHERNET)
|
||||
ahoyeth mEth;
|
||||
|
|
|
@ -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;
|
||||
|
@ -444,6 +444,8 @@ class settings {
|
|||
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].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++) {
|
||||
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<float>(obj, F("lat"), &mCfg.sun.lat);
|
||||
getVal<float>(obj, F("lon"), &mCfg.sun.lon);
|
||||
getVal<bool>(obj, F("dis"), &mCfg.sun.disNightCom);
|
||||
getVal<uint16_t>(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<uint64_t>(obj, F("sn"), &cfg->serial.u64);
|
||||
getVal<uint8_t>(obj, F("freq"), &cfg->frequency);
|
||||
getVal<uint8_t>(obj, F("pa"), &cfg->powerLevel);
|
||||
getVal<bool>(obj, F("dis"), &cfg->disNightCom);
|
||||
getVal<bool>(obj, F("add"), &cfg->add2Total);
|
||||
uint8_t size = 4;
|
||||
if(obj.containsKey(F("pwr")))
|
||||
size = obj[F("pwr")].size();
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 8
|
||||
#define VERSION_PATCH 5
|
||||
#define VERSION_PATCH 7
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -142,6 +142,7 @@ class PubMqttIvData {
|
|||
// calculate total values for RealTimeRunData_Debug
|
||||
if (CH0 == rec->assign[mPos].ch) {
|
||||
if(mIv->status > InverterStatus::STARTING) {
|
||||
if(mIv->config->add2Total) {
|
||||
mTotalFound = true;
|
||||
switch (rec->assign[mPos].fieldId) {
|
||||
case FLD_PAC:
|
||||
|
@ -162,6 +163,7 @@ class PubMqttIvData {
|
|||
mTotal[3] += mIv->getValue(mPos, rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
mAllTotalFound = false;
|
||||
}
|
||||
|
@ -178,10 +180,23 @@ class PubMqttIvData {
|
|||
mPublish(mSubTopic, mVal, retained, qos);
|
||||
}
|
||||
mPos++;
|
||||
} else {
|
||||
sendRadioStat(rec->length);
|
||||
mState = FIND_NXT_IV;
|
||||
}
|
||||
} else
|
||||
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() {
|
||||
|
@ -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<sendListCmdIv> *mSendList;
|
||||
|
|
|
@ -339,7 +339,9 @@ class RestApi {
|
|||
Inverter<> *iv;
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||
iv = mSys->getInverterByPos(i);
|
||||
if(NULL != iv) {
|
||||
if(NULL == iv)
|
||||
continue;
|
||||
|
||||
JsonObject obj2 = invArr.createNestedObject();
|
||||
obj2[F("enabled")] = (bool)iv->config->enabled;
|
||||
obj2[F("id")] = i;
|
||||
|
@ -347,6 +349,8 @@ class RestApi {
|
|||
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
|
||||
|
@ -361,7 +365,6 @@ class RestApi {
|
|||
obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
obj[F("interval")] = String(mConfig->nrf.sendInterval);
|
||||
obj[F("max_num_inverters")] = MAX_NUM_INVERTERS;
|
||||
obj[F("rstMid")] = (bool)mConfig->inst.rstYieldMidNight;
|
||||
|
@ -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,13 +585,15 @@ 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) {
|
||||
if(NULL == iv)
|
||||
continue;
|
||||
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
JsonObject invObj = inv.createNestedObject();
|
||||
invObj[F("enabled")] = (bool)iv->config->enabled;
|
||||
|
@ -599,8 +603,10 @@ class RestApi {
|
|||
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)
|
||||
|
@ -731,6 +737,8 @@ class RestApi {
|
|||
mApp->initInverter(jsonIn[F("id")]);
|
||||
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");
|
||||
|
|
|
@ -140,38 +140,33 @@
|
|||
<fieldset class="mb-4">
|
||||
<legend class="des">Inverter</legend>
|
||||
<div id="inverter"></div>
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-12 col-sm-3"><p class="subdes">General</p></div>
|
||||
<div class="col-12 col-sm-9"></div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 my-2">Interval [s]</div>
|
||||
<div class="col-4"><input type="number" name="invInterval" title="Invalid input"/></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-sm-3 my-2">Interval [s]</div>
|
||||
<div class="col-12 col-sm-9"><input type="number" name="invInterval" title="Invalid input"/></div>
|
||||
<div class="col-8 mb-2">Reset values and YieldDay at midnight</div>
|
||||
<div class="col-4"><input type="checkbox" name="invRstMid"/></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3 mb-2">Reset values and YieldDay at midnight</div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="invRstMid"/></div>
|
||||
<div class="col-8 mb-2">Reset values when inverter polling pauses at sunset</div>
|
||||
<div class="col-4"><input type="checkbox" name="invRstComStop"/></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3 mb-2">Reset values when inverter polling pauses at sunset</div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="invRstComStop"/></div>
|
||||
<div class="col-8">Reset values when inverter status is 'not available'</div>
|
||||
<div class="col-4"><input type="checkbox" name="invRstNotAvail"/></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3">Reset values when inverter status is 'not available'</div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="invRstNotAvail"/></div>
|
||||
<div class="col-8">Reset 'max' values at midnight</div>
|
||||
<div class="col-4"><input type="checkbox" name="invRstMaxMid"/></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3">Reset 'max' values at midnight</div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="invRstMaxMid"/></div>
|
||||
<div class="col-8">Start without time sync (useful in AP-Only-Mode)</div>
|
||||
<div class="col-4"><input type="checkbox" name="strtWthtTm"/></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3">Start without time sync (useful in AP-Only-Mode)</div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="strtWthtTm"/></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3">Yield Efficiency (should be between 0.95 and 0.96)</div>
|
||||
<div class="col-4 col-sm-9"><input type="number" name="yldEff" step="any"/></div>
|
||||
<div class="col-8">Yield Efficiency (should be between 0.95 and 0.96)</div>
|
||||
<div class="col-4"><input type="number" name="yldEff" step="any"/></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
@ -223,10 +218,6 @@
|
|||
<div class="col-12 col-sm-3 my-2">Offset (pre sunrise, post sunset)</div>
|
||||
<div class="col-12 col-sm-9"><select name="sunOffs"></select></div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-8 col-sm-3">Pause polling inverters during night</div>
|
||||
<div class="col-4 col-sm-9"><input type="checkbox" name="sunDisNightCom"/></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
|
@ -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))));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue