diff --git a/src/CHANGES.md b/src/CHANGES.md
index 29c3d999..414da944 100644
--- a/src/CHANGES.md
+++ b/src/CHANGES.md
@@ -1,5 +1,11 @@
# Changelog
+## 0.5.57
+* improved stability
+* added icons to index.html, added wifi-strength symbol on each page
+* moved packet stats and sun to system.html
+* refactored communication offset (adjustable in minutes now)
+
## 0.5.56
* factory reset formats entire little fs
* renamed sunrise / sunset on indext.html to start / stop communication
diff --git a/src/app.cpp b/src/app.cpp
index a2f7f93f..ed031d19 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -37,7 +37,7 @@ void app::setup() {
#if !defined(AP_ONLY)
- mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, mSys, &mTimestamp, &mSunrise, &mSunset);
+ mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, mSys, &mTimestamp);
#endif
mWifi.setup(mConfig, &mTimestamp);
@@ -126,7 +126,9 @@ void app::loop(void) {
mPayload.process(true, mConfig->nrf.maxRetransPerPyld, &mStat);
}
+#if !defined(AP_ONLY)
mMqtt.loop();
+#endif
}
//-----------------------------------------------------------------------------
@@ -149,9 +151,9 @@ void app::tickCalcSunrise(void) {
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 10) % 86400) + 86400; // next midnight, -10 for safety that it is certain next day
onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig);
if (mConfig->mqtt.broker[0] > 0) {
- once(std::bind(&PubMqttType::tickerSun, &mMqtt), 1);
- onceAt(std::bind(&PubMqttType::tickSunrise, &mMqtt), mSunrise);
- onceAt(std::bind(&PubMqttType::tickSunset, &mMqtt), mSunset);
+ mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec);
+ onceAt(std::bind(&PubMqttType::tickSunrise, &mMqtt), (mSunrise - mConfig->sun.offsetSec));
+ onceAt(std::bind(&PubMqttType::tickSunset, &mMqtt), (mSunset + mConfig->sun.offsetSec));
}
}
@@ -161,7 +163,7 @@ void app::tickSend(void) {
DPRINTLN(DBG_WARN, "NRF24 not connected!");
return;
}
- if ((mTimestamp > 0) && (!mConfig->sun.disNightCom || (mTimestamp >= mSunrise && mTimestamp <= mSunset))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set)
+ if ((mTimestamp > 0) && (!mConfig->sun.disNightCom || (mTimestamp >= (mSunrise - mConfig->sun.offsetSec) && mTimestamp <= (mSunset + mConfig->sun.offsetSec)))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set)
if (!mSys->BufCtrl.empty()) {
if (mConfig->serial.debug)
DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill()));
diff --git a/src/app.h b/src/app.h
index b7848224..c2d8a4e8 100644
--- a/src/app.h
+++ b/src/app.h
@@ -74,6 +74,7 @@ class app : public IApp, public ah::Scheduler {
}
bool saveSettings() {
+ mShowRebootRequest = true;
return mSettings.saveSettings();
}
diff --git a/src/config/settings.h b/src/config/settings.h
index e1cd449f..5eb317ad 100644
--- a/src/config/settings.h
+++ b/src/config/settings.h
@@ -55,6 +55,7 @@ typedef struct {
float lat;
float lon;
bool disNightCom; // disable night communication
+ uint16_t offsetSec;
} cfgSun_t;
typedef struct {
@@ -173,7 +174,7 @@ class settings {
//fp.seek(0, SeekSet);
DynamicJsonDocument root(4096);
DeserializationError err = deserializeJson(root, fp);
- if(!err) {
+ if(!err && (root.size() > 0)) {
mCfg.valid = true;
jsonWifi(root["wifi"]);
jsonNrf(root["nrf"]);
@@ -262,6 +263,7 @@ 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;
mCfg.serial.showIv = false;
@@ -334,13 +336,15 @@ class settings {
void jsonSun(JsonObject obj, bool set = false) {
if(set) {
- obj[F("lat")] = mCfg.sun.lat;
- obj[F("lon")] = mCfg.sun.lon;
- obj[F("dis")] = mCfg.sun.disNightCom;
+ 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 {
mCfg.sun.lat = obj[F("lat")];
mCfg.sun.lon = obj[F("lon")];
mCfg.sun.disNightCom = obj[F("dis")];
+ mCfg.sun.offsetSec = obj[F("offs")];
}
}
diff --git a/src/defines.h b/src/defines.h
index eca08e8e..56582290 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 5
-#define VERSION_PATCH 56
+#define VERSION_PATCH 57
//-------------------------------------
typedef struct {
diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h
index a28a6f04..e90aa095 100644
--- a/src/hm/hmRadio.h
+++ b/src/hm/hmRadio.h
@@ -297,6 +297,8 @@ class HmRadio {
}
uint8_t getDataRate(void) {
+ if(!mNrf24.isChipConnected())
+ return 3; // unkown
return mNrf24.getDataRate();
}
diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h
index 5338d1a0..dad8b4aa 100644
--- a/src/hm/hmSystem.h
+++ b/src/hm/hmSystem.h
@@ -104,8 +104,14 @@ class HmSystem {
}
uint8_t getNumInverters(void) {
- DPRINTLN(DBG_VERBOSE, F("hmSystem.h:getNumInverters"));
- return mNumInv;
+ uint8_t num = 0;
+ INVERTERTYPE *p;
+ for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
+ p = &mInverter[i];
+ if(p->config->serial.u64 != 0ULL)
+ num++;
+ }
+ return num;
}
void enableDebug() {
diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h
index cf98eec2..f67c1c00 100644
--- a/src/publisher/pubMqtt.h
+++ b/src/publisher/pubMqtt.h
@@ -40,14 +40,12 @@ class PubMqtt {
~PubMqtt() { }
- void setup(cfgMqtt_t *cfg_mqtt, const char *devName, const char *version, HMSYSTEM *sys, uint32_t *utcTs, uint32_t *sunrise, uint32_t *sunset) {
+ void setup(cfgMqtt_t *cfg_mqtt, const char *devName, const char *version, HMSYSTEM *sys, uint32_t *utcTs) {
mCfgMqtt = cfg_mqtt;
mDevName = devName;
mVersion = version;
mSys = sys;
mUtcTimestamp = utcTs;
- mSunrise = sunrise;
- mSunset = sunset;
snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic);
@@ -93,9 +91,11 @@ class PubMqtt {
tickSunset();
}
- void tickerSun() {
- publish("sunrise", String(*mSunrise).c_str(), true);
- publish("sunset", String(*mSunset).c_str(), true);
+ void tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs) {
+ publish("sunrise", String(sunrise).c_str(), true);
+ publish("sunset", String(sunset).c_str(), true);
+ publish("comm_start", String(sunrise - offs).c_str(), true);
+ publish("comm_stop", String(sunset + offs).c_str(), true);
}
void tickSunrise() {
@@ -505,7 +505,6 @@ class PubMqtt {
WiFiEventHandler mHWifiCon, mHWifiDiscon;
#endif
- uint32_t *mSunrise, *mSunset;
HMSYSTEM *mSys;
uint32_t *mUtcTimestamp;
uint32_t mRxCnt, mTxCnt;
diff --git a/src/utils/sun.h b/src/utils/sun.h
index 03a91f70..c66149c2 100644
--- a/src/utils/sun.h
+++ b/src/utils/sun.h
@@ -25,7 +25,7 @@ namespace ah {
// Declination of the sun
double delta = ASIN(SIN(lambda) * SIN(23.44));
// Hour angle
- double omega = ACOS((SIN(-3.5) - SIN(lat) * SIN(delta)) / (COS(lat) * COS(delta))); //(SIN(-0.83)
+ double omega = ACOS((SIN(-0.83) - SIN(lat) * SIN(delta)) / (COS(lat) * COS(delta)));
// Calculate sunrise and sunset
double Jrise = Jtransit - omega / 360;
double Jset = Jtransit + omega / 360;
diff --git a/src/web/RestApi.h b/src/web/RestApi.h
index 831f0f93..eb262aae 100644
--- a/src/web/RestApi.h
+++ b/src/web/RestApi.h
@@ -60,6 +60,7 @@ class RestApi {
else if(path == "html/logout") getHtmlLogout(root);
else if(path == "html/save") getHtmlSave(root);
else if(path == "system") getSysInfo(root);
+ else if(path == "generic") getGeneric(root);
else if(path == "reboot") getReboot(root);
else if(path == "statistics") getStatistics(root);
else if(path == "inverter/list") getInverterList(root);
@@ -144,17 +145,23 @@ class RestApi {
request->send(response);
}
+ void getGeneric(JsonObject obj) {
+ obj[F("version")] = String(mApp->getVersion());
+ obj[F("build")] = String(AUTO_GIT_HASH);
+ obj[F("wifi_rssi")] = (WiFi.status() != WL_CONNECTED) ? 0 : WiFi.RSSI();
+ obj[F("ts_uptime")] = mApp->getUptime();
+
+ #if defined(ESP32)
+ obj[F("esp_type")] = F("ESP32");
+ #else
+ obj[F("esp_type")] = F("ESP8266");
+ #endif
+ }
+
void getSysInfo(JsonObject obj) {
obj[F("ssid")] = mConfig->sys.stationSsid;
obj[F("device_name")] = mConfig->sys.deviceName;
- obj[F("version")] = String(mApp->getVersion());
- obj[F("build")] = String(AUTO_GIT_HASH);
- obj[F("ts_uptime")] = mApp->getUptime();
- obj[F("ts_now")] = mApp->getTimestamp();
- obj[F("ts_sunrise")] = mApp->getSunrise();
- obj[F("ts_sunset")] = mApp->getSunset();
- obj[F("wifi_rssi")] = WiFi.RSSI();
obj[F("mac")] = WiFi.macAddress();
obj[F("hostname")] = WiFi.getHostname();
obj[F("pwd_set")] = (strlen(mConfig->sys.adminPwd) > 0);
@@ -164,9 +171,10 @@ class RestApi {
obj[F("heap_free")] = ESP.getFreeHeap();
obj[F("sketch_total")] = ESP.getFreeSketchSpace();
obj[F("sketch_used")] = ESP.getSketchSize() / 1024; // in kb
-
+ getGeneric(obj);
getRadio(obj.createNestedObject(F("radio")));
+ getStatistics(obj.createNestedObject(F("statistics")));
#if defined(ESP32)
obj[F("heap_total")] = ESP.getHeapSize();
@@ -191,24 +199,19 @@ class RestApi {
#endif
//obj[F("littlefs_total")] = LittleFS.totalBytes();
//obj[F("littlefs_used")] = LittleFS.usedBytes();
-
- #if defined(ESP32)
- obj[F("esp_type")] = F("ESP32");
- #else
- obj[F("esp_type")] = F("ESP8266");
- #endif
}
void getHtmlSystem(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu")));
getSysInfo(obj.createNestedObject(F("system")));
+ getGeneric(obj.createNestedObject(F("generic")));
obj[F("html")] = F("Factory Reset
Reboot");
}
void getHtmlLogout(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu")));
- getSysInfo(obj.createNestedObject(F("system")));
+ getGeneric(obj.createNestedObject(F("generic")));
obj[F("refresh")] = 3;
obj[F("refresh_url")] = "/";
obj[F("html")] = F("succesfully logged out");
@@ -216,7 +219,7 @@ class RestApi {
void getHtmlSave(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu")));
- getSysInfo(obj.createNestedObject(F("system")));
+ getGeneric(obj.createNestedObject(F("generic")));
obj[F("refresh")] = 2;
obj[F("refresh_url")] = "/setup";
obj[F("html")] = F("settings succesfully save");
@@ -224,7 +227,7 @@ class RestApi {
void getReboot(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu")));
- getSysInfo(obj.createNestedObject(F("system")));
+ getGeneric(obj.createNestedObject(F("generic")));
obj[F("refresh")] = 10;
obj[F("refresh_url")] = "/";
obj[F("html")] = F("reboot. Autoreload after 10 seconds");
@@ -282,6 +285,7 @@ class RestApi {
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;
}
void getPinout(JsonObject obj) {
@@ -343,10 +347,12 @@ class RestApi {
void getIndex(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu")));
- getSysInfo(obj.createNestedObject(F("system")));
- getRadio(obj.createNestedObject(F("radio")));
- getStatistics(obj.createNestedObject(F("statistics")));
- obj["refresh_interval"] = mConfig->nrf.sendInterval;
+ getGeneric(obj.createNestedObject(F("generic")));
+
+ obj[F("ts_now")] = mApp->getTimestamp();
+ obj[F("ts_sunrise")] = mApp->getSunrise();
+ obj[F("ts_sunset")] = mApp->getSunset();
+ obj[F("ts_offset")] = mConfig->sun.offsetSec;
JsonArray inv = obj.createNestedArray(F("inverter"));
Inverter<> *iv;
@@ -369,22 +375,27 @@ class RestApi {
if(!mSys->Radio.isChipConnected())
warn.add(F("your NRF24 module can't be reached, check the wiring and pinout"));
else if(!mSys->Radio.isPVariant())
- warn.add(F("your NRF24 module isn't a plus version(+), maybe incompatible!"));
+ warn.add(F("your NRF24 module isn't a plus version(+), maybe incompatible"));
+ if(!mApp->getSettingsValid())
+ warn.add(F("your settings are invalid"));
+ if(mApp->getRebootRequestState())
+ warn.add(F("reboot your ESP to apply all your configuration changes"));
+ if(0 == mApp->getTimestamp())
+ warn.add(F("time not set. No communication to inverter possible"));
+ /*if(0 == mSys->getNumInverters())
+ warn.add(F("no inverter configured"));*/
if((!mApp->getMqttIsConnected()) && (String(mConfig->mqtt.broker).length() > 0))
warn.add(F("MQTT is not connected"));
JsonArray info = obj.createNestedArray(F("infos"));
- if(mApp->getRebootRequestState())
- info.add(F("reboot your ESP to apply all your configuration changes!"));
- if(!mApp->getSettingsValid())
- info.add(F("your settings are invalid"));
if(mApp->getMqttIsConnected())
info.add(F("MQTT is connected, ") + String(mApp->getMqttTxCnt()) + F(" packets sent, ") + String(mApp->getMqttRxCnt()) + F(" packets received"));
}
void getSetup(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu")));
+ getGeneric(obj.createNestedObject(F("generic")));
getSysInfo(obj.createNestedObject(F("system")));
getInverterList(obj.createNestedObject(F("inverter")));
getMqtt(obj.createNestedObject(F("mqtt")));
@@ -402,7 +413,7 @@ class RestApi {
void getLive(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu")));
- getSysInfo(obj.createNestedObject(F("system")));
+ getGeneric(obj.createNestedObject(F("generic")));
JsonArray invArr = obj.createNestedArray(F("inverter"));
obj["refresh_interval"] = mConfig->nrf.sendInterval;
diff --git a/src/web/html/api.js b/src/web/html/api.js
index d74fb0b7..0606dfa8 100644
--- a/src/web/html/api.js
+++ b/src/web/html/api.js
@@ -1,4 +1,36 @@
/**
+ * SVG ICONS
+ */
+
+iconWifi1 = [
+ "M11.046 10.454c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.407.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.611-.091l.015-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .707 0l.708-.707z"
+];
+
+iconWifi2 = [
+ "M13.229 8.271c.216-.216.194-.578-.063-.745A9.456 9.456 0 0 0 8 6c-1.905 0-3.68.56-5.166 1.526a.48.48 0 0 0-.063.745.525.525 0 0 0 .652.065A8.46 8.46 0 0 1 8 7a8.46 8.46 0 0 1 4.577 1.336c.205.132.48.108.652-.065zm-2.183 2.183c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.408.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.611-.091l.015-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .708 0l.707-.707z"
+];
+
+iconWifi3 = [
+ "M15.384 6.115a.485.485 0 0 0-.047-.736A12.444 12.444 0 0 0 8 3C5.259 3 2.723 3.882.663 5.379a.485.485 0 0 0-.048.736.518.518 0 0 0 .668.05A11.448 11.448 0 0 1 8 4c2.507 0 4.827.802 6.716 2.164.205.148.49.13.668-.049z",
+ "M13.229 8.271a.482.482 0 0 0-.063-.745A9.455 9.455 0 0 0 8 6c-1.905 0-3.68.56-5.166 1.526a.48.48 0 0 0-.063.745.525.525 0 0 0 .652.065A8.46 8.46 0 0 1 8 7a8.46 8.46 0 0 1 4.576 1.336c.206.132.48.108.653-.065zm-2.183 2.183c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.407.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.61-.091l.016-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .707 0l.707-.707z"
+];
+
+iconWarn = [
+ "M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z",
+ "M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"
+];
+
+iconInfo = [
+ "M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z",
+ "m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"
+];
+
+iconSuccess = [
+ "M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z",
+ "M10.97 4.97a.235.235 0 0 0-.02.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05z"
+];
+
+ /**
* GENERIC FUNCTIONS
*/
@@ -31,6 +63,15 @@ function parseESP(obj) {
document.getElementById("esp_type").innerHTML="Board: " + obj["esp_type"];
}
+function parseRssi(obj) {
+ var icon = iconWifi3;
+ if(obj["wifi_rssi"] <= -80)
+ icon = iconWifi1;
+ else if(obj["wifi_rssi"] <= -70)
+ icon = iconWifi2;
+ document.getElementById("wifiicon").replaceChildren(svg(icon, 32, 32, "#fff", null, obj["wifi_rssi"]));
+}
+
function setHide(id, hide) {
var elm = document.getElementById(id);
if(hide) {
@@ -99,15 +140,11 @@ function inp(name, val, max=32, cl=["text"], id=null, type=null) {
return e;
}
-function sel(name, opt, selId) {
+function sel(name, options, selId) {
e = document.createElement('select');
e.name = name;
- for(it of opt) {
- o = document.createElement('option');
- o.value = it[0];
- o.innerHTML = it[1];
- if(it[0] == selId)
- o.selected = true;
+ for(it of options) {
+ o = opt(it[0], it[1], (it[0] == selId));
e.appendChild(o);
}
return e;
@@ -120,11 +157,12 @@ function selDelAllOpt(sel) {
}
}
-function opt(val, html) {
+function opt(val, html, sel=false) {
o = document.createElement('option');
o.value = val;
o.innerHTML = html;
- e.appendChild(o);
+ if(sel)
+ o.selected = true;
return o;
}
@@ -156,3 +194,25 @@ function link(dst, text, target=null) {
a.appendChild(t);
return a;
}
+
+function svg(data=null, w=24, h=24, color="#000", cl=null, tooltip=null) {
+ var s = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ s.setAttribute('width', w);
+ s.setAttribute('height', h);
+ s.setAttribute('fill', color);
+ s.setAttribute('viewBox', '0 0 16 16');
+ if(null != cl) s.setAttribute('class', cl);
+ if(null != data) {
+ for(const e of data) {
+ const i = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ i.setAttribute('d', e);
+ s.appendChild(i);
+ }
+ }
+ if(null != tooltip) {
+ const t = document.createElement("title");
+ t.appendChild(document.createTextNode(tooltip));
+ s.appendChild(t);
+ }
+ return s;
+}
diff --git a/src/web/html/index.html b/src/web/html/index.html
index d626f25a..065f5f8d 100644
--- a/src/web/html/index.html
+++ b/src/web/html/index.html
@@ -15,6 +15,7 @@
+
@@ -35,23 +36,18 @@
Uptime:
ESP-Time:
-
- Communication
- start:
- stop:
-
-
WiFi RSSI: dBm
- System Infos:
-
-
-
+
System Infos:
+
+
+
+
- Discuss with us on
Discord
Support this project:
+ - Discuss with us on Discord
- Report issues
- Contribute to documentation
- Test development firmware
@@ -83,6 +79,7 @@
var exeOnce = true;
var tickCnt = 0;
var ts = 0;
+ var commInfo = "";
function apiCb(obj) {
var e = document.getElementById("apiResult");
@@ -102,24 +99,28 @@
getAjax("/api/setup", apiCb, "POST", JSON.stringify(obj));
}
- function parseSys(obj) {
+ function ts2Span(ts) {
+ return span(new Date(ts * 1000).toLocaleString('de-DE'));
+ }
+
+ function parseGeneric(obj) {
// Disclaimer
//if(obj["disclaimer"] == false) sessionStorage.setItem("gDisclaimer", promptFunction());
if(exeOnce){
parseVersion(obj);
parseESP(obj);
}
- document.getElementById("wifi_rssi").innerHTML = obj["wifi_rssi"];
+ parseRssi(obj);
+ }
+ function parseSys(obj) {
ts = obj["ts_now"];
var date = new Date(obj["ts_now"] * 1000);
- var up = obj["ts_uptime"];
+ var up = obj["generic"]["ts_uptime"];
var days = parseInt(up / 86400) % 365;
var hrs = parseInt(up / 3600) % 24;
var min = parseInt(up / 60) % 60;
var sec = up % 60;
- var sunrise = new Date(obj["ts_sunrise"] * 1000);
- var sunset = new Date(obj["ts_sunset"] * 1000);
var e = document.getElementById("uptime");
e.innerHTML = days + " Day";
if(1 != days)
@@ -139,60 +140,73 @@
e.addEventListener("click", setTime);
}
- if(0 == obj["ts_sunrise"]) {
- var e = document.getElementById("sun");
- if(null != e)
- e.parentNode.removeChild(e);
- }
- else {
- document.getElementById("sunrise").innerHTML = sunrise.toLocaleString('de-DE');
- document.getElementById("sunset").innerHTML = sunset.toLocaleString('de-DE');
+ if(obj["ts_sunrise"] > 0) {
+ if(((obj["ts_sunrise"] - obj["ts_offset"]) < obj["ts_now"])
+ && ((obj["ts_sunset"] + obj["ts_offset"]) > obj["ts_now"])) {
+ commInfo = "Polling inverter(s), will stop at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE'));
+ }
+ else {
+ commInfo = "Night time, no Communication to Inverter, ";
+ if(obj["ts_now"] > (obj["ts_sunrise"] - obj["ts_offset"])) {
+ commInfo += "stopped polling at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE'));
+ }
+ else {
+ commInfo += "will start polling at " + (new Date((obj["ts_sunrise"] - obj["ts_offset"]) * 1000).toLocaleString('de-DE'));
+ }
+ }
}
}
- function parseStat(obj) {
- document.getElementById("stat").innerHTML = "RX success: " + obj["rx_success"]
- + "\nRX fail: " + obj["rx_fail"]
- + "\nRX no answer: " + obj["rx_fail_answer"]
- + "\nFrames received: " + obj["frame_cnt"]
- + "\nTX cnt: " + obj["tx_cnt"];
- }
-
function parseIv(obj) {
- var html = "";
+ var p = div(["none"]);
for(var i of obj) {
- html += "Inverter #" + i["id"] + ": " + i["name"] + " (v" + i["version"] + ") is ";
- if(false == i["is_avail"])
- html += "not yet available\n";
+ var icon = iconWarn;
+ var color = "#F70";
+ avail = "";
+ if(false == i["enabled"]) {
+ avail = "disabled";
+ }
+ else if(false == i["is_avail"]) {
+ icon = iconInfo;
+ color = "#00d";
+ avail = "not yet available";
+ }
else {
- html += "available and is ";
+ icon = iconSuccess;
+ avail = "available and is ";
if(false == i["is_producing"])
- html += "not ";
- html += "producing\n";
+ avail += "not ";
+ avail += "producing";
}
+ p.append(
+ svg(icon, 20, 20, color, "icon"),
+ span("Inverter #" + i["id"] + ": " + i["name"] + " (v" + i["version"] + ") is " + avail),
+ br()
+ );
+
if(false == i["is_avail"]) {
if(i["ts_last_success"] > 0) {
var date = new Date(i["ts_last_success"] * 1000);
- html += "-> last successful transmission: " + date.toLocaleString('de-DE') + "\n";
+ p.append(span("-> last successful transmission: " + date.toLocaleString('de-DE')), br());
}
}
- if(false == i["enabled"])
- html += "-> disabled\n";
-
}
- document.getElementById("iv").innerHTML = html;
+ document.getElementById("iv").replaceChildren(p);
}
- function parseWarnInfo(warn, info) {
- var html = "";
+ function parseWarnInfo(warn, success) {
+ var p = div(["none"]);
for(var w of warn) {
- html += "WARN: " + w + "\n";
+ p.append(svg(iconWarn, 20, 20, "#F70", "icon"), span(w), br());
}
- for(var i of info) {
- html += "INFO: " + i + "\n";
+ for(var i of success) {
+ p.append(svg(iconSuccess, 20, 20, "#090", "icon"), span(i), br());
}
- document.getElementById("warn_info").innerHTML = html;
+
+ if(commInfo.length > 0)
+ p.append(svg(iconInfo, 20, 20, "#00d", "icon"), span(commInfo), br());
+ document.getElementById("warn_info").replaceChildren(p);
}
function tick() {
@@ -208,8 +222,8 @@
if(null != obj) {
if(exeOnce)
parseMenu(obj["menu"]);
- parseSys(obj["system"]);
- parseStat(obj["statistics"]);
+ parseGeneric(obj["generic"]);
+ parseSys(obj);
parseIv(obj["inverter"]);
parseWarnInfo(obj["warnings"], obj["infos"]);
if(exeOnce) {
@@ -217,8 +231,6 @@
exeOnce = false;
}
}
- else
- document.getElementById("refresh").innerHTML = "n/a";
}
getAjax("/api/index", parse);
diff --git a/src/web/html/login.html b/src/web/html/login.html
index 68f44084..6161461f 100644
--- a/src/web/html/login.html
+++ b/src/web/html/login.html
@@ -33,10 +33,10 @@