Browse Source

Merge branch 'lumapu:development03' into development03

pull/846/head
rejoe2 2 years ago
committed by GitHub
parent
commit
ce78534066
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/CHANGES.md
  2. 4
      src/app.h
  3. 3
      src/appInterface.h
  4. 2
      src/defines.h
  5. 64
      src/web/RestApi.h
  6. 4
      src/web/html/login.html
  7. 29
      src/web/html/style.css
  8. 107
      src/web/web.h

4
src/CHANGES.md

@ -1,5 +1,9 @@
# Development Changes
## 0.6.2 - 2023-04-04
* fix login from multiple clients #819
* fix login screen on small displays
## 0.6.1 - 2023-04-01
* merge LED fix - LED1 shows MqTT state, LED configureable active high/low #839
* only publish new inverter data #826

4
src/app.h

@ -161,8 +161,8 @@ class app : public IApp, public ah::Scheduler {
return mMqtt.getRxCnt();
}
bool getProtection() {
return mWeb.getProtection();
bool getProtection(AsyncWebServerRequest *request) {
return mWeb.isProtected(request);
}
uint8_t getIrqPin(void) {

3
src/appInterface.h

@ -8,6 +8,7 @@
#include "defines.h"
#include "hm/hmSystem.h"
#include "ESPAsyncWebServer.h"
// abstract interface to App. Make members of App accessible from child class
// like web or API without forward declaration
@ -47,7 +48,7 @@ class IApp {
virtual uint32_t getMqttRxCnt() = 0;
virtual uint32_t getMqttTxCnt() = 0;
virtual bool getProtection() = 0;
virtual bool getProtection(AsyncWebServerRequest *request) = 0;
};
#endif /*__IAPP_H__*/

2
src/defines.h

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

64
src/web/RestApi.h

@ -77,19 +77,19 @@ class RestApi {
JsonObject root = response->getRoot();
String path = request->url().substring(5);
if(path == "html/system") getHtmlSystem(root);
else if(path == "html/logout") getHtmlLogout(root);
else if(path == "html/reboot") getHtmlReboot(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);
if(path == "html/system") getHtmlSystem(request, root);
else if(path == "html/logout") getHtmlLogout(request, root);
else if(path == "html/reboot") getHtmlReboot(request, root);
else if(path == "html/save") getHtmlSave(request, root);
else if(path == "system") getSysInfo(request, root);
else if(path == "generic") getGeneric(request, root);
else if(path == "reboot") getReboot(request, root);
else if(path == "statistics") getStatistics(root);
else if(path == "inverter/list") getInverterList(root);
else if(path == "index") getIndex(root);
else if(path == "setup") getSetup(root);
else if(path == "index") getIndex(request, root);
else if(path == "setup") getSetup(request, root);
else if(path == "setup/networks") getNetworks(root);
else if(path == "live") getLive(root);
else if(path == "live") getLive(request, root);
else if(path == "record/info") getRecord(root, InverterDevInform_All);
else if(path == "record/alarm") getRecord(root, AlarmData);
else if(path == "record/config") getRecord(root, SystemConfigPara);
@ -189,10 +189,10 @@ class RestApi {
fp.close();
}
void getGeneric(JsonObject obj) {
void getGeneric(AsyncWebServerRequest *request, JsonObject obj) {
obj[F("wifi_rssi")] = (WiFi.status() != WL_CONNECTED) ? 0 : WiFi.RSSI();
obj[F("ts_uptime")] = mApp->getUptime();
obj[F("menu_prot")] = mApp->getProtection();
obj[F("menu_prot")] = mApp->getProtection(request);
obj[F("menu_mask")] = (uint16_t)(mConfig->sys.protectionMask );
obj[F("menu_protEn")] = (bool) (strlen(mConfig->sys.adminPwd) > 0);
@ -203,7 +203,7 @@ class RestApi {
#endif
}
void getSysInfo(JsonObject obj) {
void getSysInfo(AsyncWebServerRequest *request, JsonObject obj) {
obj[F("ssid")] = mConfig->sys.stationSsid;
obj[F("device_name")] = mConfig->sys.deviceName;
obj[F("dark_mode")] = (bool)mConfig->sys.darkMode;
@ -218,7 +218,7 @@ class RestApi {
obj[F("heap_free")] = mHeapFree;
obj[F("sketch_total")] = ESP.getFreeSketchSpace();
obj[F("sketch_used")] = ESP.getSketchSize() / 1024; // in kb
getGeneric(obj);
getGeneric(request, obj);
getRadio(obj.createNestedObject(F("radio")));
getStatistics(obj.createNestedObject(F("statistics")));
@ -252,34 +252,34 @@ class RestApi {
obj[F("schMax")] = max;
}
void getHtmlSystem(JsonObject obj) {
getSysInfo(obj.createNestedObject(F("system")));
getGeneric(obj.createNestedObject(F("generic")));
void getHtmlSystem(AsyncWebServerRequest *request, JsonObject obj) {
getSysInfo(request, obj.createNestedObject(F("system")));
getGeneric(request, 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>");
}
void getHtmlLogout(JsonObject obj) {
getGeneric(obj.createNestedObject(F("generic")));
void getHtmlLogout(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
obj[F("refresh")] = 3;
obj[F("refresh_url")] = "/";
obj[F("html")] = F("succesfully logged out");
}
void getHtmlReboot(JsonObject obj) {
getGeneric(obj.createNestedObject(F("generic")));
void getHtmlReboot(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
obj[F("refresh")] = 20;
obj[F("refresh_url")] = "/";
obj[F("html")] = F("rebooting ...");
}
void getHtmlSave(JsonObject obj) {
getGeneric(obj.createNestedObject(F("generic")));
void getHtmlSave(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
obj["pending"] = (bool)mApp->getSavePending();
obj["success"] = (bool)mApp->getLastSaveSucceed();
}
void getReboot(JsonObject obj) {
getGeneric(obj.createNestedObject(F("generic")));
void getReboot(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
obj[F("refresh")] = 10;
obj[F("refresh_url")] = "/";
obj[F("html")] = F("reboot. Autoreload after 10 seconds");
@ -430,8 +430,8 @@ class RestApi {
obj[F("disp_bsy")] = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : mConfig->plugin.display.disp_busy;
}
void getIndex(JsonObject obj) {
getGeneric(obj.createNestedObject(F("generic")));
void getIndex(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
obj[F("ts_now")] = mApp->getTimestamp();
obj[F("ts_sunrise")] = mApp->getSunrise();
obj[F("ts_sunset")] = mApp->getSunset();
@ -479,9 +479,9 @@ class RestApi {
info.add(F("MQTT publishes in a fixed interval of ") + String(mConfig->mqtt.interval) + F(" seconds"));
}
void getSetup(JsonObject obj) {
getGeneric(obj.createNestedObject(F("generic")));
getSysInfo(obj.createNestedObject(F("system")));
void getSetup(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
getSysInfo(request, obj.createNestedObject(F("system")));
//getInverterList(obj.createNestedObject(F("inverter")));
getMqtt(obj.createNestedObject(F("mqtt")));
getNtp(obj.createNestedObject(F("ntp")));
@ -497,8 +497,8 @@ class RestApi {
mApp->getAvailNetworks(obj);
}
void getLive(JsonObject obj) {
getGeneric(obj.createNestedObject(F("generic")));
void getLive(AsyncWebServerRequest *request, JsonObject obj) {
getGeneric(request, obj.createNestedObject(F("generic")));
obj[F("refresh")] = mConfig->nrf.sendInterval;
for (uint8_t fld = 0; fld < sizeof(acList); fld++) {

4
src/web/html/login.html

@ -11,8 +11,8 @@
<form action="/login" method="post">
<div class="row"><h2>AhoyDTU</h2></div>
<div class="row">
<div class="col-8"><input type="password" name="pwd" autofocus></div>
<div class="col-4"><input type="submit" name="login" value="login" class="btn"></div>
<div class="col-12 col-sm-8 mb-3"><input type="password" name="pwd" autofocus></div>
<div class="col-12 col-sm-4"><input type="submit" name="login" value="login" class="btn"></div>
</div>
</form>
</div>

29
src/web/html/style.css

@ -546,6 +546,18 @@ div.hr {
width: 100%;
}
#login {
width: 450px;
height: 200px;
border: 1px solid #ccc;
background-color: var(--input-bg);
position: absolute;
top: 50%;
left: 50%;
margin-top: -160px;
margin-left: -225px;
}
@media(max-width: 500px) {
div.ch .unit, div.ch-iv .unit {
font-size: 18px;
@ -559,6 +571,11 @@ div.hr {
.subgrp {
width: 180px;
}
#login {
margin-left: -150px;
width: 300px;
}
}
#serial {
@ -578,18 +595,6 @@ div.hr {
margin-top: 15px;
}
#login {
width: 450px;
height: 200px;
border: 1px solid #ccc;
background-color: var(--input-bg);
position: absolute;
top: 50%;
left: 50%;
margin-top: -160px;
margin-left: -225px;
}
.head {
background-color: var(--primary);

107
src/web/web.h

@ -126,8 +126,19 @@ class Web {
mProtected = protect;
}
bool getProtection() {
return mProtected;
bool isProtected(AsyncWebServerRequest *request) {
bool prot;
prot = mProtected;
if(!prot) {
uint8_t ip[4];
ah::ip2Arr(ip, request->client()->remoteIP().toString().c_str());
for(uint8_t i = 0; i < 4; i++) {
if(mLoginIp[i] != ip[i])
prot = true;
}
}
return prot;
}
void showUpdate2(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
@ -216,7 +227,7 @@ class Web {
}
private:
void checkRedirect(AsyncWebServerRequest *request) {
inline void checkRedirect(AsyncWebServerRequest *request) {
if ((mConfig->sys.protectionMask & PROT_MASK_INDEX) != PROT_MASK_INDEX)
request->redirect(F("/index"));
else if ((mConfig->sys.protectionMask & PROT_MASK_LIVE) != PROT_MASK_LIVE)
@ -229,15 +240,18 @@ class Web {
request->redirect(F("/login"));
}
void checkProtection(AsyncWebServerRequest *request) {
if(isProtected(request)) {
checkRedirect(request);
return;
}
}
void onUpdate(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onUpdate"));
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_UPDATE)) {
if (mProtected) {
checkRedirect(request);
return;
}
}
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_UPDATE))
checkProtection(request);
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), update_html, update_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
@ -290,12 +304,8 @@ class Web {
void onIndex(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onIndex"));
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_INDEX)) {
if (mProtected) {
checkRedirect(request);
return;
}
}
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_INDEX))
checkProtection(request);
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), index_html, index_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
@ -308,6 +318,7 @@ class Web {
if (request->args() > 0) {
if (String(request->arg("pwd")) == String(mConfig->sys.adminPwd)) {
mProtected = false;
ah::ip2Arr(mLoginIp, request->client()->remoteIP().toString().c_str());
request->redirect("/");
}
}
@ -320,10 +331,7 @@ class Web {
void onLogout(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onLogout"));
if (mProtected) {
checkRedirect(request);
return;
}
checkProtection(request);
mProtected = true;
@ -367,10 +375,8 @@ class Web {
}
void showNotFound(AsyncWebServerRequest *request) {
if (mProtected)
checkRedirect(request);
else
request->redirect("/setup");
checkProtection(request);
request->redirect("/setup");
}
void onReboot(AsyncWebServerRequest *request) {
@ -381,10 +387,7 @@ class Web {
}
void showErase(AsyncWebServerRequest *request) {
if (mProtected) {
checkRedirect(request);
return;
}
checkProtection(request);
DPRINTLN(DBG_VERBOSE, F("showErase"));
mApp->eraseSettings(false);
@ -392,10 +395,7 @@ class Web {
}
void showFactoryRst(AsyncWebServerRequest *request) {
if (mProtected) {
checkRedirect(request);
return;
}
checkProtection(request);
DPRINTLN(DBG_VERBOSE, F("showFactoryRst"));
String content = "";
@ -424,12 +424,8 @@ class Web {
void onSetup(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onSetup"));
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_SETUP)) {
if (mProtected) {
checkRedirect(request);
return;
}
}
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_SETUP))
checkProtection(request);
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), setup_html, setup_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
@ -439,10 +435,7 @@ class Web {
void showSave(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("showSave"));
if (mProtected) {
checkRedirect(request);
return;
}
checkProtection(request);
if (request->args() == 0)
return;
@ -605,12 +598,8 @@ class Web {
void onLive(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onLive"));
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_LIVE)) {
if (mProtected) {
checkRedirect(request);
return;
}
}
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_LIVE))
checkProtection(request);
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), visualization_html, visualization_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
@ -620,13 +609,6 @@ class Web {
}
void onAbout(AsyncWebServerRequest *request) {
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_LIVE)) {
if (mProtected) {
checkRedirect(request);
return;
}
}
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), about_html, about_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
response->addHeader(F("content-type"), "text/html; charset=UTF-8");
@ -643,12 +625,8 @@ class Web {
void onSerial(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onSerial"));
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_SERIAL)) {
if (mProtected) {
checkRedirect(request);
return;
}
}
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_SERIAL))
checkProtection(request);
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), serial_html, serial_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
@ -658,12 +636,8 @@ class Web {
void onSystem(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onSystem"));
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_SYSTEM)) {
if (mProtected) {
checkRedirect(request);
return;
}
}
if (CHECK_MASK(mConfig->sys.protectionMask, PROT_MASK_SYSTEM))
checkProtection(request);
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
@ -840,6 +814,7 @@ class Web {
AsyncEventSource mEvts;
bool mProtected;
uint32_t mLogoutTimeout;
uint8_t mLoginIp[4];
IApp *mApp;
HMSYSTEM *mSys;

Loading…
Cancel
Save