Browse Source

0.7.6

* fix display of hidden SSID checkbox
* changed yield correction data type to `double`, now decimal places are supported
* corrected name of 0.91" display in settings
* attempt to fix MqTT zero values only if setting is there #980, #957
* made AP password configurable #951
* added option to start without time-sync, eg. for AP-only-mode #951
pull/1005/head
lumapu 2 years ago
parent
commit
c147906834
  1. 8
      src/CHANGES.md
  2. 15
      src/app.cpp
  3. 10
      src/config/settings.h
  4. 2
      src/defines.h
  5. 7
      src/publisher/pubMqtt.h
  6. 35
      src/publisher/pubMqttIvData.h
  7. 4
      src/utils/scheduler.h
  8. 2
      src/web/RestApi.h
  9. 8
      src/web/html/index.html
  10. 21
      src/web/html/setup.html
  11. 5
      src/web/html/style.css
  12. 3
      src/web/web.h
  13. 4
      src/wifi/ahoywifi.cpp

8
src/CHANGES.md

@ -1,5 +1,13 @@
# Development Changes
## 0.7.6 - 2023-06-17
* fix display of hidden SSID checkbox
* changed yield correction data type to `double`, now decimal places are supported
* corrected name of 0.91" display in settings
* attempt to fix MqTT zero values only if setting is there #980, #957
* made AP password configurable #951
* added option to start without time-sync, eg. for AP-only-mode #951
## 0.7.5 - 2023-06-16
* fix yield day reset on midnight #957
* improved tickers in `app.cpp`

15
src/app.cpp

@ -17,12 +17,12 @@ void app::setup() {
while (!Serial)
yield();
ah::Scheduler::setup();
resetSystem();
mSettings.setup();
mSettings.getPtr(mConfig);
ah::Scheduler::setup(mConfig->inst.startWithoutTime);
DPRINT(DBG_INFO, F("Settings valid: "));
if (mSettings.getValid())
DBGPRINTLN(F("true"));
@ -67,10 +67,6 @@ void app::setup() {
mHmsPayload.enableSerialDebug(mConfig->serial.debug);
mHmsPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2));
#endif
/*DBGPRINTLN("--- after payload");
DBGPRINTLN(String(ESP.getFreeHeap()));
DBGPRINTLN(String(ESP.getHeapFragmentation()));
DBGPRINTLN(String(ESP.getMaxFreeBlockSize()));*/
if(mConfig->nrf.enabled) {
if (!mNrfRadio.isChipConnected())
@ -101,12 +97,6 @@ void app::setup() {
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
regularTickers();
// DBGPRINTLN("--- end setup");
// DBGPRINTLN(String(ESP.getFreeHeap()));
// DBGPRINTLN(String(ESP.getHeapFragmentation()));
// DBGPRINTLN(String(ESP.getMaxFreeBlockSize()));
}
//-----------------------------------------------------------------------------
@ -253,7 +243,6 @@ void app::tickNtpUpdate(void) {
}
// immediately start communicating
// @TODO: leads to reboot loops? not sure #674
if (isOK && mSendFirst) {
mSendFirst = false;
once(std::bind(&app::tickSend, this), 2, "senOn");
@ -439,7 +428,7 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) {
}
if(changed) {
if(mMqttEnabled)
if(mMqttEnabled && !skipYieldDay)
mMqtt.setZeroValuesEnable();
payloadEventListener(RealTimeRunData_Debug, NULL);
}

10
src/config/settings.h

@ -68,6 +68,7 @@ typedef struct {
// wifi
char stationSsid[SSID_LEN];
char stationPwd[PWD_LEN];
char apPwd[PWD_LEN];
bool isHidden;
cfgIp_t ip;
@ -131,7 +132,7 @@ typedef struct {
char name[MAX_NAME_LENGTH];
serial_u serial;
uint16_t chMaxPwr[6];
int32_t yieldCor[6]; // signed YieldTotal correction value
double yieldCor[6]; // signed YieldTotal correction value
char chName[6][MAX_NAME_LENGTH];
} cfgIv_t;
@ -142,6 +143,7 @@ typedef struct {
bool rstYieldMidNight;
bool rstValsNotAvail;
bool rstValsCommStop;
bool startWithoutTime;
} cfgInst_t;
typedef struct {
@ -360,6 +362,7 @@ class settings {
else {
snprintf(mCfg.sys.stationSsid, SSID_LEN, FB_WIFI_SSID);
snprintf(mCfg.sys.stationPwd, PWD_LEN, FB_WIFI_PWD);
snprintf(mCfg.sys.apPwd, PWD_LEN, WIFI_AP_PWD);
mCfg.sys.isHidden = false;
}
@ -404,6 +407,7 @@ class settings {
mCfg.inst.rstYieldMidNight = false;
mCfg.inst.rstValsNotAvail = false;
mCfg.inst.rstValsCommStop = false;
mCfg.inst.startWithoutTime = false;
mCfg.led.led0 = DEF_PIN_OFF;
mCfg.led.led1 = DEF_PIN_OFF;
@ -428,6 +432,7 @@ class settings {
char buf[16];
obj[F("ssid")] = mCfg.sys.stationSsid;
obj[F("pwd")] = mCfg.sys.stationPwd;
obj[F("ap_pwd")] = mCfg.sys.apPwd;
obj[F("hidd")] = (bool) mCfg.sys.isHidden;
obj[F("dev")] = mCfg.sys.deviceName;
obj[F("adm")] = mCfg.sys.adminPwd;
@ -441,6 +446,7 @@ class settings {
} else {
getChar(obj, F("ssid"), mCfg.sys.stationSsid, SSID_LEN);
getChar(obj, F("pwd"), mCfg.sys.stationPwd, PWD_LEN);
getChar(obj, F("ap_pwd"), mCfg.sys.apPwd, PWD_LEN);
getVal<bool>(obj, F("hidd"), &mCfg.sys.isHidden);
getChar(obj, F("dev"), mCfg.sys.deviceName, DEVNAME_LEN);
getChar(obj, F("adm"), mCfg.sys.adminPwd, PWD_LEN);
@ -617,12 +623,14 @@ class settings {
obj[F("rstMidNight")] = (bool)mCfg.inst.rstYieldMidNight;
obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail;
obj[F("rstComStop")] = (bool)mCfg.inst.rstValsCommStop;
obj[F("strtWthtTime")] = (bool)mCfg.inst.startWithoutTime;
}
else {
getVal<bool>(obj, F("en"), &mCfg.inst.enabled);
getVal<bool>(obj, F("rstMidNight"), &mCfg.inst.rstYieldMidNight);
getVal<bool>(obj, F("rstNotAvail"), &mCfg.inst.rstValsNotAvail);
getVal<bool>(obj, F("rstComStop"), &mCfg.inst.rstValsCommStop);
getVal<bool>(obj, F("strtWthtTime"), &mCfg.inst.startWithoutTime);
}
JsonArray ivArr;

2
src/defines.h

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

7
src/publisher/pubMqtt.h

@ -52,6 +52,7 @@ class PubMqtt {
memset(mLastIvState, MQTT_STATUS_NOT_AVAIL_NOT_PROD, MAX_NUM_INVERTERS);
memset(mIvLastRTRpub, 0, MAX_NUM_INVERTERS * 4);
mLastAnyAvail = false;
mZeroValues = false;
}
~PubMqtt() { }
@ -241,7 +242,7 @@ class PubMqtt {
}
void setZeroValuesEnable(void) {
mSendIvData.setZeroValuesEnable();
mZeroValues = true;
}
private:
@ -574,7 +575,8 @@ class PubMqtt {
if(mSendList.empty())
return;
mSendIvData.start();
mSendIvData.start(mZeroValues);
mZeroValues = false;
mLastAnyAvail = anyAvail;
}
@ -593,6 +595,7 @@ class PubMqtt {
std::queue<alarm_t> mAlarmList;
subscriptionCb mSubscriptionCb;
bool mLastAnyAvail;
bool mZeroValues;
uint8_t mLastIvState[MAX_NUM_INVERTERS];
uint32_t mIvLastRTRpub[MAX_NUM_INVERTERS];
uint16_t mIntervalTimeout;

35
src/publisher/pubMqttIvData.h

@ -43,10 +43,11 @@ class PubMqttIvData {
yield();
}
bool start(void) {
bool start(bool zeroValues = false) {
if(IDLE != mState)
return false;
mZeroValues = zeroValues;
mRTRDataHasBeenSent = false;
mState = START;
return true;
@ -56,10 +57,6 @@ class PubMqttIvData {
mPublish = cb;
}
void setZeroValuesEnable(void) {
mZeroValues = true;
}
private:
enum State {IDLE, START, FIND_NXT_IV, SEND_DATA, SEND_TOTALS, NUM_STATES};
typedef void (PubMqttIvData::*StateFunction)();
@ -100,8 +97,11 @@ class PubMqttIvData {
mLastIvId++;
mPos = 0;
if(found)
if(found) {
mState = SEND_DATA;
if(!mIv->isAvailable(*mUtcTimestamp))
mSendTotals = false; // avoid send total values on not producing, because the sum of values is not built
}
else if(mSendTotals)
mState = SEND_TOTALS;
else {
@ -122,19 +122,16 @@ class PubMqttIvData {
if(mPos < rec->length) {
bool retained = false;
if (mCmd == RealTimeRunData_Debug) {
switch (rec->assign[mPos].fieldId) {
case FLD_YT:
case FLD_YD:
if(!mZeroValues) {
if ((rec->assign[mPos].ch == CH0) && (!mIv->isProducing(*mUtcTimestamp))) { // avoids returns to 0 on restart
mPos++;
if(!mIv->isAvailable(*mUtcTimestamp))
mSendTotals = false; // avoid send total values on not producing, because the sum of values is no built
return;
}
if(FLD_YT == rec->assign[mPos].fieldId)
retained = true;
else if(FLD_YD == rec->assign[mPos].fieldId) {
if(!mZeroValues) {
if ((rec->assign[mPos].ch == CH0) && (!mIv->isProducing(*mUtcTimestamp))) { // avoids returns to 0 on restart
mPos++;
return;
}
retained = true;
break;
}
retained = true;
}
// calculate total values for RealTimeRunData_Debug
@ -221,7 +218,7 @@ class PubMqttIvData {
char mSubTopic[32 + MAX_NAME_LENGTH + 1];
char mVal[40];
bool mZeroValues;
bool mZeroValues; // makes sure that yield day is sent even if no inverter is online
std::queue<sendListCmdIv> *mSendList;
};

4
src/utils/scheduler.h

@ -31,9 +31,9 @@ namespace ah {
public:
Scheduler() {}
void setup() {
void setup(bool directStart) {
mUptime = 0;
mTimestamp = 0;
mTimestamp = (directStart) ? 1 : 0;
mMax = 0;
mPrevMillis = millis();
resetTicker();

2
src/web/RestApi.h

@ -206,6 +206,7 @@ class RestApi {
void getSysInfo(AsyncWebServerRequest *request, JsonObject obj) {
obj[F("ssid")] = mConfig->sys.stationSsid;
obj[F("ap_pwd")] = mConfig->sys.apPwd;
obj[F("hidd")] = mConfig->sys.isHidden;
obj[F("device_name")] = mConfig->sys.deviceName;
obj[F("dark_mode")] = (bool)mConfig->sys.darkMode;
@ -326,6 +327,7 @@ class RestApi {
obj[F("rstMid")] = (bool)mConfig->inst.rstYieldMidNight;
obj[F("rstNAvail")] = (bool)mConfig->inst.rstValsNotAvail;
obj[F("rstComStop")] = (bool)mConfig->inst.rstValsCommStop;
obj[F("strtWthtTm")] = (bool)mConfig->inst.startWithoutTime;
}
void getInverter(JsonObject obj, uint8_t id) {

8
src/web/html/index.html

@ -88,8 +88,12 @@
+ ("0"+min).substr(-2) + ":"
+ ("0"+sec).substr(-2);
var dSpan = document.getElementById("date");
if(0 != obj["ts_now"])
dSpan.innerHTML = date.toLocaleString('de-DE');
if(0 != obj["ts_now"]) {
if(obj["ts_now"] < 1680000000)
setTime();
else
dSpan.innerHTML = date.toLocaleString('de-DE');
}
else {
dSpan.innerHTML = "";
var e = inp("set", "sync from browser", 0, ["btn"], "set", "button");

21
src/web/html/setup.html

@ -55,6 +55,12 @@
<div class="s_content">
<fieldset class="mb-2">
<legend class="des">WiFi</legend>
<div class="row mb-3">
<div class="col-12 col-sm-3 my-2">AP Password (min. length: 8)</div>
<div class="col-12 col-sm-9"><input type="text" name="ap_pwd" minlength="8" /></div>
</div>
<p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.</p>
<div class="row mb-3">
@ -72,11 +78,11 @@
</div>
<div class="row mb-2 mb-sm-3">
<div class="col-12 col-sm-3 my-2">SSID</div>
<div class="col-12 col-sm-9"><input type="text" name="ssid"/><div>
<div class="col-12 col-sm-9"><input type="text" name="ssid"/></div>
</div>
<div class="row mb-2 mb-sm-3">
<div class="col-12 col-sm-3 my-2">hidden SSID</div>
<div class="col-12 col-sm-9"><input type="checkbox" name="hidd"/><div>
<div class="col-12 col-sm-3">SSID is hidden</div>
<div class="col-12 col-sm-9"><input type="checkbox" name="hidd"/></div>
</div>
<div class="row mb-2 mb-sm-3">
<div class="col-12 col-sm-3 my-2">Password</div>
@ -162,6 +168,10 @@
<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>
<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>
</fieldset>
</div>
@ -616,10 +626,11 @@
document.getElementsByName(i[0])[0].value = obj[i[1]];
for(var i of [["Mid", "rstMid"], ["ComStop", "rstComStop"], ["NotAvail", "rstNAvail"]])
document.getElementsByName("invRst"+i[0])[0].checked = obj[i[1]];
document.getElementsByName("strtWthtTm")[0].checked = obj["strtWthtTm"];
}
function parseSys(obj) {
for(var i of [["device", "device_name"], ["ssid", "ssid"]])
for(var i of [["device", "device_name"], ["ssid", "ssid"], ["ap_pwd", "ap_pwd"]])
document.getElementsByName(i[0])[0].value = obj[i[1]];
document.getElementsByName("hidd")[0].checked = obj["hidd"];
document.getElementsByName("darkMode")[0].checked = obj["dark_mode"];
@ -789,7 +800,7 @@
);
}
var opts = [[0, "None"], [1, "SSD1306 0.96\" 128X64"], [2, "SH1106 1.3\""], [3, "Nokia5110"], [4, "SSD1306 0.96\" 128X32"]];
var opts = [[0, "None"], [1, "SSD1306 0.96\" 128X64"], [2, "SH1106 1.3\""], [3, "Nokia5110"], [4, "SSD1306 0.91\" 128X32"]];
if("ESP32" == type)
opts.push([10, "ePaper"]);
var dispType = sel("disp_typ", opts, obj["disp_typ"]);

5
src/web/html/style.css

@ -475,6 +475,11 @@ input[type=text], input[type=password], select, input[type=number] {
color: var(--fg);
}
input:invalid {
border: 2px solid #f00 !important;
background-color: #400 !important;
}
input.sh {
max-width: 150px !important;
margin-right: 10px;

3
src/web/web.h

@ -448,6 +448,8 @@ class Web {
request->arg("ssid").toCharArray(mConfig->sys.stationSsid, SSID_LEN);
if (request->arg("pwd") != "{PWD}")
request->arg("pwd").toCharArray(mConfig->sys.stationPwd, PWD_LEN);
if (request->arg("ap_pwd") != "")
request->arg("ap_pwd").toCharArray(mConfig->sys.apPwd, PWD_LEN);
mConfig->sys.isHidden = (request->arg("hidd") == "on");
if (request->arg("device") != "")
request->arg("device").toCharArray(mConfig->sys.deviceName, DEVNAME_LEN);
@ -521,6 +523,7 @@ class Web {
mConfig->inst.rstYieldMidNight = (request->arg("invRstMid") == "on");
mConfig->inst.rstValsCommStop = (request->arg("invRstComStop") == "on");
mConfig->inst.rstValsNotAvail = (request->arg("invRstNotAvail") == "on");
mConfig->inst.startWithoutTime = (request->arg("strtWthtTm") == "on");
// pinout
uint8_t pin;

4
src/wifi/ahoywifi.cpp

@ -170,7 +170,7 @@ void ahoywifi::setupAp(void) {
DBGPRINT(F("\n---------\nAP MODE\nSSID: "));
DBGPRINTLN(WIFI_AP_SSID);
DBGPRINT(F("PWD: "));
DBGPRINTLN(WIFI_AP_PWD);
DBGPRINTLN(mConfig->sys.apPwd);
DBGPRINT(F("IP Address: http://"));
DBGPRINTLN(mApIp.toString());
DBGPRINTLN(F("---------\n"));
@ -180,7 +180,7 @@ void ahoywifi::setupAp(void) {
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(mApIp, mApIp, IPAddress(255, 255, 255, 0));
WiFi.softAP(WIFI_AP_SSID, WIFI_AP_PWD);
WiFi.softAP(WIFI_AP_SSID, mConfig->sys.apPwd);
}

Loading…
Cancel
Save