Browse Source

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)
pull/518/head
lumapu 2 years ago
parent
commit
5977bbaee6
  1. 6
      src/CHANGES.md
  2. 12
      src/app.cpp
  3. 1
      src/app.h
  4. 12
      src/config/settings.h
  5. 2
      src/defines.h
  6. 2
      src/hm/hmRadio.h
  7. 10
      src/hm/hmSystem.h
  8. 13
      src/publisher/pubMqtt.h
  9. 2
      src/utils/sun.h
  10. 65
      src/web/RestApi.h
  11. 78
      src/web/html/api.js
  12. 120
      src/web/html/index.html
  13. 4
      src/web/html/login.html
  14. 8
      src/web/html/serial.html
  15. 14
      src/web/html/setup.html
  16. 40
      src/web/html/style.css
  17. 43
      src/web/html/system.html
  18. 6
      src/web/html/update.html
  19. 8
      src/web/html/visualization.html
  20. 2
      src/web/web.h

6
src/CHANGES.md

@ -1,5 +1,11 @@
# Changelog # 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 ## 0.5.56
* factory reset formats entire little fs * factory reset formats entire little fs
* renamed sunrise / sunset on indext.html to start / stop communication * renamed sunrise / sunset on indext.html to start / stop communication

12
src/app.cpp

@ -37,7 +37,7 @@ void app::setup() {
#if !defined(AP_ONLY) #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 #endif
mWifi.setup(mConfig, &mTimestamp); mWifi.setup(mConfig, &mTimestamp);
@ -126,7 +126,9 @@ void app::loop(void) {
mPayload.process(true, mConfig->nrf.maxRetransPerPyld, &mStat); mPayload.process(true, mConfig->nrf.maxRetransPerPyld, &mStat);
} }
#if !defined(AP_ONLY)
mMqtt.loop(); 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 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); onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig);
if (mConfig->mqtt.broker[0] > 0) { if (mConfig->mqtt.broker[0] > 0) {
once(std::bind(&PubMqttType::tickerSun, &mMqtt), 1); mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec);
onceAt(std::bind(&PubMqttType::tickSunrise, &mMqtt), mSunrise); onceAt(std::bind(&PubMqttType::tickSunrise, &mMqtt), (mSunrise - mConfig->sun.offsetSec));
onceAt(std::bind(&PubMqttType::tickSunset, &mMqtt), mSunset); onceAt(std::bind(&PubMqttType::tickSunset, &mMqtt), (mSunset + mConfig->sun.offsetSec));
} }
} }
@ -161,7 +163,7 @@ void app::tickSend(void) {
DPRINTLN(DBG_WARN, "NRF24 not connected!"); DPRINTLN(DBG_WARN, "NRF24 not connected!");
return; 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 (!mSys->BufCtrl.empty()) {
if (mConfig->serial.debug) if (mConfig->serial.debug)
DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill())); DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill()));

1
src/app.h

@ -74,6 +74,7 @@ class app : public IApp, public ah::Scheduler {
} }
bool saveSettings() { bool saveSettings() {
mShowRebootRequest = true;
return mSettings.saveSettings(); return mSettings.saveSettings();
} }

12
src/config/settings.h

@ -55,6 +55,7 @@ typedef struct {
float lat; float lat;
float lon; float lon;
bool disNightCom; // disable night communication bool disNightCom; // disable night communication
uint16_t offsetSec;
} cfgSun_t; } cfgSun_t;
typedef struct { typedef struct {
@ -173,7 +174,7 @@ class settings {
//fp.seek(0, SeekSet); //fp.seek(0, SeekSet);
DynamicJsonDocument root(4096); DynamicJsonDocument root(4096);
DeserializationError err = deserializeJson(root, fp); DeserializationError err = deserializeJson(root, fp);
if(!err) { if(!err && (root.size() > 0)) {
mCfg.valid = true; mCfg.valid = true;
jsonWifi(root["wifi"]); jsonWifi(root["wifi"]);
jsonNrf(root["nrf"]); jsonNrf(root["nrf"]);
@ -262,6 +263,7 @@ class settings {
mCfg.sun.lat = 0.0; mCfg.sun.lat = 0.0;
mCfg.sun.lon = 0.0; mCfg.sun.lon = 0.0;
mCfg.sun.disNightCom = false; mCfg.sun.disNightCom = false;
mCfg.sun.offsetSec = 0;
mCfg.serial.interval = SERIAL_INTERVAL; mCfg.serial.interval = SERIAL_INTERVAL;
mCfg.serial.showIv = false; mCfg.serial.showIv = false;
@ -334,13 +336,15 @@ class settings {
void jsonSun(JsonObject obj, bool set = false) { void jsonSun(JsonObject obj, bool set = false) {
if(set) { if(set) {
obj[F("lat")] = mCfg.sun.lat; obj[F("lat")] = mCfg.sun.lat;
obj[F("lon")] = mCfg.sun.lon; obj[F("lon")] = mCfg.sun.lon;
obj[F("dis")] = mCfg.sun.disNightCom; obj[F("dis")] = mCfg.sun.disNightCom;
obj[F("offs")] = mCfg.sun.offsetSec;
} else { } else {
mCfg.sun.lat = obj[F("lat")]; mCfg.sun.lat = obj[F("lat")];
mCfg.sun.lon = obj[F("lon")]; mCfg.sun.lon = obj[F("lon")];
mCfg.sun.disNightCom = obj[F("dis")]; mCfg.sun.disNightCom = obj[F("dis")];
mCfg.sun.offsetSec = obj[F("offs")];
} }
} }

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 56 #define VERSION_PATCH 57
//------------------------------------- //-------------------------------------
typedef struct { typedef struct {

2
src/hm/hmRadio.h

@ -297,6 +297,8 @@ class HmRadio {
} }
uint8_t getDataRate(void) { uint8_t getDataRate(void) {
if(!mNrf24.isChipConnected())
return 3; // unkown
return mNrf24.getDataRate(); return mNrf24.getDataRate();
} }

10
src/hm/hmSystem.h

@ -104,8 +104,14 @@ class HmSystem {
} }
uint8_t getNumInverters(void) { uint8_t getNumInverters(void) {
DPRINTLN(DBG_VERBOSE, F("hmSystem.h:getNumInverters")); uint8_t num = 0;
return mNumInv; 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() { void enableDebug() {

13
src/publisher/pubMqtt.h

@ -40,14 +40,12 @@ class PubMqtt {
~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; mCfgMqtt = cfg_mqtt;
mDevName = devName; mDevName = devName;
mVersion = version; mVersion = version;
mSys = sys; mSys = sys;
mUtcTimestamp = utcTs; mUtcTimestamp = utcTs;
mSunrise = sunrise;
mSunset = sunset;
snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic); snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic);
@ -93,9 +91,11 @@ class PubMqtt {
tickSunset(); tickSunset();
} }
void tickerSun() { void tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs) {
publish("sunrise", String(*mSunrise).c_str(), true); publish("sunrise", String(sunrise).c_str(), true);
publish("sunset", String(*mSunset).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() { void tickSunrise() {
@ -505,7 +505,6 @@ class PubMqtt {
WiFiEventHandler mHWifiCon, mHWifiDiscon; WiFiEventHandler mHWifiCon, mHWifiDiscon;
#endif #endif
uint32_t *mSunrise, *mSunset;
HMSYSTEM *mSys; HMSYSTEM *mSys;
uint32_t *mUtcTimestamp; uint32_t *mUtcTimestamp;
uint32_t mRxCnt, mTxCnt; uint32_t mRxCnt, mTxCnt;

2
src/utils/sun.h

@ -25,7 +25,7 @@ namespace ah {
// Declination of the sun // Declination of the sun
double delta = ASIN(SIN(lambda) * SIN(23.44)); double delta = ASIN(SIN(lambda) * SIN(23.44));
// Hour angle // 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 // Calculate sunrise and sunset
double Jrise = Jtransit - omega / 360; double Jrise = Jtransit - omega / 360;
double Jset = Jtransit + omega / 360; double Jset = Jtransit + omega / 360;

65
src/web/RestApi.h

@ -60,6 +60,7 @@ class RestApi {
else if(path == "html/logout") getHtmlLogout(root); else if(path == "html/logout") getHtmlLogout(root);
else if(path == "html/save") getHtmlSave(root); else if(path == "html/save") getHtmlSave(root);
else if(path == "system") getSysInfo(root); else if(path == "system") getSysInfo(root);
else if(path == "generic") getGeneric(root);
else if(path == "reboot") getReboot(root); else if(path == "reboot") getReboot(root);
else if(path == "statistics") getStatistics(root); else if(path == "statistics") getStatistics(root);
else if(path == "inverter/list") getInverterList(root); else if(path == "inverter/list") getInverterList(root);
@ -144,17 +145,23 @@ class RestApi {
request->send(response); 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) { void getSysInfo(JsonObject obj) {
obj[F("ssid")] = mConfig->sys.stationSsid; obj[F("ssid")] = mConfig->sys.stationSsid;
obj[F("device_name")] = mConfig->sys.deviceName; 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("mac")] = WiFi.macAddress();
obj[F("hostname")] = WiFi.getHostname(); obj[F("hostname")] = WiFi.getHostname();
obj[F("pwd_set")] = (strlen(mConfig->sys.adminPwd) > 0); obj[F("pwd_set")] = (strlen(mConfig->sys.adminPwd) > 0);
@ -164,9 +171,10 @@ class RestApi {
obj[F("heap_free")] = ESP.getFreeHeap(); obj[F("heap_free")] = ESP.getFreeHeap();
obj[F("sketch_total")] = ESP.getFreeSketchSpace(); obj[F("sketch_total")] = ESP.getFreeSketchSpace();
obj[F("sketch_used")] = ESP.getSketchSize() / 1024; // in kb obj[F("sketch_used")] = ESP.getSketchSize() / 1024; // in kb
getGeneric(obj);
getRadio(obj.createNestedObject(F("radio"))); getRadio(obj.createNestedObject(F("radio")));
getStatistics(obj.createNestedObject(F("statistics")));
#if defined(ESP32) #if defined(ESP32)
obj[F("heap_total")] = ESP.getHeapSize(); obj[F("heap_total")] = ESP.getHeapSize();
@ -191,24 +199,19 @@ class RestApi {
#endif #endif
//obj[F("littlefs_total")] = LittleFS.totalBytes(); //obj[F("littlefs_total")] = LittleFS.totalBytes();
//obj[F("littlefs_used")] = LittleFS.usedBytes(); //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) { void getHtmlSystem(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu"))); getMenu(obj.createNestedObject(F("menu")));
getSysInfo(obj.createNestedObject(F("system"))); getSysInfo(obj.createNestedObject(F("system")));
getGeneric(obj.createNestedObject(F("generic")));
obj[F("html")] = F("<a href=\"/factory\" class=\"btn\">Factory Reset</a><br/><br/><a href=\"/reboot\" class=\"btn\">Reboot</a>"); obj[F("html")] = F("<a href=\"/factory\" class=\"btn\">Factory Reset</a><br/><br/><a href=\"/reboot\" class=\"btn\">Reboot</a>");
} }
void getHtmlLogout(JsonObject obj) { void getHtmlLogout(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu"))); getMenu(obj.createNestedObject(F("menu")));
getSysInfo(obj.createNestedObject(F("system"))); getGeneric(obj.createNestedObject(F("generic")));
obj[F("refresh")] = 3; obj[F("refresh")] = 3;
obj[F("refresh_url")] = "/"; obj[F("refresh_url")] = "/";
obj[F("html")] = F("succesfully logged out"); obj[F("html")] = F("succesfully logged out");
@ -216,7 +219,7 @@ class RestApi {
void getHtmlSave(JsonObject obj) { void getHtmlSave(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu"))); getMenu(obj.createNestedObject(F("menu")));
getSysInfo(obj.createNestedObject(F("system"))); getGeneric(obj.createNestedObject(F("generic")));
obj[F("refresh")] = 2; obj[F("refresh")] = 2;
obj[F("refresh_url")] = "/setup"; obj[F("refresh_url")] = "/setup";
obj[F("html")] = F("settings succesfully save"); obj[F("html")] = F("settings succesfully save");
@ -224,7 +227,7 @@ class RestApi {
void getReboot(JsonObject obj) { void getReboot(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu"))); getMenu(obj.createNestedObject(F("menu")));
getSysInfo(obj.createNestedObject(F("system"))); getGeneric(obj.createNestedObject(F("generic")));
obj[F("refresh")] = 10; obj[F("refresh")] = 10;
obj[F("refresh_url")] = "/"; obj[F("refresh_url")] = "/";
obj[F("html")] = F("reboot. Autoreload after 10 seconds"); 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("lat")] = mConfig->sun.lat ? String(mConfig->sun.lat, 5) : "";
obj[F("lon")] = mConfig->sun.lat ? String(mConfig->sun.lon, 5) : ""; obj[F("lon")] = mConfig->sun.lat ? String(mConfig->sun.lon, 5) : "";
obj[F("disnightcom")] = mConfig->sun.disNightCom; obj[F("disnightcom")] = mConfig->sun.disNightCom;
obj[F("offs")] = mConfig->sun.offsetSec;
} }
void getPinout(JsonObject obj) { void getPinout(JsonObject obj) {
@ -343,10 +347,12 @@ class RestApi {
void getIndex(JsonObject obj) { void getIndex(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu"))); getMenu(obj.createNestedObject(F("menu")));
getSysInfo(obj.createNestedObject(F("system"))); getGeneric(obj.createNestedObject(F("generic")));
getRadio(obj.createNestedObject(F("radio")));
getStatistics(obj.createNestedObject(F("statistics"))); obj[F("ts_now")] = mApp->getTimestamp();
obj["refresh_interval"] = mConfig->nrf.sendInterval; 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")); JsonArray inv = obj.createNestedArray(F("inverter"));
Inverter<> *iv; Inverter<> *iv;
@ -369,22 +375,27 @@ class RestApi {
if(!mSys->Radio.isChipConnected()) if(!mSys->Radio.isChipConnected())
warn.add(F("your NRF24 module can't be reached, check the wiring and pinout")); warn.add(F("your NRF24 module can't be reached, check the wiring and pinout"));
else if(!mSys->Radio.isPVariant()) 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)) if((!mApp->getMqttIsConnected()) && (String(mConfig->mqtt.broker).length() > 0))
warn.add(F("MQTT is not connected")); warn.add(F("MQTT is not connected"));
JsonArray info = obj.createNestedArray(F("infos")); 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()) if(mApp->getMqttIsConnected())
info.add(F("MQTT is connected, ") + String(mApp->getMqttTxCnt()) + F(" packets sent, ") + String(mApp->getMqttRxCnt()) + F(" packets received")); info.add(F("MQTT is connected, ") + String(mApp->getMqttTxCnt()) + F(" packets sent, ") + String(mApp->getMqttRxCnt()) + F(" packets received"));
} }
void getSetup(JsonObject obj) { void getSetup(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu"))); getMenu(obj.createNestedObject(F("menu")));
getGeneric(obj.createNestedObject(F("generic")));
getSysInfo(obj.createNestedObject(F("system"))); getSysInfo(obj.createNestedObject(F("system")));
getInverterList(obj.createNestedObject(F("inverter"))); getInverterList(obj.createNestedObject(F("inverter")));
getMqtt(obj.createNestedObject(F("mqtt"))); getMqtt(obj.createNestedObject(F("mqtt")));
@ -402,7 +413,7 @@ class RestApi {
void getLive(JsonObject obj) { void getLive(JsonObject obj) {
getMenu(obj.createNestedObject(F("menu"))); getMenu(obj.createNestedObject(F("menu")));
getSysInfo(obj.createNestedObject(F("system"))); getGeneric(obj.createNestedObject(F("generic")));
JsonArray invArr = obj.createNestedArray(F("inverter")); JsonArray invArr = obj.createNestedArray(F("inverter"));
obj["refresh_interval"] = mConfig->nrf.sendInterval; obj["refresh_interval"] = mConfig->nrf.sendInterval;

78
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 * GENERIC FUNCTIONS
*/ */
@ -31,6 +63,15 @@ function parseESP(obj) {
document.getElementById("esp_type").innerHTML="Board: " + obj["esp_type"]; 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) { function setHide(id, hide) {
var elm = document.getElementById(id); var elm = document.getElementById(id);
if(hide) { if(hide) {
@ -99,15 +140,11 @@ function inp(name, val, max=32, cl=["text"], id=null, type=null) {
return e; return e;
} }
function sel(name, opt, selId) { function sel(name, options, selId) {
e = document.createElement('select'); e = document.createElement('select');
e.name = name; e.name = name;
for(it of opt) { for(it of options) {
o = document.createElement('option'); o = opt(it[0], it[1], (it[0] == selId));
o.value = it[0];
o.innerHTML = it[1];
if(it[0] == selId)
o.selected = true;
e.appendChild(o); e.appendChild(o);
} }
return e; return e;
@ -120,11 +157,12 @@ function selDelAllOpt(sel) {
} }
} }
function opt(val, html) { function opt(val, html, sel=false) {
o = document.createElement('option'); o = document.createElement('option');
o.value = val; o.value = val;
o.innerHTML = html; o.innerHTML = html;
e.appendChild(o); if(sel)
o.selected = true;
return o; return o;
} }
@ -156,3 +194,25 @@ function link(dst, text, target=null) {
a.appendChild(t); a.appendChild(t);
return a; 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;
}

120
src/web/html/index.html

@ -15,6 +15,7 @@
<span></span> <span></span>
</a> </a>
<div id="topnav" class="hide"></div> <div id="topnav" class="hide"></div>
<div id="wifiicon" class="info"></div>
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
@ -35,23 +36,18 @@
<span class="des">Uptime: </span><span id="uptime"></span><br/> <span class="des">Uptime: </span><span id="uptime"></span><br/>
<span class="des">ESP-Time: </span><span id="date"></span> <span class="des">ESP-Time: </span><span id="date"></span>
</p> </p>
<div id="sun">
<span class="des">Communication</span><br/>
<span class="des">start: </span><span id="sunrise"></span><br>
<span class="des">stop: </span><span id="sunset"></span>
</div>
<p><span class="des">WiFi RSSI: </span><span id="wifi_rssi"></span> dBm</p>
<p> <p>
<span class="des">System Infos: </span> <span class="des">System Infos:</span>
<pre id="stat"></pre> <div id="iv"></div>
<pre id="iv"></pre> <div class="hr"></div>
<pre id="warn_info"></pre> <div id="warn_info"></div>
</p> </p>
<div class="hr"></div>
<div id="note"> <div id="note">
Discuss with us on <a href="https://discord.gg/WzhxEY62mB">Discord</a><br/>
<h3>Support this project:</h3> <h3>Support this project:</h3>
<ul> <ul>
<li>Discuss with us on <a href="https://discord.gg/WzhxEY62mB">Discord</a></li>
<li>Report <a href="https://github.com/lumapu/ahoy/issues" target="_blank">issues</a></li> <li>Report <a href="https://github.com/lumapu/ahoy/issues" target="_blank">issues</a></li>
<li>Contribute to <a href="https://github.com/lumapu/ahoy/blob/main/User_Manual.md" target="_blank">documentation</a></li> <li>Contribute to <a href="https://github.com/lumapu/ahoy/blob/main/User_Manual.md" target="_blank">documentation</a></li>
<li>Test <a href="https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml" target="_blank">development firmware</a></li> <li>Test <a href="https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml" target="_blank">development firmware</a></li>
@ -83,6 +79,7 @@
var exeOnce = true; var exeOnce = true;
var tickCnt = 0; var tickCnt = 0;
var ts = 0; var ts = 0;
var commInfo = "";
function apiCb(obj) { function apiCb(obj) {
var e = document.getElementById("apiResult"); var e = document.getElementById("apiResult");
@ -102,24 +99,28 @@
getAjax("/api/setup", apiCb, "POST", JSON.stringify(obj)); 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 // Disclaimer
//if(obj["disclaimer"] == false) sessionStorage.setItem("gDisclaimer", promptFunction()); //if(obj["disclaimer"] == false) sessionStorage.setItem("gDisclaimer", promptFunction());
if(exeOnce){ if(exeOnce){
parseVersion(obj); parseVersion(obj);
parseESP(obj); parseESP(obj);
} }
document.getElementById("wifi_rssi").innerHTML = obj["wifi_rssi"]; parseRssi(obj);
}
function parseSys(obj) {
ts = obj["ts_now"]; ts = obj["ts_now"];
var date = new Date(obj["ts_now"] * 1000); 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 days = parseInt(up / 86400) % 365;
var hrs = parseInt(up / 3600) % 24; var hrs = parseInt(up / 3600) % 24;
var min = parseInt(up / 60) % 60; var min = parseInt(up / 60) % 60;
var sec = up % 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"); var e = document.getElementById("uptime");
e.innerHTML = days + " Day"; e.innerHTML = days + " Day";
if(1 != days) if(1 != days)
@ -139,60 +140,73 @@
e.addEventListener("click", setTime); e.addEventListener("click", setTime);
} }
if(0 == obj["ts_sunrise"]) { if(obj["ts_sunrise"] > 0) {
var e = document.getElementById("sun"); if(((obj["ts_sunrise"] - obj["ts_offset"]) < obj["ts_now"])
if(null != e) && ((obj["ts_sunset"] + obj["ts_offset"]) > obj["ts_now"])) {
e.parentNode.removeChild(e); commInfo = "Polling inverter(s), will stop at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE'));
} }
else { else {
document.getElementById("sunrise").innerHTML = sunrise.toLocaleString('de-DE'); commInfo = "Night time, no Communication to Inverter, ";
document.getElementById("sunset").innerHTML = sunset.toLocaleString('de-DE'); 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) { function parseIv(obj) {
var html = ""; var p = div(["none"]);
for(var i of obj) { for(var i of obj) {
html += "Inverter #" + i["id"] + ": " + i["name"] + " (v" + i["version"] + ") is "; var icon = iconWarn;
if(false == i["is_avail"]) var color = "#F70";
html += "not yet available\n"; avail = "";
if(false == i["enabled"]) {
avail = "disabled";
}
else if(false == i["is_avail"]) {
icon = iconInfo;
color = "#00d";
avail = "not yet available";
}
else { else {
html += "available and is "; icon = iconSuccess;
avail = "available and is ";
if(false == i["is_producing"]) if(false == i["is_producing"])
html += "not "; avail += "not ";
html += "producing\n"; 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(false == i["is_avail"]) {
if(i["ts_last_success"] > 0) { if(i["ts_last_success"] > 0) {
var date = new Date(i["ts_last_success"] * 1000); 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) { function parseWarnInfo(warn, success) {
var html = ""; var p = div(["none"]);
for(var w of warn) { 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) { for(var i of success) {
html += "INFO: " + i + "\n"; 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() { function tick() {
@ -208,8 +222,8 @@
if(null != obj) { if(null != obj) {
if(exeOnce) if(exeOnce)
parseMenu(obj["menu"]); parseMenu(obj["menu"]);
parseSys(obj["system"]); parseGeneric(obj["generic"]);
parseStat(obj["statistics"]); parseSys(obj);
parseIv(obj["inverter"]); parseIv(obj["inverter"]);
parseWarnInfo(obj["warnings"], obj["infos"]); parseWarnInfo(obj["warnings"], obj["infos"]);
if(exeOnce) { if(exeOnce) {
@ -217,8 +231,6 @@
exeOnce = false; exeOnce = false;
} }
} }
else
document.getElementById("refresh").innerHTML = "n/a";
} }
getAjax("/api/index", parse); getAjax("/api/index", parse);

4
src/web/html/login.html

@ -33,10 +33,10 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
function parse(obj) { function parse(obj) {
parseVersion(obj["system"]); parseVersion(obj["general"]);
} }
getAjax("/api/index", parse); getAjax("/api/generic", parse);
</script> </script>
</body> </body>
</html> </html>

8
src/web/html/serial.html

@ -15,6 +15,7 @@
<span></span> <span></span>
</a> </a>
<div id="topnav" class="hide"></div> <div id="topnav" class="hide"></div>
<div id="wifiicon" class="info"></div>
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
@ -83,7 +84,7 @@
var con = document.getElementById("serial"); var con = document.getElementById("serial");
var exeOnce = true; var exeOnce = true;
function parseSys(obj) { function parseGeneric(obj) {
var up = obj["ts_uptime"]; var up = obj["ts_uptime"];
var days = parseInt(up / 86400) % 365; var days = parseInt(up / 86400) % 365;
var hrs = parseInt(up / 3600) % 24; var hrs = parseInt(up / 3600) % 24;
@ -94,10 +95,11 @@
+ ("0"+min).substr(-2) + ":" + ("0"+min).substr(-2) + ":"
+ ("0"+sec).substr(-2); + ("0"+sec).substr(-2);
parseRssi(obj);
if(true == exeOnce) { if(true == exeOnce) {
parseVersion(obj); parseVersion(obj);
parseESP(obj); parseESP(obj);
window.setInterval("getAjax('/api/system', parseSys)", 10000); window.setInterval("getAjax('/api/generic', parseGeneric)", 10000);
exeOnce = false; exeOnce = false;
getAjax("/api/setup", parse); getAjax("/api/setup", parse);
} }
@ -201,7 +203,7 @@
getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj)); getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj));
}); });
getAjax("/api/system", parseSys); getAjax("/api/generic", parseGeneric);
</script> </script>
</body> </body>
</html> </html>

14
src/web/html/setup.html

@ -26,6 +26,7 @@
<span></span> <span></span>
</a> </a>
<div id="topnav" class="hide"></div> <div id="topnav" class="hide"></div>
<div id="wifiicon" class="info"></div>
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
@ -41,7 +42,7 @@
<input type="hidden" name="disclaimer" value="false" id="disclaimer"> <input type="hidden" name="disclaimer" value="false" id="disclaimer">
</fieldset> </fieldset>
<button type="button" class="s_collapsible">WiFi</button> <button type="button" class="s_collapsible">Network</button>
<div class="s_content"> <div class="s_content">
<fieldset> <fieldset>
<legend class="des">WiFi</legend> <legend class="des">WiFi</legend>
@ -116,6 +117,8 @@
<input type="text" class="text" name="sunLat"/> <input type="text" class="text" name="sunLat"/>
<label for="sunLon">Longitude (decimal)</label> <label for="sunLon">Longitude (decimal)</label>
<input type="text" class="text" name="sunLon"/> <input type="text" class="text" name="sunLon"/>
<label for="sunOffs">Offset (pre sunrise, post sunset)</label>
<select name="sunOffs"></select>
<br> <br>
<label for="sunDisNightCom">disable night communication</label> <label for="sunDisNightCom">disable night communication</label>
<input type="checkbox" class="cb" name="sunDisNightCom"/><br/> <input type="checkbox" class="cb" name="sunDisNightCom"/><br/>
@ -337,8 +340,12 @@
var e = document.getElementsByName("adminpwd")[0]; var e = document.getElementsByName("adminpwd")[0];
if(!obj["pwd_set"]) if(!obj["pwd_set"])
e.value = ""; e.value = "";
}
function parseGeneric(obj) {
parseVersion(obj); parseVersion(obj);
parseESP(obj); parseESP(obj);
parseRssi(obj);
} }
function parseStaticIp(obj) { function parseStaticIp(obj) {
@ -368,6 +375,10 @@
document.getElementsByName("sunLat")[0].value = obj["lat"]; document.getElementsByName("sunLat")[0].value = obj["lat"];
document.getElementsByName("sunLon")[0].value = obj["lon"]; document.getElementsByName("sunLon")[0].value = obj["lon"];
document.getElementsByName("sunDisNightCom")[0].checked = obj["disnightcom"]; 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))));
}
} }
function parsePinout(obj, type) { function parsePinout(obj, type) {
@ -452,6 +463,7 @@
if(null != root) { if(null != root) {
parseMenu(root["menu"]); parseMenu(root["menu"]);
parseSys(root["system"]); parseSys(root["system"]);
parseGeneric(root["generic"]);
parseStaticIp(root["static_ip"]); parseStaticIp(root["static_ip"]);
parseIv(root["inverter"]); parseIv(root["inverter"]);
parseMqtt(root["mqtt"]); parseMqtt(root["mqtt"]);

40
src/web/html/style.css

@ -31,11 +31,11 @@ h2 {
} }
.topnav a.icon { .topnav a.icon {
top: 0;
left: 0;
background: #333; background: #333;
display: block; display: block;
position: absolute; position: absolute;
left: 0;
top: 0;
} }
.topnav a:hover { .topnav a:hover {
@ -43,6 +43,20 @@ h2 {
color: #000; color: #000;
} }
.topnav .info {
color: #fff;
position: absolute;
right: 24px;
top: 5px;
}
svg.icon {
vertical-align: middle;
display: inline-block;
margin-top:-4x;
padding: 5px 7px 5px 0px;
}
.title { .title {
background-color: #006ec0; background-color: #006ec0;
color: #fff !important; color: #fff !important;
@ -142,6 +156,13 @@ span.seperator {
display: block; display: block;
} }
.topnav .info {
top: auto !important;
right: auto !important;
bottom: 14px;
left: 24px;
}
#content { #content {
padding: 15px 15px 120px 250px; padding: 15px 15px 120px 250px;
} }
@ -376,11 +397,16 @@ div.ModPwr, div.ModName {
display: inline-block; display: inline-block;
} }
div.hr {
height: 1px;
border-top: 1px solid #ccc;
margin: 10px 0px 10px;
}
#note { #note {
margin: 50px 10px 10px 10px; margin: 10px 10px 10px 10px;
padding-top: 10px; padding-top: 10px;
width: 100%; width: 100%;
border-top: 1px solid #bbb;
} }
@media(max-width: 500px) { @media(max-width: 500px) {
@ -477,6 +503,12 @@ div.ModPwr, div.ModName {
.mt-4 { margin-top: 1.5rem } .mt-4 { margin-top: 1.5rem }
.mt-5 { margin-top: 3rem } .mt-5 { margin-top: 3rem }
.mb-1 { margin-bottom: 0.25rem }
.mb-2 { margin-bottom: 0.5rem }
.mb-3 { margin-bottom: 1rem }
.mb-4 { margin-bottom: 1.5rem }
.mb-5 { margin-bottom: 3rem }
.a-r { text-align: right; } .a-r { text-align: right; }
.a-c { text-align: center; } .a-c { text-align: center; }

43
src/web/html/system.html

@ -15,12 +15,15 @@
<span></span> <span></span>
</a> </a>
<div id="topnav" class="hide"></div> <div id="topnav" class="hide"></div>
<div id="wifiicon" class="info"></div>
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
<pre id="stat"></pre>
<div id="info" class="col-sm-12 col-md-6 mt-3"></div> <div id="info" class="col-sm-12 col-md-6 mt-3"></div>
<div id="radio" class="col-sm-12 col-md-6 mt-3"></div> <div id="radio" class="col-sm-12 col-md-6 mt-3"></div>
<div id="system" class="mt-3"></div> <div id="sun" class="col-sm-12 col-md-6 mt-3"></div>
<div id="html" class="mt-3 mb-3"></div>
</div> </div>
</div> </div>
<div id="footer"> <div id="footer">
@ -40,9 +43,10 @@
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
function parseSys(obj) { function parseGeneric(obj) {
parseVersion(obj); parseVersion(obj);
parseESP(obj); parseESP(obj);
parseRssi(obj);
} }
function genTabRow(key, value) { function genTabRow(key, value) {
@ -54,7 +58,7 @@
function parseSysInfo(obj) { function parseSysInfo(obj) {
const data = ["sdk", "cpu_freq", "chip_revision", const data = ["sdk", "cpu_freq", "chip_revision",
"chip_model", "chip_cores", "esp_type", "mac", "wifi_rssi", "chip_model", "chip_cores", "esp_type", "mac", "wifi_rssi", "ts_uptime",
"flash_size", "sketch_used", "heap_total", "heap_free", "heap_frag", "flash_size", "sketch_used", "heap_total", "heap_free", "heap_frag",
"max_free_blk", "version", "core_version", "reboot_reason"]; "max_free_blk", "version", "core_version", "reboot_reason"];
@ -71,7 +75,7 @@
} }
} }
function parseRadio(obj) { function parseRadio(obj, stat) {
const pa = ["MIN", "LOW", "HIGH", "MAX"]; const pa = ["MIN", "LOW", "HIGH", "MAX"];
const datarate = ["1 MBps", "2 MBps", "250 kbps"]; const datarate = ["1 MBps", "2 MBps", "250 kbps"];
@ -88,12 +92,35 @@
main.appendChild(genTabRow("Datarate", datarate[obj["DataRate"]])); main.appendChild(genTabRow("Datarate", datarate[obj["DataRate"]]));
main.appendChild(genTabRow("Power Level", pa[obj["power_level"]])); main.appendChild(genTabRow("Power Level", pa[obj["power_level"]]));
} }
main.append(
genTabRow("RX success", stat["rx_success"]),
genTabRow("RX fail", stat["rx_fail"]),
genTabRow("RX no answer", stat["rx_fail_answer"]),
genTabRow("RX frames received", stat["frame_cnt"]),
genTabRow("TX count", stat["tx_cnt"])
);
}
function parseIndex(obj) {
var h = div(["head", "p-2"]);
var r = div(["row"]);
r.appendChild(div(["col", "a-c"], "Sun"));
h.appendChild(r);
document.getElementById("sun").append (
h,
genTabRow("Sunrise", new Date(obj["ts_sunrise"] * 1000).toLocaleString('de-DE')),
genTabRow("Sunset", new Date(obj["ts_sunset"] * 1000).toLocaleString('de-DE')),
genTabRow("Communication start", new Date((obj["ts_sunrise"] - obj["ts_offset"]) * 1000).toLocaleString('de-DE')),
genTabRow("Communication stop", new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE'))
);
} }
function parse(obj) { function parse(obj) {
if(null != obj) { if(null != obj) {
parseMenu(obj["menu"]); parseMenu(obj["menu"]);
parseSys(obj["system"]); parseGeneric(obj["generic"]);
if(null != obj["refresh"]) { if(null != obj["refresh"]) {
var meta = document.createElement('meta'); var meta = document.createElement('meta');
@ -103,10 +130,10 @@
} }
else { else {
parseSysInfo(obj["system"]); parseSysInfo(obj["system"]);
parseRadio(obj["system"]["radio"]); parseRadio(obj["system"]["radio"], obj["system"]["statistics"]);
getAjax('/api/index', parseIndex);
} }
var e = document.getElementById("system"); document.getElementById("html").innerHTML = obj["html"];
e.innerHTML = obj["html"];
} }
} }

6
src/web/html/update.html

@ -15,6 +15,7 @@
<span></span> <span></span>
</a> </a>
<div id="topnav" class="hide"></div> <div id="topnav" class="hide"></div>
<div id="wifiicon" class="info"></div>
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
@ -40,15 +41,16 @@
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
function parseSys(obj) { function parseGeneric(obj) {
parseVersion(obj); parseVersion(obj);
parseESP(obj); parseESP(obj);
parseRssi(obj);
} }
function parse(obj) { function parse(obj) {
if(null != obj) { if(null != obj) {
parseMenu(obj["menu"]); parseMenu(obj["menu"]);
parseSys(obj["system"]); parseGeneric(obj["generic"]);
} }
} }

8
src/web/html/visualization.html

@ -16,6 +16,7 @@
<span></span> <span></span>
</a> </a>
<div id="topnav" class="hide"></div> <div id="topnav" class="hide"></div>
<div id="wifiicon" class="info"></div>
</div> </div>
<div id="wrapper"> <div id="wrapper">
<div id="content"> <div id="content">
@ -42,11 +43,12 @@
<script type="text/javascript"> <script type="text/javascript">
var exeOnce = true; var exeOnce = true;
function parseSys(obj) { function parseGeneric(obj) {
if(true == exeOnce){ if(true == exeOnce){
parseVersion(obj); parseVersion(obj);
parseESP(obj); parseESP(obj);
} }
parseRssi(obj);
} }
function parseIv(obj, root) { function parseIv(obj, root) {
@ -117,7 +119,7 @@
if(obj.length > 1) { if(obj.length > 1) {
for(var j = 0; j < root.ch0_fld_names.length; j++) { for(var j = 0; j < root.ch0_fld_names.length; j++) {
var val = Math.round(total[j] * 100) / 100; var val = Math.round(total[j] * 100) / 100;
if(val > 0) { if((j == 2) || (j == 6) || (j == 7) || (j == 8) || (j == 10)) {
var sub = div(["subgrp"]); var sub = div(["subgrp"]);
sub.appendChild(span(val + " " + span(root["ch0_fld_units"][j], ["unit"]).innerHTML, ["value"])); sub.appendChild(span(val + " " + span(root["ch0_fld_units"][j], ["unit"]).innerHTML, ["value"]));
sub.appendChild(span(root["ch0_fld_names"][j], ["info"])); sub.appendChild(span(root["ch0_fld_names"][j], ["info"]));
@ -133,7 +135,7 @@
if(null != obj) { if(null != obj) {
if(true == exeOnce) if(true == exeOnce)
parseMenu(obj["menu"]); parseMenu(obj["menu"]);
parseSys(obj["system"]); parseGeneric(obj["generic"]);
parseIv(obj["inverter"], obj); parseIv(obj["inverter"], obj);
document.getElementById("refresh").innerHTML = obj["refresh_interval"]; document.getElementById("refresh").innerHTML = obj["refresh_interval"];
if(true == exeOnce) { if(true == exeOnce) {

2
src/web/web.h

@ -463,10 +463,12 @@ class Web {
mConfig->sun.lat = 0.0; mConfig->sun.lat = 0.0;
mConfig->sun.lon = 0.0; mConfig->sun.lon = 0.0;
mConfig->sun.disNightCom = false; mConfig->sun.disNightCom = false;
mConfig->sun.offsetSec = 0;
} else { } else {
mConfig->sun.lat = request->arg("sunLat").toFloat(); mConfig->sun.lat = request->arg("sunLat").toFloat();
mConfig->sun.lon = request->arg("sunLon").toFloat(); mConfig->sun.lon = request->arg("sunLon").toFloat();
mConfig->sun.disNightCom = (request->arg("sunDisNightCom") == "on"); mConfig->sun.disNightCom = (request->arg("sunDisNightCom") == "on");
mConfig->sun.offsetSec = request->arg("sunOffs").toInt() * 60;
} }
// mqtt // mqtt

Loading…
Cancel
Save