WebConfigurator fixes

This commit is contained in:
iranl
2024-08-17 23:22:16 +02:00
parent 83ddd91589
commit 1ca0cb2e72
4 changed files with 121 additions and 41 deletions

View File

@@ -7,8 +7,12 @@
#include "RestartReason.h" #include "RestartReason.h"
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ctype.h> #include <ctype.h>
#include <HTTPClient.h>
#include <NetworkClientSecure.h>
extern bool forceEnableWebServer; extern bool forceEnableWebServer;
extern const uint8_t x509_crt_imported_bundle_bin_start[] asm("_binary_x509_crt_bundle_start");
extern const uint8_t x509_crt_imported_bundle_bin_end[] asm("_binary_x509_crt_bundle_end");
NukiNetworkLock::NukiNetworkLock(NukiNetwork* network, Preferences* preferences, char* buffer, size_t bufferSize) NukiNetworkLock::NukiNetworkLock(NukiNetwork* network, Preferences* preferences, char* buffer, size_t bufferSize)
: _network(network), : _network(network),
@@ -204,30 +208,102 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
else if(comparePrefixedPath(topic, mqtt_topic_update) && strcmp(value, "1") == 0 && _preferences->getBool(preference_update_from_mqtt, false)) else if(comparePrefixedPath(topic, mqtt_topic_update) && strcmp(value, "1") == 0 && _preferences->getBool(preference_update_from_mqtt, false))
{ {
Log->println(F("Update requested via MQTT.")); Log->println(F("Update requested via MQTT."));
String currentVersion = NUKI_HUB_VERSION;
bool otaManifestSuccess = false;
JsonDocument doc;
if(atof(_preferences->getString(preference_latest_version).c_str()) >= atof(currentVersion.c_str())) NetworkClientSecure *client = new NetworkClientSecure;
{ if (client) {
_preferences->putString(preference_ota_updater_url, GITHUB_LATEST_UPDATER_BINARY_URL); client->setCACertBundle(x509_crt_imported_bundle_bin_start, x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start);
_preferences->putString(preference_ota_main_url, GITHUB_LATEST_RELEASE_BINARY_URL); {
HTTPClient https;
https.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
https.useHTTP10(true);
if (https.begin(*client, GITHUB_OTA_MANIFEST_URL)) {
int httpResponseCode = https.GET();
if (httpResponseCode == HTTP_CODE_OK || httpResponseCode == HTTP_CODE_MOVED_PERMANENTLY)
{
DeserializationError jsonError = deserializeJson(doc, https.getStream());
if (!jsonError) { otaManifestSuccess = true; }
}
}
https.end();
}
delete client;
} }
else if(currentVersion.indexOf("beta") > 0)
if (otaManifestSuccess)
{ {
_preferences->putString(preference_ota_updater_url, GITHUB_BETA_RELEASE_BINARY_URL); String currentVersion = NUKI_HUB_VERSION;
_preferences->putString(preference_ota_main_url, GITHUB_BETA_UPDATER_BINARY_URL);
} if(atof(doc["release"]["version"]) >= atof(currentVersion.c_str()))
else if(currentVersion.indexOf("master") > 0) {
{ if(strcmp(NUKI_HUB_VERSION, doc["release"]["fullversion"].as<const char*>()) == 0 && strcmp(NUKI_HUB_BUILD, doc["release"]["build"].as<const char*>()) == 0 && strcmp(NUKI_HUB_DATE, doc["release"]["time"].as<const char*>()) == 0)
_preferences->putString(preference_ota_updater_url, GITHUB_MASTER_RELEASE_BINARY_URL); {
_preferences->putString(preference_ota_main_url, GITHUB_MASTER_UPDATER_BINARY_URL); Log->println(F("Nuki Hub is already on the latest release version, OTA update aborted."));
}
else
{
_preferences->putString(preference_ota_updater_url, GITHUB_LATEST_UPDATER_BINARY_URL);
_preferences->putString(preference_ota_main_url, GITHUB_LATEST_RELEASE_BINARY_URL);
Log->println(F("Updating to latest release version."));
delay(200);
restartEsp(RestartReason::OTAReboot);
}
}
else if(currentVersion.indexOf("beta") > 0)
{
if(strcmp(NUKI_HUB_VERSION, doc["beta"]["fullversion"].as<const char*>()) == 0 && strcmp(NUKI_HUB_BUILD, doc["beta"]["build"].as<const char*>()) == 0 && strcmp(NUKI_HUB_DATE, doc["beta"]["time"].as<const char*>()) == 0)
{
Log->println(F("Nuki Hub is already on the latest beta version, OTA update aborted."));
}
else
{
_preferences->putString(preference_ota_updater_url, GITHUB_BETA_RELEASE_BINARY_URL);
_preferences->putString(preference_ota_main_url, GITHUB_BETA_UPDATER_BINARY_URL);
Log->println(F("Updating to latest beta version."));
delay(200);
restartEsp(RestartReason::OTAReboot);
}
}
else if(currentVersion.indexOf("master") > 0)
{
if(strcmp(NUKI_HUB_VERSION, doc["master"]["fullversion"].as<const char*>()) == 0 && strcmp(NUKI_HUB_BUILD, doc["master"]["build"].as<const char*>()) == 0 && strcmp(NUKI_HUB_DATE, doc["master"]["time"].as<const char*>()) == 0)
{
Log->println(F("Nuki Hub is already on the latest development version, OTA update aborted."));
}
else
{
_preferences->putString(preference_ota_updater_url, GITHUB_MASTER_RELEASE_BINARY_URL);
_preferences->putString(preference_ota_main_url, GITHUB_MASTER_UPDATER_BINARY_URL);
Log->println(F("Updating to latest developmemt version."));
delay(200);
restartEsp(RestartReason::OTAReboot);
}
}
else
{
if(strcmp(NUKI_HUB_VERSION, doc["release"]["fullversion"].as<const char*>()) == 0 && strcmp(NUKI_HUB_BUILD, doc["release"]["build"].as<const char*>()) == 0 && strcmp(NUKI_HUB_DATE, doc["release"]["time"].as<const char*>()) == 0)
{
Log->println(F("Nuki Hub is already on the latest release version, OTA update aborted."));
}
else
{
_preferences->putString(preference_ota_updater_url, GITHUB_LATEST_UPDATER_BINARY_URL);
_preferences->putString(preference_ota_main_url, GITHUB_LATEST_RELEASE_BINARY_URL);
Log->println(F("Updating to latest release version."));
delay(200);
restartEsp(RestartReason::OTAReboot);
}
}
} }
else else
{ {
_preferences->putString(preference_ota_updater_url, GITHUB_LATEST_UPDATER_BINARY_URL); Log->println(F("Failed to retrieve OTA manifest, OTA update aborted."));
_preferences->putString(preference_ota_main_url, GITHUB_LATEST_RELEASE_BINARY_URL);
} }
delay(200);
restartEsp(RestartReason::OTAReboot);
} }
else if(comparePrefixedPath(topic, mqtt_topic_webserver_action)) else if(comparePrefixedPath(topic, mqtt_topic_webserver_action))
{ {

View File

@@ -2906,7 +2906,10 @@ void NukiOpenerWrapper::readConfig()
char resultStr[20]; char resultStr[20];
NukiOpener::cmdResultToString(result, resultStr); NukiOpener::cmdResultToString(result, resultStr);
Log->print(F("Opener config result: ")); Log->print(F("Opener config result: "));
Log->println(resultStr); Log->print(resultStr);
Log->print("(");
Log->print(result);
Log->println(")");
postponeBleWatchdog(); postponeBleWatchdog();
} }

View File

@@ -283,9 +283,9 @@ void WebCfgServer::buildOtaHtml(AsyncWebServerRequest *request, bool debug)
#else #else
String build_type = "debug"; String build_type = "debug";
#endif #endif
response->print("<form onsubmit=\"if(document.getElementById('currentver').value == document.getElementById('latestver').value && '" + release_type + "' == '" + build_type + "') { alert('You are already on this version, build and build type'); return false; } else { return confirm('Do you really want to update to the latest release?'); } \" action=\"/autoupdate\" method=\"get\" style=\"float: left; margin-right: 10px\"><input type=\"hidden\" name=\"release\" value=\"1\" /><input type=\"hidden\" name=\"" + release_type + "\" value=\"1\" /><input type=\"hidden\" name=\"token\" value=\"" + _confirmCode + "\" /><br><input type=\"submit\" style=\"background: green\" value=\"Update to latest release\"></form>"); response->print("<form onsubmit=\"if(document.getElementById('currentver').innerHTML == document.getElementById('latestver').innerHTML && '" + release_type + "' == '" + build_type + "') { alert('You are already on this version, build and build type'); return false; } else { return confirm('Do you really want to update to the latest release?'); } \" action=\"/autoupdate\" method=\"get\" style=\"float: left; margin-right: 10px\"><input type=\"hidden\" name=\"release\" value=\"1\" /><input type=\"hidden\" name=\"" + release_type + "\" value=\"1\" /><input type=\"hidden\" name=\"token\" value=\"" + _confirmCode + "\" /><br><input type=\"submit\" style=\"background: green\" value=\"Update to latest release\"></form>");
response->print("<form onsubmit=\"if(document.getElementById('currentver').value == document.getElementById('betaver').value && '" + release_type + "' == '" + build_type + "') { alert('You are already on this version, build and build type'); return false; } else { return confirm('Do you really want to update to the latest beta? This version could contain breaking bugs and necessitate downgrading to the latest release version using USB/Serial'); }\" action=\"/autoupdate\" method=\"get\" style=\"float: left; margin-right: 10px\"><input type=\"hidden\" name=\"beta\" value=\"1\" /><input type=\"hidden\" name=\"" + release_type + "\" value=\"1\" /><input type=\"hidden\" name=\"token\" value=\"" + _confirmCode + "\" /><br><input type=\"submit\" style=\"color: black; background: yellow\" value=\"Update to latest beta\"></form>"); response->print("<form onsubmit=\"if(document.getElementById('currentver').innerHTML == document.getElementById('betaver').innerHTML && '" + release_type + "' == '" + build_type + "') { alert('You are already on this version, build and build type'); return false; } else { return confirm('Do you really want to update to the latest beta? This version could contain breaking bugs and necessitate downgrading to the latest release version using USB/Serial'); }\" action=\"/autoupdate\" method=\"get\" style=\"float: left; margin-right: 10px\"><input type=\"hidden\" name=\"beta\" value=\"1\" /><input type=\"hidden\" name=\"" + release_type + "\" value=\"1\" /><input type=\"hidden\" name=\"token\" value=\"" + _confirmCode + "\" /><br><input type=\"submit\" style=\"color: black; background: yellow\" value=\"Update to latest beta\"></form>");
response->print("<form onsubmit=\"if(document.getElementById('currentver').value == document.getElementById('devver').value && '" + release_type + "' == '" + build_type + "') { alert('You are already on this version, build and build type'); return false; } else { return confirm('Do you really want to update to the latest development version? This version could contain breaking bugs and necessitate downgrading to the latest release version using USB/Serial'); }\" action=\"/autoupdate\" method=\"get\" style=\"float: left; margin-right: 10px\"><input type=\"hidden\" name=\"master\" value=\"1\" /><input type=\"hidden\" name=\"" + release_type + "\" value=\"1\" /><input type=\"hidden\" name=\"token\" value=\"" + _confirmCode + "\" /><br><input type=\"submit\" style=\"background: red\" value=\"Update to latest development version\"></form>"); response->print("<form onsubmit=\"if(document.getElementById('currentver').innerHTML == document.getElementById('devver').innerHTML && '" + release_type + "' == '" + build_type + "') { alert('You are already on this version, build and build type'); return false; } else { return confirm('Do you really want to update to the latest development version? This version could contain breaking bugs and necessitate downgrading to the latest release version using USB/Serial'); }\" action=\"/autoupdate\" method=\"get\" style=\"float: left; margin-right: 10px\"><input type=\"hidden\" name=\"master\" value=\"1\" /><input type=\"hidden\" name=\"" + release_type + "\" value=\"1\" /><input type=\"hidden\" name=\"token\" value=\"" + _confirmCode + "\" /><br><input type=\"submit\" style=\"background: red\" value=\"Update to latest development version\"></form>");
response->print("<div style=\"clear: both\"></div><br>"); response->print("<div style=\"clear: both\"></div><br>");
response->print("<b>Current version: </b><span id=\"currentver\">"); response->print("<b>Current version: </b><span id=\"currentver\">");
@@ -358,6 +358,16 @@ void WebCfgServer::buildOtaHtml(AsyncWebServerRequest *request, bool debug)
response->print(")</span>, "); response->print(")</span>, ");
response->print(doc["master"]["time"].as<const char*>()); response->print(doc["master"]["time"].as<const char*>());
response->print("<br>"); response->print("<br>");
String currentVersion = NUKI_HUB_VERSION;
const char* latestVersion;
if(atof(doc["release"]["version"]) >= atof(currentVersion.c_str())) latestVersion = doc["release"]["fullversion"];
else if(currentVersion.indexOf("beta") > 0) latestVersion = doc["beta"]["fullversion"];
else if(currentVersion.indexOf("master") > 0) latestVersion = doc["master"]["fullversion"];
else latestVersion = doc["release"]["fullversion"];
if(strcmp(latestVersion, _preferences->getString(preference_latest_version).c_str()) != 0) _preferences->putString(preference_latest_version, latestVersion);
} }
#endif #endif
response->print("<br></div>"); response->print("<br></div>");
@@ -2746,9 +2756,9 @@ void WebCfgServer::buildAdvancedConfigHtml(AsyncWebServerRequest *request)
printInputField(response, "TSKNTWK", "Task size Network (min 12288, max 32768)", _preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), 6, ""); printInputField(response, "TSKNTWK", "Task size Network (min 12288, max 32768)", _preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), 6, "");
response->print("<tr><td>Advised minimum network task size based on current settings</td><td id=\"minnetworktask\"></td>"); response->print("<tr><td>Advised minimum network task size based on current settings</td><td id=\"minnetworktask\"></td>");
printInputField(response, "TSKNUKI", "Task size Nuki (min 8192, max 32768)", _preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), 6, ""); printInputField(response, "TSKNUKI", "Task size Nuki (min 8192, max 32768)", _preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), 6, "");
printInputField(response, "ALMAX", "Max auth log entries (min 1, max 50)", _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 3, "inputmaxauthlog"); printInputField(response, "ALMAX", "Max auth log entries (min 1, max 50)", _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 3, "id=\"inputmaxauthlog\"");
printInputField(response, "KPMAX", "Max keypad entries (min 1, max 100)", _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD), 3, "inputmaxkeypad"); printInputField(response, "KPMAX", "Max keypad entries (min 1, max 100)", _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD), 3, "id=\"inputmaxkeypad\"");
printInputField(response, "TCMAX", "Max timecontrol entries (min 1, max 50)", _preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL), 3, "inputmaxtimecontrol"); printInputField(response, "TCMAX", "Max timecontrol entries (min 1, max 50)", _preferences->getInt(preference_timecontrol_max_entries, MAX_TIMECONTROL), 3, "id=\"inputmaxtimecontrol\"");
printCheckBox(response, "SHOWSECRETS", "Show Pairing secrets on Info page (for 120s after next boot)", _preferences->getBool(preference_show_secrets), ""); printCheckBox(response, "SHOWSECRETS", "Show Pairing secrets on Info page (for 120s after next boot)", _preferences->getBool(preference_show_secrets), "");
if(_preferences->getBool(preference_lock_enabled, true)) if(_preferences->getBool(preference_lock_enabled, true))
{ {
@@ -3875,7 +3885,7 @@ void WebCfgServer::printInputField(AsyncResponseStream *response,
const char *description, const char *description,
const char *value, const char *value,
const size_t& maxLength, const size_t& maxLength,
const char *id, const char *args,
const bool& isPassword, const bool& isPassword,
const bool& showLengthRestriction) const bool& showLengthRestriction)
{ {
@@ -3896,19 +3906,10 @@ void WebCfgServer::printInputField(AsyncResponseStream *response,
response->print("</td><td>"); response->print("</td><td>");
response->print("<input type="); response->print("<input type=");
response->print(isPassword ? "\"password\"" : "\"text\""); response->print(isPassword ? "\"password\"" : "\"text\"");
if(strcmp(id, "") != 0) if(strcmp(args, "") != 0)
{ {
if(strncmp(id, "class=", 6) != 0) response->print(" ");
{ response->print(args);
response->print(" ");
response->print(id);
}
else
{
response->print(" id=\"");
response->print(id);
response->print("\"");
}
} }
if(strcmp(value, "") != 0) if(strcmp(value, "") != 0)
{ {
@@ -3928,11 +3929,11 @@ void WebCfgServer::printInputField(AsyncResponseStream *response,
const char *description, const char *description,
const int value, const int value,
size_t maxLength, size_t maxLength,
const char *id) const char *args)
{ {
char valueStr[20]; char valueStr[20];
itoa(value, valueStr, 10); itoa(value, valueStr, 10);
printInputField(response, token, description, valueStr, maxLength, id); printInputField(response, token, description, valueStr, maxLength, args);
} }
void WebCfgServer::printCheckBox(AsyncResponseStream *response, const char *token, const char *description, const bool value, const char *htmlClass) void WebCfgServer::printCheckBox(AsyncResponseStream *response, const char *token, const char *description, const bool value, const char *htmlClass)

View File

@@ -68,8 +68,8 @@ private:
void processUnpair(AsyncWebServerRequest *request, bool opener); void processUnpair(AsyncWebServerRequest *request, bool opener);
void processUpdate(AsyncWebServerRequest *request); void processUpdate(AsyncWebServerRequest *request);
void processFactoryReset(AsyncWebServerRequest *request); void processFactoryReset(AsyncWebServerRequest *request);
void printInputField(AsyncResponseStream *response, const char* token, const char* description, const char* value, const size_t& maxLength, const char* id, const bool& isPassword = false, const bool& showLengthRestriction = false); void printInputField(AsyncResponseStream *response, const char* token, const char* description, const char* value, const size_t& maxLength, const char* args, const bool& isPassword = false, const bool& showLengthRestriction = false);
void printInputField(AsyncResponseStream *response, const char* token, const char* description, const int value, size_t maxLength, const char* id); void printInputField(AsyncResponseStream *response, const char* token, const char* description, const int value, size_t maxLength, const char* args);
void printCheckBox(AsyncResponseStream *response, const char* token, const char* description, const bool value, const char* htmlClass); void printCheckBox(AsyncResponseStream *response, const char* token, const char* description, const bool value, const char* htmlClass);
void printCheckBox(String &partString, const char* token, const char* description, const bool value, const char* htmlClass); void printCheckBox(String &partString, const char* token, const char* description, const bool value, const char* htmlClass);
void printTextarea(AsyncResponseStream *response, const char *token, const char *description, const char *value, const size_t& maxLength, const bool& enabled = true, const bool& showLengthRestriction = false); void printTextarea(AsyncResponseStream *response, const char *token, const char *description, const char *value, const size_t& maxLength, const bool& enabled = true, const bool& showLengthRestriction = false);