Merge pull request #379 from duhow/refresh-main

webcfg: add header and meta refresh for main page
This commit is contained in:
Jan-Ole Schümann
2024-06-03 13:31:05 +07:00
committed by GitHub
2 changed files with 124 additions and 58 deletions

View File

@@ -7,6 +7,7 @@
#include "RestartReason.h"
#include <esp_task_wdt.h>
#include <esp_wifi.h>
#include <ArduinoJson.h>
WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Network* network, Gpio* gpio, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal)
: _server(ethServer),
@@ -65,6 +66,14 @@ void WebCfgServer::initialize()
}
sendCss();
});
_server.on("/status", HTTP_GET, [&]() {
if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server.requestAuthentication();
}
String response = "";
buildStatusHtml(response);
_server.send(200, "application/json", response);
});
_server.on("/favicon.ico", HTTP_GET, [&]() {
if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server.requestAuthentication();
@@ -1087,77 +1096,46 @@ void WebCfgServer::update()
void WebCfgServer::buildHtml(String& response)
{
buildHtmlHeader(response);
String header = "<script>let intervalId; window.onload = function() { updateInfo(); intervalId = setInterval(updateInfo, 3000); }; function updateInfo() { var request = new XMLHttpRequest(); request.open('GET', '/status', true); request.onload = () => { const obj = JSON.parse(request.responseText); if (obj.stop == 1) { clearInterval(intervalId); } for (var key of Object.keys(obj)) { if(key=='ota' && document.getElementById(key) !== null) { document.getElementById(key).innerText = \"<a href='/ota'>\" + obj[key] + \"</a>\"; } else if(document.getElementById(key) !== null) { document.getElementById(key).innerText = obj[key]; } } }; request.send(); }</script>";
buildHtmlHeader(response, header);
response.concat("<br><h3>Info</h3>\n");
response.concat("<table>");
printParameter(response, "Hostname", _hostname.c_str());
printParameter(response, "MQTT Connected", _network->mqttConnectionState() > 0 ? "Yes" : "No");
printParameter(response, "Hostname", _hostname.c_str(), "", "hostname");
printParameter(response, "MQTT Connected", _network->mqttConnectionState() > 0 ? "Yes" : "No", "", "mqttState");
if(_nuki != nullptr)
{
char lockstateArr[20];
NukiLock::lockstateToString(_nuki->keyTurnerState().lockState, lockstateArr);
printParameter(response, "Nuki Lock paired", _nuki->isPaired() ? ("Yes (BLE Address " + _nuki->getBleAddress().toString() + ")").c_str() : "No");
printParameter(response, "Nuki Lock state", lockstateArr);
char lockStateArr[20];
NukiLock::lockstateToString(_nuki->keyTurnerState().lockState, lockStateArr);
printParameter(response, "Nuki Lock paired", _nuki->isPaired() ? ("Yes (BLE Address " + _nuki->getBleAddress().toString() + ")").c_str() : "No", "", "lockPaired");
printParameter(response, "Nuki Lock state", lockStateArr, "", "lockState");
if(_nuki->isPaired())
{
switch(_preferences->getInt(preference_lock_pin_status, 4))
{
case 0:
printParameter(response, "Nuki Lock PIN status", "PIN not set");
break;
case 1:
printParameter(response, "Nuki Lock PIN status", "PIN valid");
break;
case 2:
printParameter(response, "Nuki Lock PIN status", "PIN set but invalid");
break;
default:
printParameter(response, "Nuki Lock PIN status", "Unknown");
break;
}
String lockState = pinStateToString(_preferences->getInt(preference_lock_pin_status, 4));
printParameter(response, "Nuki Lock PIN status", lockState.c_str(), "", "lockPin");
}
}
if(_nukiOpener != nullptr)
{
char lockstateArr[20];
NukiOpener::lockstateToString(_nukiOpener->keyTurnerState().lockState, lockstateArr);
printParameter(response, "Nuki Opener paired", _nukiOpener->isPaired() ? ("Yes (BLE Address " + _nukiOpener->getBleAddress().toString() + ")").c_str() : "No");
char openerStateArr[20];
NukiOpener::lockstateToString(_nukiOpener->keyTurnerState().lockState, openerStateArr);
printParameter(response, "Nuki Opener paired", _nukiOpener->isPaired() ? ("Yes (BLE Address " + _nukiOpener->getBleAddress().toString() + ")").c_str() : "No", "", "openerPaired");
if(_nukiOpener->keyTurnerState().nukiState == NukiOpener::State::ContinuousMode)
{
printParameter(response, "Nuki Opener state", "Open (Continuous Mode)");
}
else
{
printParameter(response, "Nuki Opener state", lockstateArr);
}
if(_nukiOpener->keyTurnerState().nukiState == NukiOpener::State::ContinuousMode) printParameter(response, "Nuki Opener state", "Open (Continuous Mode)", "", "openerState");
else printParameter(response, "Nuki Opener state", openerStateArr, "", "openerState");
if(_nukiOpener->isPaired())
{
switch(_preferences->getInt(preference_opener_pin_status, 4))
{
case 0:
printParameter(response, "Nuki Opener PIN status", "PIN not set");
break;
case 1:
printParameter(response, "Nuki Opener PIN status", "PIN valid");
break;
case 2:
printParameter(response, "Nuki Opener PIN status", "PIN set but invalid");
break;
default:
printParameter(response, "Nuki Opener PIN status", "Unknown");
break;
}
String openerState = pinStateToString(_preferences->getInt(preference_opener_pin_status, 4));
printParameter(response, "Nuki Opener PIN status", openerState.c_str(), "", "openerPin");
}
}
printParameter(response, "Firmware", NUKI_HUB_VERSION, "/info");
printParameter(response, "Firmware", NUKI_HUB_VERSION, "/info", "firmware");
if(_preferences->getBool(preference_check_updates)) printParameter(response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota");
if(_preferences->getBool(preference_check_updates)) printParameter(response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota", "ota");
response.concat("</table><br><table id=\"tblnav\"><tbody>");
response.concat("<tr><td><h5>MQTT and Network Configuration</h5></td><td class=\"tdbtn\">");
@@ -1392,6 +1370,88 @@ void WebCfgServer::buildAdvancedConfigHtml(String &response)
response.concat("</body></html>");
}
void WebCfgServer::buildStatusHtml(String &response)
{
JsonDocument json;
char _resbuf[2048];
bool mqttDone = false;
bool lockDone = false;
bool openerDone = false;
bool latestDone = false;
json["stop"] = 0;
if(_network->mqttConnectionState() > 0)
{
json["mqttState"] = "Yes";
mqttDone = true;
}
else json["mqttState"] = "No";
if(_nuki != nullptr)
{
char lockStateArr[20];
NukiLock::lockstateToString(_nuki->keyTurnerState().lockState, lockStateArr);
String lockState = lockStateArr;
String LockPaired = (_nuki->isPaired() ? ("Yes (BLE Address " + _nuki->getBleAddress().toString() + ")").c_str() : "No");
json["lockPaired"] = LockPaired;
json["lockState"] = lockState;
if(_nuki->isPaired())
{
json["lockPin"] = pinStateToString(_preferences->getInt(preference_lock_pin_status, 4));
lockDone = true;
}
else json["lockPin"] = "Not Paired";
}
else lockDone = true;
if(_nukiOpener != nullptr)
{
char openerStateArr[20];
NukiOpener::lockstateToString(_nukiOpener->keyTurnerState().lockState, openerStateArr);
String openerState = openerStateArr;
String openerPaired = (_nukiOpener->isPaired() ? ("Yes (BLE Address " + _nukiOpener->getBleAddress().toString() + ")").c_str() : "No");
json["openerPaired"] = openerPaired;
if(_nukiOpener->keyTurnerState().nukiState == NukiOpener::State::ContinuousMode) json["openerState"] = "Open (Continuous Mode)";
else json["openerState"] = openerState;
if(_nukiOpener->isPaired())
{
json["openerPin"] = pinStateToString(_preferences->getInt(preference_opener_pin_status, 4));
openerDone = true;
}
else json["openerPin"] = "Not Paired";
}
else openerDone = true;
if(_preferences->getBool(preference_check_updates))
{
json["latestFirmware"] = _preferences->getString(preference_latest_version);
latestDone = true;
}
else latestDone = true;
if(mqttDone && lockDone && openerDone && latestDone) json["stop"] = 1;
serializeJson(json, _resbuf, sizeof(_resbuf));
response = _resbuf;
}
String WebCfgServer::pinStateToString(uint8_t value) {
switch(value)
{
case 0:
return (String)"PIN not set";
case 1:
return (String)"PIN valid";
case 2:
return (String)"PIN set but invalid";;
default:
return (String)"Unknown";
}
}
void WebCfgServer::buildAccLvlHtml(String &response)
{
buildHtmlHeader(response);
@@ -2036,10 +2096,11 @@ void WebCfgServer::processFactoryReset()
restartEsp(RestartReason::NukiHubReset);
}
void WebCfgServer::buildHtmlHeader(String &response)
void WebCfgServer::buildHtmlHeader(String &response, String additionalHeader)
{
response.concat("<html><head>");
response.concat("<meta name='viewport' content='width=device-width, initial-scale=1'>");
if(strcmp(additionalHeader.c_str(), "") != 0) response.concat(additionalHeader);
response.concat("<link rel='stylesheet' href='/style.css'>");
response.concat("<title>Nuki Hub</title></head><body>");
@@ -2192,17 +2253,20 @@ void WebCfgServer::buildNavigationButton(String &response, const char *caption,
response.concat("</form>");
}
void WebCfgServer::printParameter(String& response, const char *description, const char *value, const char *link)
void WebCfgServer::printParameter(String& response, const char *description, const char *value, const char *link, const char *id)
{
response.concat("<tr>");
response.concat("<td>");
response.concat(description);
response.concat("</td>");
response.concat("<td>");
if(strcmp(link, "") == 0)
if(strcmp(id, "") == 0) response.concat("<td>");
else
{
response.concat(value);
response.concat("<td id=\"");
response.concat(id);
response.concat("\">");
}
if(strcmp(link, "") == 0) response.concat(value);
else
{
response.concat("<a href=\"");

View File

@@ -42,6 +42,7 @@ private:
void buildOtaHtml(String& response, bool errored);
void buildOtaCompletedHtml(String& response);
void buildMqttConfigHtml(String& response);
void buildStatusHtml(String& response);
void buildAdvancedConfigHtml(String& response);
void buildNukiConfigHtml(String& response);
void buildGpioConfigHtml(String& response);
@@ -53,7 +54,7 @@ private:
void processUnpair(bool opener);
void processFactoryReset();
void buildHtmlHeader(String& response);
void buildHtmlHeader(String& response, String additionalHeader = "");
void printInputField(String& response, const char* token, const char* description, const char* value, const size_t& maxLength, const bool& isPassword = false, const bool& showLengthRestriction = false);
void printInputField(String& response, const char* token, const char* description, const int value, size_t maxLength);
void printCheckBox(String& response, const char* token, const char* description, const bool value, const char* htmlClass);
@@ -64,8 +65,9 @@ private:
const std::vector<std::pair<String, String>> getNetworkDetectionOptions() const;
const std::vector<std::pair<String, String>> getGpioOptions() const;
String getPreselectionForGpio(const uint8_t& pin);
String pinStateToString(uint8_t value);
void printParameter(String& response, const char* description, const char* value, const char *link = "");
void printParameter(String& response, const char* description, const char* value, const char *link = "", const char *id = "");
String generateConfirmCode();
void waitAndProcess(const bool blocking, const uint32_t duration);
@@ -92,4 +94,4 @@ private:
String _confirmCode = "----";
bool _enabled = true;
};
};