diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index fc81178..f44fa60 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -90,7 +90,8 @@ module.exports = { 'use/actuators', 'use/boards', 'use/displays', - 'use/gateway' + 'use/gateway', + 'use/webui' ] }, { diff --git a/docs/use/webui.md b/docs/use/webui.md new file mode 100644 index 0000000..6024d01 --- /dev/null +++ b/docs/use/webui.md @@ -0,0 +1,49 @@ +# WebUI + +For ESP32 based environments a WebUI is available to provide basic configuration and monitoring of your OpenMQTTGateway Device. Functions included are: + +* Configuration +* Information +* Firmware Upgrade +* Console +* Resart + +# Login Authentication + +By default access to the WebUI uses basic authentication to control access to your OpenMQTTGateway Device. The login is `admin` and the password is your ota_password. + +# Configuration Options + +## Wifi + +Abiltity to change the SSID and password for your Wifi, if the change is unsuccessful it will revert back to the previous wifi settings. + +## MQTT + +Abiltity to change the mqtt settings, if the change is unsuccessful it will revert back to the previous mqtt settings. + +## WebUI + +Ability to change the display of sensor to Metric or Imperial, and disable the WebUI Authentication + +## Logging + +Ability to temporarily change the logging level. + +# Information + +Details of OpenMQTTGateway Device status + +# Firmware Upgrade + +Ability to upgrade firmware by URL or to latest version. + +# Console + +Ability to view messages from the OpenMQTTGateway console. The scope of messages visible in the UI is limited to just the OpenMQTTGatewy codebase, messages from the ESP hardware or other libraries are not visible, + +Ability to inject commands to OpenMQTTGateway for processing. The commands accepted are of the form mqtt topic then json message. And as you are already on the target device, you do not need to include the device name ie + +`commands/MQTTtoSYS/config {"cmd":"restart"}` + +This works for all modules in your environment. \ No newline at end of file diff --git a/main/ZwebUI.ino b/main/ZwebUI.ino index 2cc8f49..95da8e3 100644 --- a/main/ZwebUI.ino +++ b/main/ZwebUI.ino @@ -45,22 +45,6 @@ QueueHandle_t webUIQueue; WebServer server(80); -boolean displayMetric = DISPLAY_METRIC; - -/*------------------- Local functions ----------------------*/ - -void notFound(); -void handleRoot(); // "/" - -void handleCS(); // Console -void handleCN(); // Configuration - -void handleIN(); // Information - -void handleRT(); // Restart -void handleCL(); // Configure Cloud -void handleTK(); // Return Cloud token - /*------------------- External functions ----------------------*/ esp_err_t nvs_flash_erase(void); @@ -81,7 +65,11 @@ const uint16_t TOPSZ = 151; // Max number of characters in topic string uint8_t masterlog_level; // Master log level used to override set log level bool reset_web_log_flag = false; // Reset web console log -# ifdef ESP32 +const char* www_username = WEBUI_LOGIN; +String authFailResponse = "Authentication Failed"; +bool webUISecure = WEBUI_AUTH; +boolean displayMetric = DISPLAY_METRIC; + /*********************************************************************************************\ * ESP32 AutoMutex \*********************************************************************************************/ @@ -241,8 +229,6 @@ String HtmlEscape(const String unescaped) { return result; } -# endif // ESP32 - void AddLogData(uint32_t loglevel, const char* log_data, const char* log_data_payload = nullptr, const char* log_data_retained = nullptr) { // Store log_data in buffer // To lower heap usage log_data_payload may contain the payload data from MqttPublishPayload() @@ -414,6 +400,7 @@ bool exists(String path) { */ void handleRoot() { WEBUI_TRACE_LOG(F("handleRoot: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -476,6 +463,7 @@ void handleRoot() { * */ void handleCN() { + WEBUI_SECURE WEBUI_TRACE_LOG(F("handleCN: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { @@ -499,6 +487,54 @@ void handleCN() { } } +/** + * @brief /WU - Configuration Page + * T: handleWU: uri: /wu, args: 3, method: 1 + * T: handleWU Arg: 0, dm=on - displayMetric + * T: handleWU Arg: 1, sw=on - webUISecure + * T: handleWU Arg: 2, save= + */ +void handleWU() { + WEBUI_TRACE_LOG(F("handleWU: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE + if (server.args()) { + for (uint8_t i = 0; i < server.args(); i++) { + WEBUI_TRACE_LOG(F("handleWU Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); + } + bool update = false; + + if (displayMetric != server.hasArg("dm")) { + update = true; + } + displayMetric = server.hasArg("dm"); + + if (webUISecure != server.hasArg("sw")) { + update = true; + } + webUISecure = server.hasArg("sw"); + + if (server.hasArg("save") && update) { + WebUIConfig_save(); + } + } + + char jsonChar[100]; + serializeJson(modules, jsonChar, measureJson(modules) + 1); + + char buffer[WEB_TEMPLATE_BUFFER_MAX_SIZE]; + + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, header_html, (String(gateway_name) + " - Configure WebUI").c_str()); + String response = String(buffer); + response += String(script); + response += String(style); + int logLevel = Log.getLevel(); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, config_webui_body, jsonChar, gateway_name, (displayMetric ? "checked" : ""), (webUISecure ? "checked" : "")); + response += String(buffer); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, footer, OMG_VERSION); + response += String(buffer); + server.send(200, "text/html", response); +} + /** * @brief /WI - Configure WiFi Page * T: handleWI: uri: /wi, args: 4, method: 1 @@ -508,6 +544,7 @@ void handleCN() { */ void handleWI() { WEBUI_TRACE_LOG(F("handleWI: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE String WiFiScan = ""; if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { @@ -670,6 +707,7 @@ void handleWI() { */ void handleMQ() { WEBUI_TRACE_LOG(F("handleMQ: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleMQ Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -708,10 +746,10 @@ void handleMQ() { } // SC - Secure Connection argument is only present when true - WEBtoSYS["mqtt_secure"] = server.hasArg("sc"); if (mqtt_secure != server.hasArg("sc")) { update = true; } + WEBtoSYS["mqtt_secure"] = server.hasArg("sc"); if (!update) { Log.warning(F("[WebUI] clearing" CR)); @@ -792,6 +830,7 @@ void handleMQ() { */ void handleLO() { WEBUI_TRACE_LOG(F("handleLO: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleLO Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -825,6 +864,7 @@ void handleLO() { */ void handleRT() { WEBUI_TRACE_LOG(F("handleRT: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleRT Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -862,6 +902,7 @@ void handleRT() { */ void handleCL() { WEBUI_TRACE_LOG(F("handleCL: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleCL Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -915,6 +956,7 @@ void handleCL() { */ void handleTK() { WEBUI_TRACE_LOG(F("handleTK: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleTK Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -957,6 +999,7 @@ void handleTK() { */ void handleIN() { WEBUI_TRACE_LOG(F("handleCN: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleIN Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -1026,6 +1069,7 @@ void handleIN() { */ void handleUP() { WEBUI_TRACE_LOG(F("handleUP: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args()) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleUP Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -1110,6 +1154,7 @@ void sendRestartPage() { */ void handleCS() { WEBUI_TRACE_LOG(F("handleCS: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE if (server.args() && server.hasArg("c2")) { for (uint8_t i = 0; i < server.args(); i++) { WEBUI_TRACE_LOG(F("handleCS Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); @@ -1173,6 +1218,7 @@ void handleCS() { * */ void notFound() { + WEBUI_SECURE # ifdef WEBUI_DEVELOPMENT String path = server.uri(); if (!exists(path)) { @@ -1196,6 +1242,7 @@ void notFound() { void WebUISetup() { WEBUI_TRACE_LOG(F("ZwebUI setup start" CR)); + WebUIConfig_load(); webUIQueue = xQueueCreate(5, sizeof(webUIQueueMessage*)); # ifdef WEBUI_DEVELOPMENT @@ -1222,6 +1269,7 @@ void WebUISetup() { server.on("/cn", handleCN); // Configuration server.on("/wi", handleWI); // Configure Wifi server.on("/mq", handleMQ); // Configure MQTT + server.on("/wu", handleWU); // Configure WebUI # if defined(ZgatewayCloud) server.on("/cl", handleCL); // Configure Cloud server.on("/tk", handleTK); // Store Device Token @@ -1233,6 +1281,8 @@ void WebUISetup() { Log.begin(LOG_LEVEL, &WebLog); + Log.trace(F("[WebUI] displayMetric %T" CR), displayMetric); + Log.trace(F("[WebUI] WebUI Secure %T" CR), webUISecure); Log.notice(F("OpenMQTTGateway URL: http://%s/" CR), WiFi.localIP().toString().c_str()); displayPrint("URL: http://", (char*)WiFi.localIP().toString().c_str()); Log.notice(F("ZwebUI setup done" CR)); @@ -1306,6 +1356,7 @@ String stateWebUIStatus() { StaticJsonDocument jsonBuffer; JsonObject WebUIdata = jsonBuffer.to(); WebUIdata["displayMetric"] = (bool)displayMetric; + WebUIdata["webUISecure"] = (bool)webUISecure; WebUIdata["displayQueue"] = uxQueueMessagesWaiting(webUIQueue); ; @@ -1321,25 +1372,27 @@ bool WebUIConfig_save() { StaticJsonDocument jsonBuffer; JsonObject jo = jsonBuffer.to(); jo["displayMetric"] = (bool)displayMetric; + jo["webUISecure"] = (bool)webUISecure; // Save config into NVS (non-volatile storage) String conf = ""; serializeJson(jsonBuffer, conf); preferences.begin(Gateway_Short_Name, false); - preferences.putString("WebUIConfig", conf); + int result = preferences.putString("WebUIConfig", conf); preferences.end(); + Log.trace(F("[WebUI] WebUIConfig_save: %s, result: %d" CR), conf.c_str(), result); return true; } void WebUIConfig_init() { - boolean displayMetric = DISPLAY_METRIC; + displayMetric = DISPLAY_METRIC; + webUISecure = WEBUI_AUTH; Log.notice(F("WebUI config initialised" CR)); } bool WebUIConfig_load() { StaticJsonDocument jsonBuffer; preferences.begin(Gateway_Short_Name, true); - String exists = preferences.getString("WebUIConfig", "{}"); - if (exists != "{}") { + if (preferences.isKey("WebUIConfig")) { auto error = deserializeJson(jsonBuffer, preferences.getString("WebUIConfig", "{}")); preferences.end(); if (error) { @@ -1352,6 +1405,7 @@ bool WebUIConfig_load() { } JsonObject jo = jsonBuffer.as(); displayMetric = jo["displayMetric"].as(); + webUISecure = jo["webUISecure"].as(); return true; } else { preferences.end(); diff --git a/main/config_WebContent.h b/main/config_WebContent.h index 37a671e..64796d0 100644 --- a/main/config_WebContent.h +++ b/main/config_WebContent.h @@ -45,8 +45,8 @@ #else # define configure_3 #endif -#define configure_4 "

" -#define configure_5 +#define configure_4 "

" +#define configure_5 "

" #define configure_6 #define configure_7 #define configure_8 @@ -83,8 +83,6 @@ const char console_body[] = body_header "