Kaynağa Gözat

Auto stash before merge of "master-cmake" and "origin/master-cmake"

Sebastien 4 yıl önce
ebeveyn
işleme
7457632990
53 değiştirilmiş dosya ile 1825 ekleme ve 1220 silme
  1. 2 0
      .gitignore
  2. 0 5
      .pydevproject
  3. 3 1
      build-scripts/ESP32-A1S-sdkconfig.defaults
  4. 3 1
      build-scripts/I2S-4MFlash-sdkconfig.defaults
  5. 3 1
      build-scripts/SqueezeAmp-sdkconfig.defaults
  6. 2 1
      components/platform_console/app_recovery/CMakeLists.txt
  7. 5 1
      components/platform_console/app_recovery/application_name.h
  8. 3 1
      components/platform_console/app_recovery/recovery.c
  9. 3 2
      components/platform_console/app_squeezelite/CMakeLists.txt
  10. 5 1
      components/platform_console/app_squeezelite/application_name.h
  11. 2 2
      components/platform_console/app_squeezelite/cmd_squeezelite.c
  12. 1 1
      components/platform_console/cmd_i2ctools.c
  13. 1 1
      components/wifi-manager/webapp/.eslintcache
  14. 57 36
      components/wifi-manager/webapp/.vscode/tasks.json
  15. 6 1
      components/wifi-manager/webapp/mock/config.json
  16. 8 1
      components/wifi-manager/webapp/mock/messages.json
  17. 51 0
      components/wifi-manager/webapp/mock/messages_ota.json
  18. 21 0
      components/wifi-manager/webapp/mock/messages_ota_fail.json
  19. 2 2
      components/wifi-manager/webapp/mock/status.json
  20. 1 0
      components/wifi-manager/webapp/package.json
  21. 402 331
      components/wifi-manager/webapp/src/index.ejs
  22. 569 129
      components/wifi-manager/webapp/src/js/custom.js
  23. 27 27
      components/wifi-manager/webapp/src/sass/layout/_features.scss
  24. 348 348
      components/wifi-manager/webapp/src/sass/setup/_normalize.scss
  25. 18 18
      components/wifi-manager/webapp/src/sass/utils/_mixins.scss
  26. 36 23
      components/wifi-manager/webapp/src/sass/utils/_style.css
  27. 3 3
      components/wifi-manager/webapp/webapp.cmake
  28. 15 15
      components/wifi-manager/webapp/webpack.c
  29. 25 25
      components/wifi-manager/webapp/webpack.h
  30. BIN
      components/wifi-manager/webapp/webpack/dist/favicon-32x32.png
  31. 0 0
      components/wifi-manager/webapp/webpack/dist/index.html
  32. BIN
      components/wifi-manager/webapp/webpack/dist/index.html.br
  33. BIN
      components/wifi-manager/webapp/webpack/dist/index.html.gz
  34. 0 0
      components/wifi-manager/webapp/webpack/dist/js/index.e644c0.bundle.js
  35. BIN
      components/wifi-manager/webapp/webpack/dist/js/index.e644c0.bundle.js.br
  36. BIN
      components/wifi-manager/webapp/webpack/dist/js/index.e644c0.bundle.js.gz
  37. 0 7
      components/wifi-manager/webapp/webpack/dist/js/node-modules.e644c0.bundle.js
  38. BIN
      components/wifi-manager/webapp/webpack/dist/js/node-modules.e644c0.bundle.js.br
  39. BIN
      components/wifi-manager/webapp/webpack/dist/js/node-modules.e644c0.bundle.js.gz
  40. 0 1
      components/wifi-manager/webapp/webpack/dist/js/runtime.e644c0.bundle.js
  41. BIN
      components/wifi-manager/webapp/webpack/dist/js/runtime.e644c0.bundle.js.br
  42. BIN
      components/wifi-manager/webapp/webpack/dist/js/runtime.e644c0.bundle.js.gz
  43. 0 0
      components/wifi-manager/webapp/webpack/dist/sprite.svg
  44. BIN
      components/wifi-manager/webapp/webpack/dist/sprite.svg.br
  45. 42 9
      components/wifi-manager/webapp/webpack/webpack.dev.js
  46. 71 50
      components/wifi-manager/webapp/webpack/webpack.prod.js
  47. 4 3
      components/wifi-manager/wifi_manager.c
  48. 0 113
      eclipse_make_wrapper.py
  49. 69 50
      main/Kconfig.projbuild
  50. 6 3
      main/esp_app_main.c
  51. 2 2
      main/platform_esp32.h
  52. 8 4
      sdkconfig
  53. 1 1
      version.txt

+ 2 - 0
.gitignore

@@ -98,3 +98,5 @@ test/.vscode/
 
 node_modules/*
 esp-dsp/
+
+components/wifi-manager/webapp/webpack/dist

+ 0 - 5
.pydevproject

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?eclipse-pydev version="1.0"?><pydev_project>
-    <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
-    <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
-</pydev_project>

+ 3 - 1
build-scripts/ESP32-A1S-sdkconfig.defaults

@@ -29,7 +29,9 @@ CONFIG_SPDIF_DO_IO=-1
 CONFIG_DAC_CONFIG="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32"
 CONFIG_MUTE_GPIO=-1
 CONFIG_MUTE_GPIO_LEVEL=-1
-
+CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
+CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
+CONFIG_PROJECT_NAME="Squeezelite-A1S"
 CONFIG_IDF_TARGET_ESP32=y
 CONFIG_IDF_TARGET="esp32"
 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000

+ 3 - 1
build-scripts/I2S-4MFlash-sdkconfig.defaults

@@ -34,7 +34,9 @@ CONFIG_SPDIF_WS_IO=-1
 CONFIG_SPDIF_DO_IO=-1
 CONFIG_MUTE_GPIO=-1
 CONFIG_MUTE_GPIO_LEVEL=-1
-
+CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
+CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
+CONFIG_PROJECT_NAME="Squeezelite-ESP32"
 #
 # SDK tool configuration
 #

+ 3 - 1
build-scripts/SqueezeAmp-sdkconfig.defaults

@@ -32,7 +32,9 @@ CONFIG_SPDIF_NUM=0
 CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
 CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0"
 CONFIG_MUTE_GPIO_LEVEL=-1
-
+CONFIG_PROJECT_NAME="SqueezeAmp"
+CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
+CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
 #
 # SDK tool configuration
 #

+ 2 - 1
components/platform_console/app_recovery/CMakeLists.txt

@@ -5,5 +5,6 @@ idf_component_register( SRC_DIRS .
  
 target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc")	
 idf_build_get_property(project_ver PROJECT_VER)
+message("******************* ${project_ver}")
 string(SUBSTRING "${project_ver}" 0 31 PROJECT_VER_CUT)
-set_source_files_properties(recovery.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"recovery\"")
+set_source_files_properties(recovery.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\"")

+ 5 - 1
components/platform_console/app_recovery/application_name.h

@@ -1,2 +1,6 @@
 #pragma once
-#define PROJECT_NAME "recovery"
+#include "sdkconfig.h"
+#ifndef CONFIG_PROJECT_NAME
+#pragma message "Defaulting project name."
+#define CONFIG_PROJECT_NAME "Squeezelite-ESP32"
+#endif

+ 3 - 1
components/platform_console/app_recovery/recovery.c

@@ -1,13 +1,15 @@
 #include <stdio.h>
 #include <string.h>
+#include "application_name.h"
 #include "esp_err.h"
 #include "esp_app_format.h"
+
 extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length);
 
 const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
     .magic_word = ESP_APP_DESC_MAGIC_WORD,
     .version = PROJECT_VER,
-    .project_name = PROJECT_NAME,
+    .project_name = CONFIG_PROJECT_NAME,
     .idf_ver = IDF_VER,
 
 #ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION

+ 3 - 2
components/platform_console/app_squeezelite/CMakeLists.txt

@@ -1,4 +1,4 @@
- idf_build_get_property(idf_path IDF_PATH)
+idf_build_get_property(idf_path IDF_PATH)
 idf_component_register( SRCS cmd_squeezelite.c 
 						INCLUDE_DIRS . 
 						PRIV_REQUIRES spi_flash bootloader_support  partition_table bootloader_support console codecs squeezelite newlib pthread tools platform_config display )
@@ -13,7 +13,8 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=lround")
 target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=esp_app_desc")
 
 idf_build_get_property(project_ver PROJECT_VER)
+message("******************* ${project_ver}")
 string(SUBSTRING "${project_ver}" 0 31 PROJECT_VER_CUT)
-set_source_files_properties(cmd_squeezelite.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"squeezelite\"")
+set_source_files_properties(cmd_squeezelite.c PROPERTIES COMPILE_DEFINITIONS "PROJECT_VER=\"${PROJECT_VER_CUT}\" ")
 
 

+ 5 - 1
components/platform_console/app_squeezelite/application_name.h

@@ -1,2 +1,6 @@
 #pragma once
-#define PROJECT_NAME "squeezelite"
+#include "sdkconfig.h"
+#ifndef CONFIG_PROJECT_NAME
+#pragma message "Defaulting project name."
+#define CONFIG_PROJECT_NAME "Squeezelite-ESP32"
+#endif

+ 2 - 2
components/platform_console/app_squeezelite/cmd_squeezelite.c

@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <string.h>
-
+#include "application_name.h"
 #include "esp_log.h"
 #include "esp_console.h"
 #include "esp_pthread.h"
@@ -22,7 +22,7 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
 
     .magic_word = ESP_APP_DESC_MAGIC_WORD,
     .version = PROJECT_VER,
-    .project_name = PROJECT_NAME,
+    .project_name = CONFIG_PROJECT_NAME,
     .idf_ver = IDF_VER,
 
 #ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION

+ 1 - 1
components/platform_console/cmd_i2ctools.c

@@ -906,7 +906,7 @@ static void register_i2c_set_display(){
 	i2cdisp_args.cs = 		arg_int0("b", "cs", "<n>","SPI Only. CS GPIO (for SPI displays)");
 	i2cdisp_args.speed = 	arg_int0("s", "speed", "<n>","SPI Only. Bus Speed (Default 8000000). SPI interface can work up to 26MHz~40MHz");
 	i2cdisp_args.back = 	arg_int0("b", "back", "<n>","Backlight GPIO (if applicable)");
-	i2cdisp_args.depth = 	arg_int0("p", "depth", "1|4", "Bit Depth (only for SSD1326 displays)");
+	i2cdisp_args.depth = 	arg_int0("p", "depth", "-1|1|4", "Bit Depth (only for SSD1326 displays)");
 	i2cdisp_args.type = 	arg_str0("t", "type", "<I2C|SPI>", "Interface (default I2C)");
 	i2cdisp_args.rotate = 	arg_lit0("r", "rotate", "Rotate 180 degrees");
 	i2cdisp_args.clear = 	arg_lit0(NULL, "clear", "clear configuration and return");

+ 1 - 1
components/wifi-manager/webapp/.eslintcache

@@ -1 +1 @@
-[{"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\test.js":"1","C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js":"2"},{"size":4775,"mtime":1608244817341,"results":"3","hashOfConfig":"4"},{"size":52524,"mtime":1608525668984,"results":"5","hashOfConfig":"4"},{"filePath":"6","messages":"7","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"8"},"1lj4yrw",{"filePath":"9","messages":"10","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\test.js",[],[],"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js",[]]
+[{"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\test.js":"1","C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js":"2"},{"size":4775,"mtime":1608244817341,"results":"3","hashOfConfig":"4"},{"size":67665,"mtime":1616681036934,"results":"5","hashOfConfig":"4"},{"filePath":"6","messages":"7","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"8"},"1lj4yrw",{"filePath":"9","messages":"10","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\test.js",[],[],"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js",[]]

+ 57 - 36
components/wifi-manager/webapp/.vscode/tasks.json

@@ -1,42 +1,63 @@
 {
     "version": "2.0.0",
     "tasks": [
-        // {
-        //     "label": "build",
-        //     "command": "webpack --config webpack/webpack.prod.js",
-        //     "type": "shell",
-        //     "group": { "kind": "build", "isDefault": true },
-        //     "isBackground": true
-        // },
-          
-        {
-            "type": "npm",
-            "label": "webpack: dev server",
-            "script": "dev",
-            "promptOnClose": true,
-            "isBackground": true,
-            "problemMatcher": {
-              "owner": "webpack",
-              "severity": "error",
-              "fileLocation": "absolute",
-              "pattern": [
-                {
-                  "regexp": "ERROR in (.*)",
-                  "file": 1
-                },
-                {
-                  "regexp": "\\((\\d+),(\\d+)\\):(.*)",
-                  "line": 1,
-                  "column": 2,
-                  "message": 3
-                }
-              ],
-              "background": {
-                "activeOnStart": true,
-                "beginsPattern": "Compiling\\.\\.\\.",
-                "endsPattern": "Compiled successfully\\."
-              }
+      {
+        "type": "npm",
+        "label": "webpack: dev server",
+        "script": "dev",
+        "promptOnClose": true,
+        "isBackground": true,
+        "problemMatcher": {
+          "owner": "webpack",
+          "severity": "error",
+          "fileLocation": "absolute",
+          "pattern": [
+            {
+              "regexp": "ERROR in (.*)",
+              "file": 1
+            },
+            {
+              "regexp": "\\((\\d+),(\\d+)\\):(.*)",
+              "line": 1,
+              "column": 2,
+              "message": 3
             }
-          }        
+          ],
+          "background": {
+            "activeOnStart": true,
+            "beginsPattern": "Compiling\\.\\.\\.",
+            "endsPattern": "Compiled successfully\\."
+          }
+        }
+      },
+      {
+        "type": "npm",
+        "label": "webpack: build",
+        "script": "build",
+        "promptOnClose": true,
+        "isBackground": true,
+        "problemMatcher": {
+          "owner": "webpack",
+          "severity": "error",
+          "fileLocation": "absolute",
+          "pattern": [
+            {
+              "regexp": "ERROR in (.*)",
+              "file": 1
+            },
+            {
+              "regexp": "\\((\\d+),(\\d+)\\):(.*)",
+              "line": 1,
+              "column": 2,
+              "message": 3
+            }
+          ],
+          "background": {
+            "activeOnStart": true,
+            "beginsPattern": "Compiling\\.\\.\\.",
+            "endsPattern": "Compiled successfully\\."
+          }
+        }
+      }
     ]
 }

+ 6 - 1
components/wifi-manager/webapp/mock/config.json

@@ -338,6 +338,11 @@
 			"type": 33,
 			"value": "D",
 			"chg": false
+		},
+		"rel_api": {
+			"type": 33,
+			"value": "https://api.github.com/repos/sle118/squeezelite-esp32/releases",
+			"chg": false
 		}
-	}
+  	}
 }

+ 8 - 1
components/wifi-manager/webapp/mock/messages.json

@@ -67,7 +67,14 @@
 		"sent_time":	6245,
 		"current_time":	6364
 	}, {
-		"message":	"[{\n\t\t\"name\":\t\"SMSL BT4.2\",\n\t\t\"rssi\":\t-129\n\t}]",
+		"message":	"[{\n\t\t\"name\":\t\"BOSE BT\",\n\t\t\"rssi\":\t-129\n\t}]",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_BT",
+		"sent_time":	6259,
+		"current_time":	6364
+	}
+	, {
+		"message":	"[{\n\t\t\"name\":\t\"BOSE2 BT\",\n\t\t\"rssi\":\t-50\n\t}]",
 		"type":	"MESSAGING_INFO",
 		"class":	"MESSAGING_CLASS_BT",
 		"sent_time":	6259,

+ 51 - 0
components/wifi-manager/webapp/mock/messages_ota.json

@@ -0,0 +1,51 @@
+[{
+		"message":	"{\"ota_dsc\":\"Initializing...\",\"ota_pct\":0}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119203,
+		"current_time":	121837
+	}, {
+		"message":	"{\"ota_dsc\":\"Starting OTA...\",\"ota_pct\":0}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	}, {
+		"message":	"{\"ota_dsc\":\"Erasing...\",\"ota_pct\":0}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	}, {
+		"message":	"{\"ota_dsc\":\"Erasing...\",\"ota_pct\":10}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	}, {
+		"message":	"{\"ota_dsc\":\"Erasing...\",\"ota_pct\":100}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	}, {
+		"message":	"{\"ota_dsc\":\"Flashing...\",\"ota_pct\":10}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	}, {
+		"message":	"{\"ota_dsc\":\"Erasing...\",\"ota_pct\":90}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	}, {
+		"message":	"{\"ota_dsc\":\"Success!\",\"ota_pct\":100}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	}
+	
+	]

+ 21 - 0
components/wifi-manager/webapp/mock/messages_ota_fail.json

@@ -0,0 +1,21 @@
+[{
+		"message":	"{\"ota_dsc\":\"Initializing...\",\"ota_pct\":0}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119203,
+		"current_time":	121837
+	}, {
+		"message":	"{\"ota_dsc\":\"Starting OTA...\",\"ota_pct\":0}",
+		"type":	"MESSAGING_INFO",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	119255,
+		"current_time":	121838
+	},
+	{
+		"message":	"{\"ota_dsc\":\"Error: Failed to execute HTTP download. ERROR\",\"ota_pct\":0}",
+		"type":	"MESSAGING_ERROR",
+		"class":	"MESSAGING_CLASS_OTA",
+		"sent_time":	121954,
+		"current_time":	124911
+	}
+	]

+ 2 - 2
components/wifi-manager/webapp/mock/status.json

@@ -1,6 +1,6 @@
 {
-	"project_name": "dev-server",
-	"version": "webpack",
+	"project_name": "SqueezeAMP",
+	"version": "local.500.cmake-master",
 	"recovery": 1,
 	"Jack": "1",
 	"Voltage": 0,

+ 1 - 0
components/wifi-manager/webapp/package.json

@@ -38,6 +38,7 @@
     "popper": "^1.0.1",
     "react": "^17.0.1",
     "remixicon": "^2.5.0",
+    "string-argv": "^0.3.1",
     "stylelint-config-standard": "^20.0.0",
     "svgo": "^1.3.2",
     "webpack-icons-installer": "^2.0.0"

+ 402 - 331
components/wifi-manager/webapp/src/index.ejs

@@ -8,16 +8,16 @@
 	<title>SqueezeESP32</title>
 
 </head>
- 
-<body>
+
+<body class="d-flex flex-column">
 	<div style="display:none">
-        <% if (htmlWebpackPlugin.files.sprites) { %>
-            <% for (var spriteFileName in htmlWebpackPlugin.files.sprites) { %>
-              <%= htmlWebpackPlugin.files.sprites[spriteFileName] %>
-            <% } %>
-          <% }  %>
-        </div>          
-	<nav class="navbar navbar-expand-sm navbar-dark bg-primary" id="mainnav">
+		<% if (htmlWebpackPlugin.files.sprites) { %>
+			<% for (var spriteFileName in htmlWebpackPlugin.files.sprites) { %>
+				<%= htmlWebpackPlugin.files.sprites[spriteFileName] %>
+					<% } %>
+						<% } %>
+	</div>
+	<header class="navbar navbar-expand-sm navbar-dark  bg-primary sticky-top border-bottom border-dark" id="mainnav">
 		<a class="navbar-brand" id="navtitle" href="#">SqueezeESP32</a>
 		<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
 			aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
@@ -40,19 +40,19 @@
 
 		</div>
 		<div class="info navbar-right" style="display: inline-flex;">
-			<svg class="recovery_element bg-primary" style="fill:orange; width:1.5rem; height: 1.5rem;">
+			<svg class="recovery_element " style="fill:orange; width:1.5rem; height: 1.5rem;">
 				<use xlink:href="#device-recover-fill"></use>
 			</svg>
 
 			<svg style="fill:white; width:1.5rem; height: 1.5rem;">
 				<use id="battery" xlink:href="#battery-fill"></use>
 			</svg>
-			<svg  id="o_jack"  style="fill:white; width:1.5rem; height: 1.5rem;">
-				<use  xlink:href="#headphone-fill"></use>
+			<svg id="o_jack" style="fill:white; width:1.5rem; height: 1.5rem;">
+				<use xlink:href="#headphone-fill"></use>
+			</svg>
+			<svg style="fill:white; width:1.5rem; height: 1.5rem;">
+				<use id="o_bt" xlink:href="#bluetooth-fill"></use>
 			</svg>
-			<svg   style="fill:white; width:1.5rem; height: 1.5rem;">
-				<use id="o_bt"   xlink:href="#bluetooth-fill"></use>
-			</svg>	
 			<span data-toggle="tooltip" id="o_type" data-placement="top" title=""><svg
 					xmlns="http://www.w3.org/2000/svg" id="output" width="24" height="24" viewBox="0 0 24 24">
 					<g id="o_i2s" display="none">
@@ -70,370 +70,441 @@
 							d="M3 14L3 15L3 16L3 17L3 18L3 19L3 20L3 21L3 22L4 22L5 22L6 22L7 22L7 21L8 21L8 20L9 20L9 19L9 18L9 17L9 16L8 16L8 15L7 15L7 14L6 14L5 14L3 14z" />
 					</g>
 				</svg></span>
-				<svg   style="fill:white; width:1.5rem; height: 1.5rem;">
-					<use id="wifiStsIcon"   xlink:href="#signal-wifi-fill"></use>
-				</svg>	
-				
+			<svg style="fill:white; width:1.5rem; height: 1.5rem;">
+				<use id="wifiStsIcon" xlink:href="#signal-wifi-fill"></use>
+			</svg>
 
 
+
+		</div>
+	</header>
+	<main role="main" class="flex-grow mt-1 mb-5" id="content">
+		<!-- Button trigger modal -->
+  
+  <!-- Modal -->
+  <div class="modal fade" id="otadiv" tabindex="-1" role="dialog" aria-labelledby="fwProgressLabel" aria-hidden="true">
+	<div class="modal-dialog" role="document">
+	  <div class="modal-content">
+		<div class="modal-header">
+		  <h5 class="modal-title" id="fwProgressLabel">Upgrade Progress</h5>
+		  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+			<span aria-hidden="true">&times;</span>
+		  </button>
 		</div>
-	</nav>
-	<div id="message"></div>
-	<div id="content">
-		<div id="myTabContent" class="tab-content mt-3">
+		<div class="modal-body">
+			<span id="flash-status"></span>
+			<div class="progress" id="progress">
+				<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" style="width:0%">
+					0%
+				</div>
+			</div>
+		</div>
+		<div class="modal-footer">
+		  <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+		</div>
+	  </div>
+	</div>
+  </div>
+		
+		<div id="myTabContent" class="tab-content">
+
 			<div class="tab-pane fade" id="tab-cfg-hw"></div>
 			<div class="tab-pane fade" id="tab-cfg-syst"></div>
 			<div class="tab-pane fade" id="tab-cfg-gen"></div>
 			<div class="tab-pane fade" id="tab-cfg-fw">
-				<div id="boot-div">
-					<form id="boot-form" action="/recovery.json" method="post" target="dummyframe">
-						<button id="boot-button" type="submit" class="btn btn-primary">Recovery</button>
-					</form>
-				</div>
-				<h1>Check for firmware upgrade</h1>
-				<div class="buttons">
-					<input type="button" id="fwcheck" class="btn btn-info" value="Check for updates" />
-				</div>
-				<div id="searchfw" class="form-group">
-					<select class="custom-select" id="fwbranch">
-						<option selected="">Choose FW branch</option>
-					</select>
-					<input class="form-control form-control-sm" id="searchinput" type="text"
-						placeholder="search releases" id="inputSmall">
-				</div>
-				<table class="table table-hover">
-					<thead>
-						<tr>
-							<th scope="col">Firmware version</th>
-							<th scope="col">Release date/time</th>
-							<th scope="col">HW platform</th>
-							<th scope="col">IDF version</th>
-							<th scope="col">Branch</th>
-							<th scope="col">Flash this FW</th>
-						</tr>
-					</thead>
-					<tbody id="releaseTable">
-					</tbody>
-				</table>
-				<h2>Firmware URL:</h2>
-				<textarea id="fwurl" maxlength="1000"></textarea>
-				<div class="buttons">
-					<input type="button" id="flash" class="btn btn-danger" value="Flash!" /><span
-						id="flash-status"></span>
-				</div>
-				<div id="uploaddiv" class="recovery_element">
-					<p>OR</p>
-					<div class="form-group">
-						<input type="file" class="form-control-file" id="flashfilename" aria-describedby="fileHelp">
-						<div class="buttons">
-							<button type="button" class="btn btn-danger" id="fwUpload">Upload!</button>
+				
+				<div class="card text-white  mb-3">
+					<div class="card-header">Software Updates</div>
+					<div class="card-body">
+						<table class="table table-hover table-striped table-dark">
+							<thead>
+								<tr>
+									<th class="border-bottom-0 pb-0" scope="col">Version</th>
+									<th class="border-bottom-0 pb-0" scope="col">Date/Time</th>
+									<th class="border-bottom-0 pb-0" scope="col">Platform</th>
+									<th class="border-bottom-0 pb-0" scope="col">Branch</th>
+									<th class="border-bottom-0 pb-0" scope="col">Bit Depth</th>
+								</tr>
+								<tr>
+									<th class="border-top-0 pt-0" scope="col"><input class="form-control-sm upSrch"
+											id="svrs" type="text" placeholder="search releases"></th>
+									<th class="border-top-0 pt-0" scope="col"></th>
+									<th class="border-top-0 pt-0" scope="col"><input class="form-control-sm  upSrch"
+											id="splf" type="text" placeholder="search platform"></th>
+									<th class="border-top-0 pt-0" scope="col"><select class="form-control-sm  upSrch"
+											id="fwbranch">
+											<option selected="">Choose FW branch</option>
+										</select>
+									<th class="border-top-0 pt-0" scope="col"><input class="form-control-sm upSrch"
+											id="bits" type="text" placeholder="search bit depth"></th>
+									</th>
+								</tr>
+							</thead>
+							<tbody id="rTable"></tbody>
+						</table>
+
+						<div class="form-group row">
+							<div class="col-auto">
+								<button type="button" id="chkUpdates" class="btn btn-info btn-sm">Check for
+									updates</button>
+							</div>
+							<label class="col-auto col-form-label" for="fw-url-input">Firmware URL</label>
+							<div class="col">
+								<input type="text" class="form-control"
+									placeholder="select entry from list or enter known url" id="fw-url-input">
+							</div>
+							<div class="col-auto">
+								<button type="button" id='start-flash' data-toggle="modal" data-target="#uCnfrm"
+									class="btn btn-warning btn-sm" style="display: none;">Flash Firmware</button>
+							</div>
 						</div>
+
 					</div>
 				</div>
-				<div id="otadiv" class="recovery_element">
-					<div class="progress" id="progress">
-						<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100"
-							style="width:0%">
-							0%
+				<div class="modal" id="uCnfrm">
+					<div class="modal-dialog modal-dialog-centered" role="document">
+						<div class="modal-content">
+							<div class="modal-header">
+								<h5 class="modal-title">Firmware Flash</h5>
+								<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+									<span aria-hidden="true">&times;</span>
+								</button>
+							</div>
+							<div class="modal-body">
+								<p>Flash URL <span id="selectedFWURL"></span> to device?</p>
+							</div>
+							<div class="modal-footer  ">
+								<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
+								<button type="button" class="btn btn-warning" data-dismiss="modal"
+									onclick="hFlash();">Ok</button>
+							</div>
 						</div>
 					</div>
 				</div>
-			</div>
-			<div class="tab-pane fade" id="tab-nvs">
-				<table class="table table-hover">
-					<thead>
-						<tr>
-							<th scope="col">Key</th>
-							<th scope="col">Value</th>
-						</tr>
-					</thead>
-					<tbody id="nvsTable">
-					</tbody>
-				</table>
-				<div class="buttons">
-					<div id="boot-div">
-						<form id="reboot-form" action="/reboot.json" method="post" target="dummyframe">
-							<button id="reboot-button" type="submit" class="btn btn-primary">Reboot</button>
-						</form>
+				<div class="card text-white  mb-3">
+					<div class="card-header">Local Firmware Upload</div>
+					<div class="card-body">
+							<div id="uploaddiv" class="recovery_element form-group row">
+									<label for="flashfilename" class="col-auto col-form-label">Local File</label>
+									<div class="col">
+										<input type="file" class="form-control-file" id="flashfilename" aria-describedby="fileHelp">
+								</div>
+								<div class="col-auto">
+									<div class="buttons">
+										<button type="button" class="btn btn-danger" id="fwUpload">Upload!</button>
+									</div>
+								</div>
+							</div>
 					</div>
-					<input id="save-nvs" type="button" class="btn btn-success" value="Commit">
-					<input id="save-as-nvs" type="button" class="btn btn-success" value="Download config">
-					<input id="load-nvs" type="button" class="btn btn-success" value="Load File">
-					<input aria-describedby="fileHelp" onchange="onChooseFile(event, onFileLoad.bind(this))"
-						id="nvsfilename" type="file" style="display:none">
 				</div>
 			</div>
+		
 
-			<div class="tab-pane fade" id="tab-cfg-audio">
-				<div class="card text-white bg-primary mb-3">
-					<div class="card-header">Usage Templates</div>
-					<div class="card-body">
-						<fieldset>
-							<fieldset class="form-group" id="output-tmpl">
-								<legend>Output</legend>
-								<div class="form-check">
-									<label class="form-check-label">
-										<input type="radio" class="form-check-input" name="output-tmpl" id="i2s">
-										I2S Dac
-									</label>
-								</div>
-								<div class="form-check">
-									<label class="form-check-label">
-										<input type="radio" class="form-check-input" name="output-tmpl" id="spdif">
-										SPDIF
-									</label>
-								</div>
-								<div class="form-check">
-									<label class="form-check-label">
-										<input type="radio" class="form-check-input" name="output-tmpl" id="bt">
-										Bluetooth
-									</label>
-								</div>
-							</fieldset>
-							<div class="form-group"><label for="player">Player Name</label><input type="text"
-									class="form-control " placeholder="Squeezelite" id="player"></div>
-							<div class="form-group"><label for="optional">Optional setting (e.g. for LMS IP
-									address)</label><input type="text" class="form-control" id="optional"></div>
-							<div class="form-group">
-								<div class="form-check">
-									<label class="form-check-label">
-										<input class="form-check-input" type="checkbox" id="disable-squeezelite"
-											value="" checked="">
-										Disable Squeezelite
-									</label>
-								</div>
+
+
+		<div class="tab-pane fade" id="tab-nvs">
+			<table class="table table-hover">
+				<thead>
+					<tr>
+						<th scope="col">Key</th>
+						<th scope="col">Value</th>
+					</tr>
+				</thead>
+				<tbody id="nvsTable">
+				</tbody>
+			</table>
+			<div class="buttons">
+				<div id="boot-div">
+					<form id="reboot-form" action="/reboot.json" method="post" target="dummyframe">
+						<button id="reboot-button" type="submit" class="btn btn-primary">Reboot</button>
+					</form>
+				</div>
+				<input id="save-nvs" type="button" class="btn btn-success" value="Commit">
+				<input id="save-as-nvs" type="button" class="btn btn-success" value="Download config">
+				<input id="load-nvs" type="button" class="btn btn-success" value="Load File">
+				<input aria-describedby="fileHelp" onchange="onChooseFile(event, onFileLoad.bind(this))"
+					id="nvsfilename" type="file" style="display:none">
+			</div>
+		</div>
+
+		<div class="tab-pane fade" id="tab-cfg-audio">
+			<div class="card text-white  mb-3">
+				<div class="card-header">Usage Templates</div>
+				<div class="card-body">
+					<fieldset>
+						<fieldset class="form-group" id="output-tmpl">
+							<legend>Output</legend>
+							<div class="form-check">
+								<label class="form-check-label">
+									<input type="radio" class="form-check-input" name="output-tmpl" id="i2s">
+									I2S Dac
+								</label>
 							</div>
-							<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true"
-								style="display: none;" id="toast_cfg-audio-tmpl">
-								<div class="toast-header"><strong class="mr-auto">Result</strong><button type="button"
-										class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close"
-										onclick="hideSurrounding(this)"><span aria-hidden="true">×</span></button></div>
-								<div class="toast-body" id="msg_cfg-audio-tmpl"></div>
+							<div class="form-check">
+								<label class="form-check-label">
+									<input type="radio" class="form-check-input" name="output-tmpl" id="spdif">
+									SPDIF
+								</label>
+							</div>
+							<div class="form-check">
+								<label class="form-check-label">
+									<input type="radio" class="form-check-input" name="output-tmpl" id="bt">
+									Bluetooth
+								</label>
 							</div>
-							<button id="save-autoexec1" type="submit" class="btn btn-info" cmdname="cfg-audio-tmpl"
-								onclick="saveAutoexec1(false)">Save</button>
-							<button id="commit-autoexec1" type="submit" class="btn btn-warning" cmdname="cfg-audio-tmpl"
-								onclick="saveAutoexec1(true)">Apply</button>
 						</fieldset>
-					</div>
+						<div class="form-group"><label for="player">Player Name</label><input type="text"
+								class="form-control " placeholder="Squeezelite" id="player"></div>
+						<div class="form-group"><label for="optional">Optional setting (e.g. for LMS IP
+								address)</label><input type="text" class="form-control" id="optional"></div>
+						<div class="form-group">
+							<div class="form-check">
+								<label class="form-check-label">
+									<input class="form-check-input" type="checkbox" id="disable-squeezelite" value=""
+										checked="">
+									Disable Squeezelite
+								</label>
+							</div>
+						</div>
+						<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true"
+							style="display: none;" id="toast_cfg-audio-tmpl">
+							<div class="toast-header"><strong class="mr-auto">Result</strong><button type="button"
+									class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close"
+									onclick="hideSurrounding(this)"><span aria-hidden="true">×</span></button></div>
+							<div class="toast-body" id="msg_cfg-audio-tmpl"></div>
+						</div>
+						<button id="save-autoexec1" type="submit" class="btn btn-info" cmdname="cfg-audio-tmpl"
+							onclick="saveAutoexec1(false)">Save</button>
+						<button id="commit-autoexec1" type="submit" class="btn btn-warning" cmdname="cfg-audio-tmpl"
+							onclick="saveAutoexec1(true)">Apply</button>
+					</fieldset>
 				</div>
 			</div>
-			<div class="tab-pane fade active show" id="tab-wifi">
-				<div class="card text-white bg-primary mb-3">
-					<div class="card-header">WiFi Status</div>
-					<div class="card-body">
-						<table class="table table-hover">
-							<thead>
-								<tr>
-									<th scope="col">Joined</th>
-									<th scope="col">Name</th>
-									<th scope="col">Signal</th>
-									<th scope="col">Security</th>
-								</tr>
-							</thead>
-							<tbody id="wifiTable"></tbody>
-						</table>
-						<button type="button" id="updateAP" class="btn btn-info btn-sm">Scan</button>
+		</div>
+		<div class="tab-pane fade active show" id="tab-wifi">
+			<div class="card text-white  mb-3">
+				<div class="card-header">WiFi Status</div>
+				<div class="card-body">
+					<table class="table table-hover">
+						<thead>
+							<tr>
+								<th scope="col">Joined</th>
+								<th scope="col">Name</th>
+								<th scope="col">Signal</th>
+								<th scope="col">Security</th>
+							</tr>
+						</thead>
+						<tbody id="wifiTable"></tbody>
+					</table>
+					<button type="button" id="updateAP" class="btn btn-info btn-sm">Scan</button>
 
-					</div>
-					<div class="modal" id="WiFiDisconnectConfirm">
-						<div class="modal-dialog modal-dialog-centered" role="document">
-							<div class="modal-content">
-								<div class="modal-header">
-									<h5 class="modal-title">Disconnect</h5>
-									<button type="button" class="close" data-dismiss="modal" aria-label="Close">
-										<span aria-hidden="true">&times;</span>
-									</button>
-								</div>
-								<div class="modal-body">
-									<p>Disconnect from network? After disconnecting, the system won't be accessible from the current address and will expose itself as access point name <span id="apName"></span> with password <span id="apPass"></span>  </p>
-								</div>
-								<div class="modal-footer connecting-success connecting-status">
-									<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
-									<button type="button" class="btn btn-warning" data-dismiss="modal"
-										onclick="handleDisconnect();">Ok</button>
-								</div>
+				</div>
+				<div class="modal" id="WiFiDisconnectConfirm">
+					<div class="modal-dialog modal-dialog-centered" role="document">
+						<div class="modal-content">
+							<div class="modal-header">
+								<h5 class="modal-title">Disconnect</h5>
+								<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+									<span aria-hidden="true">&times;</span>
+								</button>
+							</div>
+							<div class="modal-body">
+								<p>Disconnect from network? After disconnecting, the system won't be accessible from
+									the current address and will expose itself as access point name <span
+										id="apName"></span> with password <span id="apPass"></span> </p>
+							</div>
+							<div class="modal-footer connecting-success connecting-status">
+								<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
+								<button type="button" class="btn btn-warning" data-dismiss="modal"
+									onclick="handleDisconnect();">Ok</button>
 							</div>
 						</div>
 					</div>
-					<div class="modal" id="WifiConnectDialog">
-						<div class="modal-dialog modal-dialog-centered" role="document">
-							<div class="modal-content">
-								<div class="modal-header">
-									<h5 class="modal-title connecting connecting-init connecting-fail">Connect to WiFi</h5>
-									<h5 class="modal-title connecting-status connecting-success">Status</h5>
-									<button type="button" class="close" data-dismiss="modal" aria-label="Close">
-										<span aria-hidden="true">&times;</span>
-									</button>
-								</div>
-								<div class="modal-body">
-									<fieldset class="connecting-init connecting-fail">
-										<div class="form-group"><label for="manual_ssid">Wifi Name</label><input
-												type="text" class="form-control" placeholder="Enter Name"
-												id="manual_ssid"></div>
-										<div class="form-group"><label for="manual_pwd">Password</label><input
-												type="password" class="form-control" placeholder="Enter Name"
-												id="manual_pwd"></div>
-									</fieldset>
-									<div id="connect-wait" class="connecting">
-										<div>Connecting to <span id="ssid-wait"></span> </div>
+				</div>
+				<div class="modal" id="WifiConnectDialog">
+					<div class="modal-dialog modal-dialog-centered" role="document">
+						<div class="modal-content">
+							<div class="modal-header">
+								<h5 class="modal-title connecting connecting-init connecting-fail">Connect to WiFi
+								</h5>
+								<h5 class="modal-title connecting-status connecting-success">Status</h5>
+								<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+									<span aria-hidden="true">&times;</span>
+								</button>
+							</div>
+							<div class="modal-body">
+								<fieldset class="connecting-init connecting-fail">
+									<div class="form-group"><label for="manual_ssid">Wifi Name</label><input type="text"
+											class="form-control" placeholder="Enter Name" id="manual_ssid"></div>
+									<div class="form-group"><label for="manual_pwd">Password</label><input
+											type="password" class="form-control" placeholder="Enter Name"
+											id="manual_pwd"></div>
+								</fieldset>
+								<div id="connect-wait" class="connecting">
+									<div>Connecting to <span id="ssid-wait"></span> </div>
 									<div>
-												You may lose wifi access while the esp32 recalibrates
-													its radio. Please
-													wait until your device automatically reconnects. This can take up to
-													30s.
-												</div>
-									</div>
-									<div id="connect-success" class="connecting-success connecting-status">
-										<div> Connected to Access Point : <span id="connectedToSSID"></span></div>
-										<div> Device IP address : <span id="ipAddress"></span></div>
-										<div>Subnet Mask:<span id="netmask"></span></div>
-										<div>Default Gateway:<span id="gateway"></span></div>
-									</div>
-									<div id="connect-fail" class="connecting-fail">
-										<h3 class="text-error">Connection failed</h3>
-										<p >Please double-check wifi password if any and make sure the access point has good signal.</p>
+										You may lose wifi access while the esp32 recalibrates
+										its radio. Please
+										wait until your device automatically reconnects. This can take up to
+										30s.
 									</div>
 								</div>
-								<div class="modal-footer ">
-									<button type="button" class="btn btn-secondary connecting-init connecting-fail connecting" data-dismiss="modal">Close</button>
-									<button type="button" id="btnJoin" class="btn btn-primary connecting-init connecting-fail"
-										onclick="handleConnect();">Join</button>
-									<button type="button" class="connecting btn btn-primary" disabled>
-										<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
-											<span class="sr-only">Connecting...</span></button>
+								<div id="connect-success" class="connecting-success connecting-status">
+									<div> Connected to Access Point : <span id="connectedToSSID"></span></div>
+									<div> Device IP address : <span id="ipAddress"></span></div>
+									<div>Subnet Mask:<span id="netmask"></span></div>
+									<div>Default Gateway:<span id="gateway"></span></div>
 								</div>
-
-								<div class="modal-footer connecting-success connecting-status">
-									<button type="button" class="btn btn-warning" data-toggle="modal"
-										data-dismiss="modal" data-target="#WiFiDisconnectConfirm">Disconnect</button>
-									<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
+								<div id="connect-fail" class="connecting-fail">
+									<h3 class="text-error">Connection failed</h3>
+									<p>Please double-check wifi password if any and make sure the access point has
+										good signal.</p>
 								</div>
+							</div>
+							<div class="modal-footer ">
+								<button type="button"
+									class="btn btn-secondary connecting-init connecting-fail connecting"
+									data-dismiss="modal">Close</button>
+								<button type="button" id="btnJoin"
+									class="btn btn-primary connecting-init connecting-fail"
+									onclick="handleConnect();">Join</button>
+								<button type="button" class="connecting btn btn-primary" disabled>
+									<span class="spinner-border spinner-border-sm" role="status"
+										aria-hidden="true"></span>
+									<span class="sr-only">Connecting...</span></button>
+							</div>
 
+							<div class="modal-footer connecting-success connecting-status">
+								<button type="button" class="btn btn-warning" data-toggle="modal" data-dismiss="modal"
+									data-target="#WiFiDisconnectConfirm">Disconnect</button>
+								<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
 							</div>
+
 						</div>
 					</div>
-
 				</div>
+
 			</div>
-			<div class="tab-pane fade " id="tab-commands">
-				<fieldset id="commands-list"></fieldset>
-			</div>
-			<!-- Status -->
-			<div class="tab-pane fade " id="tab-syslog">
-				<div class="card border-primary mb-3">
-					<div class="card-header">Logs</div>
-					<div class="card-body">
-						<table class="table table-hover">
-							<thead>
-								<tr>
-									<th scope="col">Timestamp</th>
-									<th scope="col">Message</th>
-								</tr>
-							</thead>
-							<tbody id="syslogTable">
-							</tbody>
-						</table>
-						<div class="buttons">
-							<input id="clear-syslog" type="button" class="btn btn-danger btn-sm" value="Clear" />
-						</div>
+		</div>
+		<div class="tab-pane fade " id="tab-commands">
+			<fieldset id="commands-list"></fieldset>
+		</div>
+		<!-- Status -->
+		<div class="tab-pane fade " id="tab-syslog">
+			<div class="card border-primary mb-3">
+				<div class="card-header">Logs</div>
+				<div class="card-body">
+					<table class="table table-hover">
+						<thead>
+							<tr>
+								<th scope="col">Timestamp</th>
+								<th scope="col">Message</th>
+							</tr>
+						</thead>
+						<tbody id="syslogTable">
+						</tbody>
+					</table>
+					<div class="buttons">
+						<input id="clear-syslog" type="button" class="btn btn-danger btn-sm" value="Clear" />
 					</div>
 				</div>
-				<div class="card border-primary mb-3">
-					<div class="card-header">Pin Assignments</div>
-					<div class="card-body">
-						<table class="table table-hover">
-							<thead>
-								<tr>
-									<th scope="col">Device</th>
-									<th scope="col">Pin Name</th>
-									<th scope="col">GPIO Number</th>
-									<th scope="col">Type</th>
-								</tr>
-							</thead>
-							<tbody id="gpiotable"></tbody>
-						</table>
-					</div>
+			</div>
+			<div class="card border-primary mb-3">
+				<div class="card-header">Pin Assignments</div>
+				<div class="card-body">
+					<table class="table table-hover">
+						<thead>
+							<tr>
+								<th scope="col">Device</th>
+								<th scope="col">Pin Name</th>
+								<th scope="col">GPIO Number</th>
+								<th scope="col">Type</th>
+							</tr>
+						</thead>
+						<tbody id="gpiotable"></tbody>
+					</table>
 				</div>
-				<div class="card border-primary mb-3" style="visibility: collapse;" id="tasks_sect">
-					<div class="card-header">Tasks</div>
-					<div class="card-body">
-						<table class="table table-hover">
-							<!-- console.log(msg_time.toLocaleString() + '\tname' + '\tcpu' + '\tstate' + '\tminstk' + '\tbprio' + '\tcprio' + '\tnum'); -->
-							<thead>
-								<tr>
-									<th scope="col">#</th>
-									<th scope="col">Task Name</th>
-									<th scope="col">CPU</th>
-									<th scope="col">State</th>
-									<th scope="col">Min Stack</th>
-									<th scope="col">Base Priority</th>
-									<th scope="col">Cur Priority</th>
-								</tr>
-							</thead>
-							<tbody id="tasks"></tbody>
-						</table>
-					</div>
+			</div>
+			<div class="card border-primary mb-3" style="visibility: collapse;" id="tasks_sect">
+				<div class="card-header">Tasks</div>
+				<div class="card-body">
+					<table class="table table-hover">
+						<!-- console.log(msg_time.toLocaleString() + '\tname' + '\tcpu' + '\tstate' + '\tminstk' + '\tbprio' + '\tcprio' + '\tnum'); -->
+						<thead>
+							<tr>
+								<th scope="col">#</th>
+								<th scope="col">Task Name</th>
+								<th scope="col">CPU</th>
+								<th scope="col">State</th>
+								<th scope="col">Min Stack</th>
+								<th scope="col">Base Priority</th>
+								<th scope="col">Cur Priority</th>
+							</tr>
+						</thead>
+						<tbody id="tasks"></tbody>
+					</table>
 				</div>
 			</div>
-			<!-- syslog -->
-			<div class="tab-pane fade " id="tab-credits">
-				<div class="card text-white bg-primary mb-3">
-					<div class="card-header">Credits</div>
-					<div class="card-body">
-						<p><strong><a
-									href="https://github.com/sle118/squeezelite-esp32">squeezelite-esp32</a><br></strong>&copy;
-							2020, philippe44, sle118, daduke<br /><a href="https://opensource.org/licenses/MIT">This
-								software is released under the MIT License.</a></p>
-						<p>
-							This app would not be possible without the following libraries:
-						</p>
-						<ul>
-							<li>squeezelite, &copy; 2012-2019, Adrian Smith and Ralph Irving. Licensed under the GPL
-								License.</li>
-							<li>esp32-wifi-manager, &copy; 2017-2019, Tony Pottier. Licensed under the MIT License.</li>
-							<li>SpinKit, &copy; 2015, Tobias Ahlin. Licensed under the MIT License.</li>
-							<li>jQuery, The jQuery Foundation. Licensed under the MIT License.</li>
-							<li>cJSON, &copy; 2009-2017, Dave Gamble and cJSON contributors. Licensed under the MIT
-								License.
-							</li>
-							<li>esp32-rotary-encoder, &copy; 2011-2019, David Antliff and Ben Buxton. Licensed under the
-								GPL
-								License.</li>
-							<li>tarablessd1306, &copy; 2017-2018, Tara Keeling. Licensed under the MIT license.</li>
-						</ul>
-					</div>
+		</div>
+		<!-- syslog -->
+		<div class="tab-pane fade " id="tab-credits">
+			<div class="card text-white  mb-3">
+				<div class="card-header">Credits</div>
+				<div class="card-body">
+					<p><strong><a
+								href="https://github.com/sle118/squeezelite-esp32">squeezelite-esp32</a><br></strong>&copy;
+						2020, philippe44, sle118, daduke<br /><a href="https://opensource.org/licenses/MIT">This
+							software is released under the MIT License.</a></p>
+					<p>
+						This app would not be possible without the following libraries:
+					</p>
+					<ul>
+						<li>squeezelite, &copy; 2012-2019, Adrian Smith and Ralph Irving. Licensed under the GPL
+							License.</li>
+						<li>esp32-wifi-manager, &copy; 2017-2019, Tony Pottier. Licensed under the MIT License.</li>
+						<li>SpinKit, &copy; 2015, Tobias Ahlin. Licensed under the MIT License.</li>
+						<li>jQuery, The jQuery Foundation. Licensed under the MIT License.</li>
+						<li>cJSON, &copy; 2009-2017, Dave Gamble and cJSON contributors. Licensed under the MIT
+							License.
+						</li>
+						<li>esp32-rotary-encoder, &copy; 2011-2019, David Antliff and Ben Buxton. Licensed under the
+							GPL
+							License.</li>
+						<li>tarablessd1306, &copy; 2017-2018, Tara Keeling. Licensed under the MIT license.</li>
+					</ul>
 				</div>
-				<div class="card text-white bg-primary mb-3">
-					<div class="card-header">Extras/Overrides</div>
-					<div class="card-body">
-						<fieldset>
-							<div class="form-check">
-								<label class="form-check-label"><input type="checkbox" id="show-nvs"
-										class="form-check-input " value="">Show NVS Editor</label>
-							</div>
-						</fieldset>
-						<fieldset>
-							<div class="form-check">
-								<label class="form-check-label"><input type="checkbox" id="show-commands"
-										class="form-check-input " value="">Show Advanced Commands</label>
-							</div>
-						</fieldset>
-					</div>
+			</div>
+			<div class="card text-white  mb-3">
+				<div class="card-header">Extras/Overrides</div>
+				<div class="card-body">
+					<fieldset>
+						<div class="form-check">
+							<label class="form-check-label"><input type="checkbox" id="show-nvs"
+									class="form-check-input " value="">Show NVS Editor</label>
+						</div>
+					</fieldset>
+					<fieldset>
+						<div class="form-check">
+							<label class="form-check-label"><input type="checkbox" id="show-commands"
+									class="form-check-input " value="">Show Advanced Commands</label>
+						</div>
+					</fieldset>
 				</div>
 			</div>
-			<!-- credits -->
 		</div>
-
+		<!-- credits -->
+		</div>
 	</div>
-	<footer class="footer bg-primary text.primary">
-		<button class="btn-warning ota_element" id="reboot_nav" type="submit" onclick="handleReboot(false);"
-			style="display: none;">Reboot</button>
-		<button class="btn-danger recovery_element" id="reboot_ota_nav" type="submit" onclick="handleReboot(true);"
-			style="display: none;">Exit Recovery</button><br>
-		<span id="foot-fw"></span><span id="foot-wifi"></span>
+	</main>
+	<footer>
+		<div class="fixed-bottom d-flex justify-content-between  border-top border-dark p-3 bg-primary">
+			<span class="text-center" id="foot-fw"></span><button class="btn-warning ota_element " id="reboot_nav"
+				type="submit" onclick="handleReboot(false);" style="display: none;">Reboot</button>
+			<button class="btn-warning recovery_element" id="reboot_ota_nav" type="submit" onclick="handleReboot(true);"
+				style="display: none;">Exit Recovery</button><span class="text-center" id="foot-wifi"></span>
+		</div>
+
 	</footer>
-	</div>
 </body>
 
 </html>

+ 569 - 129
components/wifi-manager/webapp/src/js/custom.js

@@ -97,24 +97,347 @@ const connectReturnCode = {
 }
 const taskStates = {
   0: 'eRunning',
-
   /*! < A task is querying the state of itself, so must be running. */
   1: 'eReady',
-
   /*! < The task being queried is in a read or pending ready list. */
   2: 'eBlocked',
-
   /*! < The task being queried is in the Blocked state. */
   3: 'eSuspended',
-
   /*! < The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */
   4: 'eDeleted',
 };
+const flash_status_codes = {
+  NONE : 0,
+  DOWNLOADING_FILE: 1,
+  REBOOT_TO_RECOVERY: 2,
+  CHECK_FOR_UPLOAD: 3,
+  UPLOADING: 4,
+  SET_FWURL: 5,
+  FLASHING: 6,
+  DOWNLOADING_COMPLETE: 7,
+};
+let flash_state=flash_status_codes.FLASH_NONE;
+let flash_ota_dsc='';
+let flash_ota_pct=0;
+function isFlashExecuting(){
+  return flash_ota_dsc!='' || flash_ota_pct>0;
+}
+// function z(){
+  
+//   const data = {
+//     timestamp: Date.now(),
+//   };
+//   if (blockFlashButton) {
+//     return;
+//   }
+//   blockFlashButton = true;
+//   const url = $('#fw-url-input').val();
+//   data.config = {
+//     fwurl: {
+//       value: url,
+//       type: 33,
+//     },
+//   };
+
+//   $.ajax({
+//     url: '/config.json',
+//     dataType: 'text',
+//     method: 'POST',
+//     cache: false,
+//     contentType: 'application/json; charset=utf-8',
+//     data: JSON.stringify(data),
+//     error: handleExceptionResponse,
+//   });
+// }
+const flash_events={
+  START_OTA : function(data) {
+    if (flash_state == flash_status_codes.NONE) {
+      console.log('Starting OTA process');
+      flash_state=flash_status_codes.DOWNLOADING_FILE;
+      // 1. Create a new XMLHttpRequest object
+      let xhr = new XMLHttpRequest();
+      
+      // 2. Configure it: GET-request for the URL /article/.../load
+      xhr.open('GET', data.url);
+      xhr.responseType = "blob";
+      // 4. This will be called after the response is received
+      xhr.onload = function() {
+        if (xhr.status != 200) { // analyze HTTP status of the response
+          console.log(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found
+        } else { // show the result
+          console.log(`Done, got ${xhr.response.length} bytes`); // response is the server response
+        }
+      };
+
+      xhr.onprogress = function(event) {
+        if (event.lengthComputable) {
+          console.log(`Received ${event.loaded} of ${event.total} bytes`);
+        } else {
+          console.log(`Received ${event.loaded} bytes`); // no Content-Length
+        }
+
+      };
 
+      xhr.onerror = function() {
+        console.log("Request failed");
+      };      
+      xhr.send();
+    }
+    else {
+      console.warn('Unexpected status while starting flashing');
+    }    
+
+  },
+  FOUND_RECOVERY: function(data) {
+    console.log(JSON.stringify(data));
+    switch (flash_state) {
+      case flash_status_codes.NONE:
+          console.log('Current Flash state is NONE');
+        break;
+        case flash_status_codes.DOWNLOADING_FILE:
+          console.log('DOWNLOADING_FILE');
+        break;
+        case flash_status_codes.DOWNLOADING_COMPLETE:
+          console.log('DOWNLOADING_COMPLETE');
+        break;        
+        case flash_status_codes.REBOOT_TO_RECOVERY:
+          console.log('REBOOT_TO_RECOVERY');
+        break;
+        case flash_status_codes.CHECK_FOR_UPLOAD:
+          console.log('CHECK_FOR_UPLOAD');
+        break;
+        case flash_status_codes.UPLOADING:
+          console.log('UPLOADING');
+        break;
+        case flash_status_codes.SET_FWURL:
+          console.log('SET_FWURL');
+        break;
+        case flash_status_codes.FLASHING:
+          console.log('FLASHING');
+        break;
+    
+      default:
+        break;
+    }
+  },
+  UPLOAD_YES: function(data) {
+    console.log(JSON.stringify(data));
+    switch (flash_state) {
+      case flash_status_codes.NONE:
+
+          console.log('Current Flash state is NONE');
+        break;
+        case flash_status_codes.DOWNLOADING_FILE:
+          console.log('DOWNLOADING_FILE');
+        break;
+        case flash_status_codes.DOWNLOADING_COMPLETE:
+          console.log('DOWNLOADING_COMPLETE');
+        break;        
+        case flash_status_codes.REBOOT_TO_RECOVERY:
+          console.log('REBOOT_TO_RECOVERY');
+        break;
+        case flash_status_codes.CHECK_FOR_UPLOAD:
+          console.log('CHECK_FOR_UPLOAD');
+        break;
+        case flash_status_codes.UPLOADING:
+          console.log('UPLOADING');
+        break;
+        case flash_status_codes.SET_FWURL:
+          console.log('SET_FWURL');
+        break;
+        case flash_status_codes.FLASHING:
+          console.log('FLASHING');
+        break;
+    
+      default:
+        break;
+    }
+  },
+  UPLOAD_NO: function(data) {
+    console.log(JSON.stringify(data));
+
+    switch (flash_state) {
+      case flash_status_codes.NONE:
+
+          console.log('Current Flash state is NONE');
+        break;
+        case flash_status_codes.DOWNLOADING_FILE:
+          console.log('DOWNLOADING_FILE');
+        break;
+        case flash_status_codes.DOWNLOADING_COMPLETE:
+          console.log('DOWNLOADING_COMPLETE');
+        break;        
+        case flash_status_codes.REBOOT_TO_RECOVERY:
+          console.log('REBOOT_TO_RECOVERY');
+        break;
+        case flash_status_codes.CHECK_FOR_UPLOAD:
+          console.log('CHECK_FOR_UPLOAD');
+        break;
+        case flash_status_codes.UPLOADING:
+          console.log('UPLOADING');
+        break;
+        case flash_status_codes.SET_FWURL:
+          console.log('SET_FWURL');
+        break;
+        case flash_status_codes.FLASHING:
+          console.log('FLASHING');
+        break;
+    
+      default:
+        break;
+    }
+  },
+  DOWNLOAD_COMPLETE: function(data) {
+    console.log(JSON.stringify(data));
+
+    switch (flash_state) {
+      case flash_status_codes.NONE:
+
+          console.log('Current Flash state is NONE');
+        break;
+        case flash_status_codes.DOWNLOADING_FILE:
+          console.log('DOWNLOADING_FILE');
+        break;
+        case flash_status_codes.DOWNLOADING_COMPLETE:
+          console.log('DOWNLOADING_COMPLETE');
+        break;        
+        case flash_status_codes.REBOOT_TO_RECOVERY:
+          console.log('REBOOT_TO_RECOVERY');
+        break;
+        case flash_status_codes.CHECK_FOR_UPLOAD:
+          console.log('CHECK_FOR_UPLOAD');
+        break;
+        case flash_status_codes.UPLOADING:
+          console.log('UPLOADING');
+        break;
+        case flash_status_codes.SET_FWURL:
+          console.log('SET_FWURL');
+        break;
+        case flash_status_codes.FLASHING:
+          console.log('FLASHING');
+        break;
+    
+      default:
+        break;
+    }
+  },
+  MESSAGES: function(data) {
+    console.log(JSON.stringify(data));
+    if(data.ota_dsc){
+      flash_ota_dsc=data.ota_dsc;
+    }
+    if(data.ota_pct){
+      flash_ota_pct=data.ota_pct;
+    }
+    switch (flash_state) {
+      case flash_status_codes.NONE:
+
+          console.log('Current Flash state is NONE');
+        break;
+        case flash_status_codes.DOWNLOADING_FILE:
+          console.log('DOWNLOADING_FILE');
+        break;
+        case flash_status_codes.DOWNLOADING_COMPLETE:
+          console.log('DOWNLOADING_COMPLETE');
+        break;        
+        case flash_status_codes.REBOOT_TO_RECOVERY:
+          console.log('REBOOT_TO_RECOVERY');
+        break;
+        case flash_status_codes.CHECK_FOR_UPLOAD:
+          console.log('CHECK_FOR_UPLOAD');
+        break;
+        case flash_status_codes.UPLOADING:
+          console.log('UPLOADING');
+        break;
+        case flash_status_codes.SET_FWURL:
+          console.log('SET_FWURL');
+        break;
+        case flash_status_codes.FLASHING:
+          console.log('FLASHING');
+        break;
+    
+      default:
+        break;
+    }    
+  },
+  STATUS: function(data) {
+    console.log(JSON.stringify(data));
+
+    if(data.ota_dsc){
+      flash_ota_dsc=data.ota_dsc;
+    }
+    if(data.ota_pct){
+      flash_ota_pct=data.ota_pct;
+    }
+    switch (flash_state) {
+      case flash_status_codes.NONE:
+
+          console.log('Current Flash state is NONE');
+        break;
+        case flash_status_codes.DOWNLOADING_FILE:
+          console.log('DOWNLOADING_FILE');
+        break;
+        case flash_status_codes.DOWNLOADING_COMPLETE:
+          console.log('DOWNLOADING_COMPLETE');
+        break;        
+        case flash_status_codes.REBOOT_TO_RECOVERY:
+          console.log('REBOOT_TO_RECOVERY');
+        break;
+        case flash_status_codes.CHECK_FOR_UPLOAD:
+          console.log('CHECK_FOR_UPLOAD');
+        break;
+        case flash_status_codes.UPLOADING:
+          console.log('UPLOADING');
+        break;
+        case flash_status_codes.SET_FWURL:
+          console.log('SET_FWURL');
+        break;
+        case flash_status_codes.FLASHING:
+          console.log('FLASHING');
+        break;
+    
+      default:
+        break;
+    }    
+  }
+};
 window.hideSurrounding = function(obj){
-  $(obj).parent().parent().hide()
+  $(obj).parent().parent().hide();
 }
 
+
+function handle_flash_state(data) {
+  if(isFlashExecuting()) {
+    flash_state= flash_status_codes.FLASHING;
+  }
+  if(data.event)  {
+    data.event(data);
+  } 
+
+
+  if(flash_state!=flash_status_codes.NONE){
+    $('#otadiv').modal();
+    if (flash_ota_pct !== 0) {
+      $('.progress-bar')
+        .css('width', flash_ota_pct + '%')
+        .attr('aria-valuenow', flash_ota_pct);
+      $('.progress-bar').html(flash_ota_pct + '%');
+    }
+    if (flash_ota_dsc !== '') {
+      $('span#flash-status').html(flash_ota_dsc);
+      if ((data.type ?? '') === 'MESSAGING_ERROR' || flash_ota_pct > 95) {
+        //blockFlashButton = false;
+      }
+    }      
+  }
+  else {
+    flash_ota_pct=0;
+    flash_ota_dsc='';
+  }
+}
+window.hFlash = function(){
+  handle_flash_state({ event: flash_events.START_OTA, url: $('#fw-url-input').val() });
+}
 window.handleReboot = function(ota){
   if(ota){
     $('#reboot_ota_nav').removeClass('active'); delayReboot(500,'', true);
@@ -167,7 +490,6 @@ function handleTemplateTypeRadio(outtype) {
 function handleExceptionResponse(xhr, _ajaxOptions, thrownError) {
   console.log(xhr.status);
   console.log(thrownError);
-  enableStatusTimer = true;
   if (thrownError !== '') {
     showLocalMessage(thrownError, 'MESSAGING_ERROR');
   }
@@ -205,14 +527,13 @@ function showCmdMessage(cmdname, msgtype, msgtext, append = false) {
   $('#msg_' + cmdname).html(escapedtext);
 }
 
-const releaseURL =
+let releaseURL =
   'https://api.github.com/repos/sle118/squeezelite-esp32/releases';
+  
 let recovery = false;
-var enableStatusTimer = true;
 const commandHeader = 'squeezelite -b 500:2000 -d all=info -C 30 -W';
-let otapct, otadsc;
 let blockAjax = false;
-let blockFlashButton = false;
+//let blockFlashButton = false;
 let apList = null;
 //let selectedSSID = '';
 //let checkStatusInterval = null;
@@ -224,8 +545,9 @@ let SystemConfig={};
 let LastCommandsState = null;
 var output = '';
 let hostName = '';
-let versionName='SqueezeESP32';
-let appTitle=versionName;
+let versionName='Squeezelite-ESP32';
+let project_name=versionName;
+let btSinkNamesOptSel='#cfg-audio-bt_source-sink_name';
 let ConnectedToSSID={};
 let ConnectingToSSID={};
 const ConnectingToActions = {
@@ -356,7 +678,6 @@ function onChooseFile(event, onLoadFileHandler) {
 function delayReboot(duration, cmdname, ota = false) {
   const url = ota ? '/reboot_ota.json' : '/reboot.json';
   $('tbody#tasks').empty();
-  enableStatusTimer = false;
   $('#tasks_sect').css('visibility', 'collapse');
   Promise.resolve({ cmdname: cmdname, url: url })
     .delay(duration)
@@ -384,7 +705,6 @@ function delayReboot(duration, cmdname, ota = false) {
         error: handleExceptionResponse,
         complete: function() {
           console.log('reboot call completed');
-          enableStatusTimer = true;
           Promise.resolve(data)
             .delay(6000)
             .then(function(rdata) {
@@ -505,7 +825,40 @@ window.handleConnect = function(){
 
 }
 $(document).ready(function() {
+  $('#wifiTable').on('click','tr', function() {
+
+  });
+  $('#fw-url-input').on('input', function() {
+    if($(this).val().length>8 && ($(this).val().startsWith('http://') || $(this).val().startsWith('https://'))){
+      $('#start-flash').show();
+    } 
+    else {
+      $('#start-flash').hide();
+    }
+  });
+  $('.upSrch').on('input', function() {
+    const val = this.value;
+    
+    if(val.length==0) {
+      $("#rTable tr").removeClass(this.id+'_hide');
+    }
+    else {
+      $(`#rTable td:nth-child(${$(this).parent().index()+1})`).filter(function(){ 
+        return !$(this).text().toUpperCase().includes(val.toUpperCase());
+      }).parent().addClass(this.id+'_hide');
+    }
+    $('[class*="_hide"]').hide();
+    $('#rTable tr').not('[class*="_hide"]').show()
+
+  });
   setTimeout(refreshAP,1500);
+
+  
+  $('#otadiv').on('hidden.bs.modal', function () {
+    // reset flash status. This should stop the state machine from
+    // executing steps up to flashing itself.
+    flash_state=flash_status_codes.NONE;
+  });
   $('#WifiConnectDialog').on('shown.bs.modal', function () {
     $("*[class*='connecting']").hide();
     if(ConnectingToSSID.Action!==ConnectingToActions.STS){
@@ -520,7 +873,10 @@ $(document).ready(function() {
     $('#WifiConnectDialog input').val('');
   })
   
-  
+  $('#uCnfrm').on('shown.bs.modal', function () {
+    $('#selectedFWURL').text($('#fw-url-input').val());
+  })
+ 
   $('input#show-commands')[0].checked = LastCommandsState === 1;
   $('a[href^="#tab-commands"]').hide();
   $('#load-nvs').on('click', function() {
@@ -704,41 +1060,112 @@ $(document).ready(function() {
       xhttp.open('POST', uploadPath, true);
       xhttp.send(file);
     }
-    enableStatusTimer = true;
   });
-  $('#flash').on('click', function() {
-    const data = {
-      timestamp: Date.now(),
-    };
-    if (blockFlashButton) {
-      return;
-    }
-    blockFlashButton = true;
-    const url = $('#fwurl').val();
-    data.config = {
-      fwurl: {
-        value: url,
-        type: 33,
-      },
-    };
+  // $('#flash').on('click', function() {
+  //   const data = {
+  //     timestamp: Date.now(),
+  //   };
+  //   if (blockFlashButton) {
+  //     return;
+  //   }
+  //   blockFlashButton = true;
+  //   const url = $('#fwurl').val();
+  //   data.config = {
+  //     fwurl: {
+  //       value: url,
+  //       type: 33,
+  //     },
+  //   };
 
-    $.ajax({
-      url: '/config.json',
-      dataType: 'text',
-      method: 'POST',
-      cache: false,
-      contentType: 'application/json; charset=utf-8',
-      data: JSON.stringify(data),
-      error: handleExceptionResponse,
-    });
-    enableStatusTimer = true;
-  });
+  //   $.ajax({
+  //     url: '/config.json',
+  //     dataType: 'text',
+  //     method: 'POST',
+  //     cache: false,
+  //     contentType: 'application/json; charset=utf-8',
+  //     data: JSON.stringify(data),
+  //     error: handleExceptionResponse,
+  //   });
+  //   enableStatusTimer = true;
+  // });
 
   $('[name=output-tmpl]').on('click', function() {
     handleTemplateTypeRadio(this.id);
   });
 
-  $('#fwcheck').on('click', function() {
+  $('#chkUpdates').on('click', function() {
+    $('#rTable').html('');
+    $.getJSON(releaseURL, function(data) {
+      let i = 0;
+      const branches = [];
+      data.forEach(function(release) {
+        const namecomponents = release.name.split('#');
+        const branch = namecomponents[3];
+        if (!branches.includes(branch)) {
+          branches.push(branch);
+        }
+      });
+      let fwb='';
+      branches.forEach(function(branch) {
+        fwb += '<option value="' + branch + '">' + branch + '</option>';
+      });
+      $('#fwbranch').append(fwb);
+
+      data.forEach(function(release) {
+        let url = '';
+        release.assets.forEach(function(asset) {
+          if (asset.name.match(/\.bin$/)) {
+            url = asset.browser_download_url;
+          }
+        });
+        const namecomponents = release.name.split('#');
+        const ver = namecomponents[0];
+        const cfg = namecomponents[2];
+        const branch = namecomponents[3];
+        var bits = ver.substr(ver.lastIndexOf('-')+1);
+        bits = (bits =='32' || bits == '16')?bits:'';
+
+        let body = release.body;
+        body = body.replace(/'/gi, '"');
+        body = body.replace(
+          /[\s\S]+(### Revision Log[\s\S]+)### ESP-IDF Version Used[\s\S]+/,
+          '$1'
+        );
+        body = body.replace(/- \(.+?\) /g, '- ');
+        $('#rTable').append(`<tr class='release ' fwurl='${url}'>
+        <td data-toggle='tooltip' title='${body}'>${ver}</td><td>${new Date(release.created_at).toLocalShort()}
+        </td><td class='upf'>${cfg}</td><td>${branch}</td><td>${bits}</td></tr>`
+        );
+      });
+      if (i > 7) {
+        $('#releaseTable').append(
+          "<tr id='showall'>" +
+            "<td colspan='6'>" +
+            "<input type='button' id='showallbutton' class='btn btn-info' value='Show older releases' />" +
+            '</td>' +
+            '</tr>'
+        );
+        $('#showallbutton').on('click', function() {
+          $('tr.hide').removeClass('hide');
+          $('tr#showall').addClass('hide');
+        });
+      }
+      $('#searchfw').css('display', 'inline');
+      if($('.upf').filter(function(){ return $(this).text().toUpperCase()===project_name.toUpperCase()}).length>0){
+        $('#splf').val(project_name).trigger('input');
+      }
+      $('#rTable tr.release').on('click', function() {
+        $('#fw-url-input').val(this.attributes['fwurl'].value);
+        $('#start-flash').show();
+        $('#rTable tr.release').removeClass('table-success table-warning');
+        $(this).addClass('table-success table-warning');
+      });
+
+    }).fail(function() {
+      alert('failed to fetch release history!');
+    });    
+  });
+    $('#fwcheck').on('click', function() {    
     $('#releaseTable').html('');
     $('#fwbranch').empty();
     $.getJSON(releaseURL, function(data) {
@@ -824,61 +1251,54 @@ $(document).ready(function() {
     });
   });
 
-  $('input#searchinput').on('input', function() {
-    const s = $('input#searchinput').val();
-    const re = new RegExp(s, 'gi');
-    if (s.length === 0) {
-      $('tr.release').removeClass('hide');
-    } else if (s.length < 3) {
-      $('tr.release').addClass('hide');
-    } else {
-      $('tr.release').addClass('hide');
-      $('tr.release').each(function() {
-        $(this)
-          .find('td')
-          .each(function() {
-            if (
-              $(this)
-                .html()
-                .match(re)
-            ) {
-              $(this)
-                .parent()
-                .removeClass('hide');
-            }
-          });
-      });
-    }
-  });
-
-  $('#fwbranch').on('change', function() {
-    const branch = this.value;
-    const re = new RegExp('^' + branch + '$', 'gi');
-    $('tr.release').addClass('hide');
-    $('tr.release').each(function() {
-      $(this)
-        .find('td')
-        .each(function() {
-          console.log($(this).html());
-          if (
-            $(this)
-              .html()
-              .match(re)
-          ) {
-            $(this)
-              .parent()
-              .removeClass('hide');
-          }
-        });
-    });
-  });
+  // $('input#searchinput').on('input', function() {
+  //   const s = $('input#searchinput').val();
+  //   const re = new RegExp(s, 'gi');
+  //   if (s.length === 0) {
+  //     $('tr.release').removeClass('hide');
+  //   } else if (s.length < 3) {
+  //     $('tr.release').addClass('hide');
+  //   } else {
+  //     $('tr.release').addClass('hide');
+  //     $('tr.release').each(function() {
+  //       $(this)
+  //         .find('td')
+  //         .each(function() {
+  //           if (
+  //             $(this)
+  //               .html()
+  //               .match(re)
+  //           ) {
+  //             $(this)
+  //               .parent()
+  //               .removeClass('hide');
+  //           }
+  //         });
+  //     });
+  //   }
+  // });
 
-  $('#boot-button').on('click', function() {
-    enableStatusTimer = true;
-  });
-  $('#reboot-button').on('click', function() {
-    enableStatusTimer = true;
-  });
+  // $('#fwbranch').on('change', function() {
+  //   const branch = this.value;
+  //   const re = new RegExp('^' + branch + '$', 'gi');
+  //   $('tr.release').addClass('hide');
+  //   $('tr.release').each(function() {
+  //     $(this)
+  //       .find('td')
+  //       .each(function() {
+  //         console.log($(this).html());
+  //         if (
+  //           $(this)
+  //             .html()
+  //             .match(re)
+  //         ) {
+  //           $(this)
+  //             .parent()
+  //             .removeClass('hide');
+  //         }
+  //       });
+  //   });
+  // });
 
   $('#updateAP').on('click', function() {
     refreshAP();
@@ -1023,7 +1443,7 @@ function refreshAPHTML2(data) {
       $('#wifiTable').prepend(`${formatAP(ConnectedToSSID.ssid, ConnectedToSSID.rssi ?? 0, 0)}`);
     }
     $(wifiSelector).filter(function() {return $(this).text() === ConnectedToSSID.ssid;  }).siblings().first().html('&check;').parent().addClass((ConnectedToSSID.urc === connectReturnCode.UPDATE_CONNECTION_OK?'table-success':'table-warning'));
-    $('span#foot-wifi').html(`, SSID: <strong>${ConnectedToSSID.ssid}</strong>, IP: <strong>${ConnectedToSSID.ip}</strong>`);    
+    $('span#foot-wifi').html(`SSID: <strong>${ConnectedToSSID.ssid}</strong>, IP: <strong>${ConnectedToSSID.ip}</strong>`);    
     $('#wifiStsIcon').attr('xlink:href',rssiToIcon(ConnectedToSSID.rssi));
   }
   else {
@@ -1067,6 +1487,12 @@ function showTask(task) {
       '</td></tr>'
   );
 }
+function btExists(name){
+  return getBTSinkOpt(name).length>0;
+}
+function getBTSinkOpt(name){
+  return $(`${btSinkNamesOptSel} option:contains('${name}')`);
+}
 function getMessages() {
   $.getJSON('/messages.json?1', async function(data) {
     for (const msg of data) {
@@ -1075,23 +1501,13 @@ function getMessages() {
       msgTime.setTime(msgTime.getTime() - msgAge);
       switch (msg.class) {
         case 'MESSAGING_CLASS_OTA':
-          // message: "{"ota_dsc":"Erasing flash complete","ota_pct":0}"
           var otaData = JSON.parse(msg.message);
-          if ((otaData.ota_pct ?? 0) !== 0) {
-            otapct = otaData.ota_pct;
-            $('.progress-bar')
-              .css('width', otapct + '%')
-              .attr('aria-valuenow', otapct);
-            $('.progress-bar').html(otapct + '%');
-          }
-          if ((otaData.ota_dsc ??'') !== '') {
-            otadsc = otaData.ota_dsc;
-            $('span#flash-status').html(otadsc);
-            if (msg.type === 'MESSAGING_ERROR' || otapct > 95) {
-              blockFlashButton = false;
-              enableStatusTimer = true;
-            }
-          }
+          handle_flash_state({
+            ota_pct: (otaData.ota_pct ?? 0),
+            ota_dsc: (otaData.ota_dsc ??''),
+            type: msg.type,
+            event: flash_events.MESSAGES
+          });
           break;
         case 'MESSAGING_CLASS_STATS':
           // for task states, check structure : task_state_t
@@ -1134,9 +1550,34 @@ function getMessages() {
           showCmdMessage(msgparts[1], msg.type, msgparts[2], true);
           break;
         case 'MESSAGING_CLASS_BT':
+          if($("#cfg-audio-bt_source-sink_name").is('input')){
+          var attr=$("#cfg-audio-bt_source-sink_name")[0].attributes;
+          var attrs='';
+          for (var j = 0; j < attr.length; j++) {
+              if(attr.item(j).name!="type"){
+                attrs+=`${attr.item(j).name } = "${attr.item(j).value}" `;
+              }
+          }
+          var curOpt=$("#cfg-audio-bt_source-sink_name")[0].value;
+            $("#cfg-audio-bt_source-sink_name").replaceWith(`<select id="cfg-audio-bt_source-sink_name" ${attrs}><option value="${curOpt}" data-description="${curOpt}">${curOpt}</option></select> `);
+          }
           JSON.parse(msg.message).forEach(function(btEntry) {
-            showMessage({ type:msg.type, message:`BT Audio device found: ${btEntry.name} RSSI: ${btEntry.rssi} `}, msgTime);
+            //<input type="text" class="form-control bg-success" placeholder="name" hasvalue="true" longopts="sink_name" shortopts="n" checkbox="false" cmdname="cfg-audio-bt_source" id="cfg-audio-bt_source-sink_name" name="cfg-audio-bt_source-sink_name">
+            //<select hasvalue="true" longopts="jack_behavior" shortopts="j" checkbox="false" cmdname="cfg-audio-general" id="cfg-audio-general-jack_behavior" name="cfg-audio-general-jack_behavior" class="form-control "><option>--</option><option>Headphones</option><option>Subwoofer</option></select>            
+            if(!btExists(btEntry.name)){
+              $("#cfg-audio-bt_source-sink_name").append(`<option>${btEntry.name}</option>`);
+              showMessage({ type:msg.type, message:`BT Audio device found: ${btEntry.name} RSSI: ${btEntry.rssi} `}, msgTime);
+            }
+            getBTSinkOpt(btEntry.name).attr('data-description', `${btEntry.name} (${btEntry.rssi}dB)`)
+                                      .attr('rssi',btEntry.rssi)
+                                      .attr('value',btEntry.name)
+                                      .text(`${btEntry.name} [${btEntry.rssi}dB]`).trigger('change');
+            
           });
+          $(btSinkNamesOptSel).append($(`${btSinkNamesOptSel} option`).remove().sort(function(a, b) { 
+              console.log(`${parseInt($(a).attr('rssi'))} < ${parseInt( $(b).attr('rssi'))} ? `);
+              return parseInt($(a).attr('rssi')) < parseInt( $(b).attr('rssi')) ? 1 : -1; 
+            }));
           break;
         default:
           break;
@@ -1165,7 +1606,6 @@ function handleRecoveryMode(data) {
   } else {
     $('*[href*="-nvs"]').hide();
   }
-  enableStatusTimer = true;
   if (locRecovery === 1) {
     recovery = true;
     $('.recovery_element').show();
@@ -1297,9 +1737,6 @@ function batteryToIcon(voltage) {
 }
 function checkStatus() {
   RepeatCheckStatusInterval();
-  if (!enableStatusTimer) {
-    return;
-  }
   if (blockAjax) {
     return;
   }
@@ -1309,15 +1746,14 @@ function checkStatus() {
     handleRecoveryMode(data);
     handleWifiStatus(data);
     handlebtstate(data);
-    let pname = '';
+    handle_flash_state(data);
     if (data.project_name && data.project_name !== '') {
-      pname = data.project_name;
+      project_name = data.project_name;
     }
     if (data.version && data.version !== '') {
       versionName=data.version;
-      appTitle= (versionName.toLowerCase().includes('squeezeamp')?"SqueezeAmp":"SqueezeESP32");
-      $("#navtitle").text= `${appTitle}`;
-      $('span#foot-fw').html(`fw: <strong>${versionName}</strong>, mode: <strong>${pname}</strong>`);
+      $("#navtitle").html(`${project_name}${recovery?'<br>[recovery]':''}`);
+      $('span#foot-fw').html(`fw: <strong>${versionName}</strong>, mode: <strong>${recovery?"Recovery":project_name}</strong>`);
     } else {
       $('span#flash-status').html('');
     }
@@ -1352,8 +1788,11 @@ window.runCommand = function(button, reboot) {
       const attr = allfields[i].attributes;
       let qts = '';
       let opt = '';
-      let isSelect = allfields[i].attributes.class.value === 'custom-select';
-      if ((isSelect && allfields[i].selectedIndex !== 0) || !isSelect) {
+      let isSelect = $(allfields[i]).is('select');
+      const hasValue=attr.hasvalue.value === 'true';
+      const validVal=(isSelect && allfields[i].value !== '--' ) || ( !isSelect && allfields[i].value !== '' );
+
+      if ( !hasValue|| hasValue && validVal)  {
         if (attr.longopts.value !== 'undefined') {
           opt += '--' + attr.longopts.value;
         } else if (attr.shortopts.value !== 'undefined') {
@@ -1401,7 +1840,6 @@ window.runCommand = function(button, reboot) {
       }
     },
   });
-  enableStatusTimer = true;
 }
 function getLongOps(data, name, longopts){
   return data.values[name]!==undefined?data.values[name][longopts]:"";
@@ -1418,7 +1856,7 @@ function getCommands() {
 
         // innerhtml+='<tr class="table-light"><td>'+(isConfig?'<h1>':'');
         innerhtml +=
-          '<div class="card text-white bg-primary mb-3"><div class="card-header">' +
+          '<div class="card text-white mb-3"><div class="card-header">' +
           command.help.encodeHTML().replace(/\n/g, '<br />') +
           '</div><div class="card-body">';
         innerhtml += '<fieldset id="flds-' + command.name + '">';
@@ -1602,7 +2040,9 @@ function getConfig() {
           $('#player').val(val);
           document.title = val;
           hostName = val;
-        } 
+        } else if (key === 'rel_api') {
+           releaseURL = val;
+        }
         $('tbody#nvsTable').append(
           '<tr>' +
             '<td>' +

+ 27 - 27
components/wifi-manager/webapp/src/sass/layout/_features.scss

@@ -1,34 +1,34 @@
-.features:hover {
-  cursor: pointer;
-  animation: jello-horizontal 1.2s;
-}
+// .features:hover {
+//   cursor: pointer;
+//   animation: jello-horizontal 1.2s;
+// }
 
-@keyframes jello-horizontal {
-  0% {
-    transform: scale3d(1, 1, 1);
-  }
+// @keyframes jello-horizontal {
+//   0% {
+//     transform: scale3d(1, 1, 1);
+//   }
 
-  30% {
-    transform: scale3d(1.25, .75, 1);
-  }
+//   30% {
+//     transform: scale3d(1.25, .75, 1);
+//   }
 
-  40% {
-    transform: scale3d(.75, 1.25, 1);
-  }
+//   40% {
+//     transform: scale3d(.75, 1.25, 1);
+//   }
 
-  50% {
-    transform: scale3d(1.15, .85, 1);
-  }
+//   50% {
+//     transform: scale3d(1.15, .85, 1);
+//   }
 
-  65% {
-    transform: scale3d(.95, 1.05, 1);
-  }
+//   65% {
+//     transform: scale3d(.95, 1.05, 1);
+//   }
 
-  75% {
-    transform: scale3d(1.05, .95, 1);
-  }
+//   75% {
+//     transform: scale3d(1.05, .95, 1);
+//   }
 
-  100% {
-    transform: scale3d(1, 1, 1);
-  }
-}
+//   100% {
+//     transform: scale3d(1, 1, 1);
+//   }
+// }

+ 348 - 348
components/wifi-manager/webapp/src/sass/setup/_normalize.scss

@@ -1,348 +1,348 @@
-/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
-
-/* Document
-   ========================================================================== */
-
-/**
- * 1. Correct the line height in all browsers.
- * 2. Prevent adjustments of font size after orientation changes in iOS.
- */
-
-html {
-  line-height: 1.15; /* 1 */
-  -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/* Sections
-   ========================================================================== */
-
-/**
- * Remove the margin in all browsers.
- */
-
-body {
-  margin: 0;
-}
-
-/**
- * Render the `main` element consistently in IE.
- */
-
-main {
-  display: block;
-}
-
-/**
- * Correct the font size and margin on `h1` elements within `section` and
- * `article` contexts in Chrome, Firefox, and Safari.
- */
-
-h1 {
-  font-size: 2em;
-  margin: .67em 0;
-}
-
-/* Grouping content
-   ========================================================================== */
-
-/**
- * 1. Add the correct box sizing in Firefox.
- * 2. Show the overflow in Edge and IE.
- */
-
-hr {
-  box-sizing: content-box; /* 1 */
-  height: 0; /* 1 */
-  overflow: visible; /* 2 */
-}
-
-/**
- * 1. Correct the inheritance and scaling of font size in all browsers.
- * 2. Correct the odd `em` font sizing in all browsers.
- */
-
-pre {
-  font-family: monospace; /* 1 */
-  font-size: 1em; /* 2 */
-}
-
-/* Text-level semantics
-   ========================================================================== */
-
-/**
- * Remove the gray background on active links in IE 10.
- */
-
-a {
-  background-color: transparent;
-}
-
-/**
- * 1. Remove the bottom border in Chrome 57-
- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
- */
-
-abbr[title] {
-  border-bottom: none; /* 1 */
-  text-decoration: underline; /* 2 */
-}
-
-/**
- * Add the correct font weight in Chrome, Edge, and Safari.
- */
-
-b,
-strong {
-  font-weight: bolder;
-}
-
-/**
- * 1. Correct the inheritance and scaling of font size in all browsers.
- * 2. Correct the odd `em` font sizing in all browsers.
- */
-
-code,
-kbd,
-samp {
-  font-family: monospace; /* 1 */
-  font-size: 1em; /* 2 */
-}
-
-/**
- * Add the correct font size in all browsers.
- */
-
-small {
-  font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` elements from affecting the line height in
- * all browsers.
- */
-
-sub,
-sup {
-  font-size: 75%;
-  line-height: 0;
-  position: relative;
-  vertical-align: baseline;
-}
-
-sub {
-  bottom: -.25em;
-}
-
-sup {
-  top: -.5em;
-}
-
-/* Embedded content
-   ========================================================================== */
-
-/**
- * Remove the border on images inside links in IE 10.
- */
-
-img {
-  border-style: none;
-}
-
-/* Forms
-   ========================================================================== */
-
-/**
- * 1. Change the font styles in all browsers.
- * 2. Remove the margin in Firefox and Safari.
- */
-
-button,
-input,
-optgroup,
-select,
-textarea {
-  font-family: inherit; /* 1 */
-  font-size: 100%; /* 1 */
-  line-height: 1.15; /* 1 */
-  margin: 0; /* 2 */
-}
-
-/**
- * Show the overflow in IE.
- * 1. Show the overflow in Edge.
- */
-
-button,
-input { /* 1 */
-  overflow: visible;
-}
-
-/**
- * Remove the inheritance of text transform in Edge, Firefox, and IE.
- * 1. Remove the inheritance of text transform in Firefox.
- */
-
-button,
-select { /* 1 */
-  text-transform: none;
-}
-
-/**
- * Correct the inability to style clickable types in iOS and Safari.
- */
-
-button,
-[type="button"],
-[type="reset"],
-[type="submit"] {
-  -webkit-appearance: button;
-}
-
-/**
- * Remove the inner border and padding in Firefox.
- */
-
-button::-moz-focus-inner,
-[type="button"]::-moz-focus-inner,
-[type="reset"]::-moz-focus-inner,
-[type="submit"]::-moz-focus-inner {
-  border-style: none;
-  padding: 0;
-}
-
-/**
- * Restore the focus styles unset by the previous rule.
- */
-
-button:-moz-focusring,
-[type="button"]:-moz-focusring,
-[type="reset"]:-moz-focusring,
-[type="submit"]:-moz-focusring {
-  outline: 1px dotted ButtonText;
-}
-
-/**
- * Correct the padding in Firefox.
- */
-
-fieldset {
-  padding: .35em .75em .625em;
-}
-
-/**
- * 1. Correct the text wrapping in Edge and IE.
- * 2. Correct the color inheritance from `fieldset` elements in IE.
- * 3. Remove the padding so developers are not caught out when they zero out
- *    `fieldset` elements in all browsers.
- */
-
-legend {
-  box-sizing: border-box; /* 1 */
-  color: inherit; /* 2 */
-  display: table; /* 1 */
-  max-width: 100%; /* 1 */
-  padding: 0; /* 3 */
-  white-space: normal; /* 1 */
-}
-
-/**
- * Add the correct vertical alignment in Chrome, Firefox, and Opera.
- */
-
-progress {
-  vertical-align: baseline;
-}
-
-/**
- * Remove the default vertical scrollbar in IE 10+.
- */
-
-textarea {
-  overflow: auto;
-}
-
-/**
- * 1. Add the correct box sizing in IE 10.
- * 2. Remove the padding in IE 10.
- */
-
-[type="checkbox"],
-[type="radio"] {
-  box-sizing: border-box; /* 1 */
-  padding: 0; /* 2 */
-}
-
-/**
- * Correct the cursor style of increment and decrement buttons in Chrome.
- */
-
-[type="number"]::-webkit-inner-spin-button,
-[type="number"]::-webkit-outer-spin-button {
-  height: auto;
-}
-
-/**
- * 1. Correct the odd appearance in Chrome and Safari.
- * 2. Correct the outline style in Safari.
- */
-
-[type="search"] {
-  -webkit-appearance: textfield; /* 1 */
-  outline-offset: -2px; /* 2 */
-}
-
-/**
- * Remove the inner padding in Chrome and Safari on macOS.
- */
-
-[type="search"]::-webkit-search-decoration {
-  -webkit-appearance: none;
-}
-
-/**
- * 1. Correct the inability to style clickable types in iOS and Safari.
- * 2. Change font properties to `inherit` in Safari.
- */
-
-::-webkit-file-upload-button {
-  -webkit-appearance: button; /* 1 */
-  font: inherit; /* 2 */
-}
-
-/* Interactive
-   ========================================================================== */
-
-/*
- * Add the correct display in Edge, IE 10+, and Firefox.
- */
-
-details {
-  display: block;
-}
-
-/*
- * Add the correct display in all browsers.
- */
-
-summary {
-  display: list-item;
-}
-
-/* Misc
-   ========================================================================== */
-
-/**
- * Add the correct display in IE 10+.
- */
-
-template {
-  display: none;
-}
-
-/**
- * Add the correct display in IE 10.
- */
-
-[hidden] {
-  display: none;
-}
+// /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+// /* Document
+//    ========================================================================== */
+
+// /**
+//  * 1. Correct the line height in all browsers.
+//  * 2. Prevent adjustments of font size after orientation changes in iOS.
+//  */
+
+// html {
+//   line-height: 1.15; /* 1 */
+//   -webkit-text-size-adjust: 100%; /* 2 */
+// }
+
+// /* Sections
+//    ========================================================================== */
+
+// /**
+//  * Remove the margin in all browsers.
+//  */
+
+// body {
+//   margin: 0;
+// }
+
+// /**
+//  * Render the `main` element consistently in IE.
+//  */
+
+// main {
+//   display: block;
+// }
+
+// /**
+//  * Correct the font size and margin on `h1` elements within `section` and
+//  * `article` contexts in Chrome, Firefox, and Safari.
+//  */
+
+// h1 {
+//   font-size: 2em;
+//   margin: .67em 0;
+// }
+
+// /* Grouping content
+//    ========================================================================== */
+
+// /**
+//  * 1. Add the correct box sizing in Firefox.
+//  * 2. Show the overflow in Edge and IE.
+//  */
+
+// hr {
+//   box-sizing: content-box; /* 1 */
+//   height: 0; /* 1 */
+//   overflow: visible; /* 2 */
+// }
+
+// /**
+//  * 1. Correct the inheritance and scaling of font size in all browsers.
+//  * 2. Correct the odd `em` font sizing in all browsers.
+//  */
+
+// pre {
+//   font-family: monospace; /* 1 */
+//   font-size: 1em; /* 2 */
+// }
+
+// /* Text-level semantics
+//    ========================================================================== */
+
+// /**
+//  * Remove the gray background on active links in IE 10.
+//  */
+
+// a {
+//   background-color: transparent;
+// }
+
+// /**
+//  * 1. Remove the bottom border in Chrome 57-
+//  * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+//  */
+
+// abbr[title] {
+//   border-bottom: none; /* 1 */
+//   text-decoration: underline; /* 2 */
+// }
+
+// /**
+//  * Add the correct font weight in Chrome, Edge, and Safari.
+//  */
+
+// b,
+// strong {
+//   font-weight: bolder;
+// }
+
+// /**
+//  * 1. Correct the inheritance and scaling of font size in all browsers.
+//  * 2. Correct the odd `em` font sizing in all browsers.
+//  */
+
+// code,
+// kbd,
+// samp {
+//   font-family: monospace; /* 1 */
+//   font-size: 1em; /* 2 */
+// }
+
+// /**
+//  * Add the correct font size in all browsers.
+//  */
+
+// small {
+//   font-size: 80%;
+// }
+
+// /**
+//  * Prevent `sub` and `sup` elements from affecting the line height in
+//  * all browsers.
+//  */
+
+// sub,
+// sup {
+//   font-size: 75%;
+//   line-height: 0;
+//   position: relative;
+//   vertical-align: baseline;
+// }
+
+// sub {
+//   bottom: -.25em;
+// }
+
+// sup {
+//   top: -.5em;
+// }
+
+// /* Embedded content
+//    ========================================================================== */
+
+// /**
+//  * Remove the border on images inside links in IE 10.
+//  */
+
+// img {
+//   border-style: none;
+// }
+
+// /* Forms
+//    ========================================================================== */
+
+// /**
+//  * 1. Change the font styles in all browsers.
+//  * 2. Remove the margin in Firefox and Safari.
+//  */
+
+// button,
+// input,
+// optgroup,
+// select,
+// textarea {
+//   font-family: inherit; /* 1 */
+//   font-size: 100%; /* 1 */
+//   line-height: 1.15; /* 1 */
+//   margin: 0; /* 2 */
+// }
+
+// /**
+//  * Show the overflow in IE.
+//  * 1. Show the overflow in Edge.
+//  */
+
+// button,
+// input { /* 1 */
+//   overflow: visible;
+// }
+
+// /**
+//  * Remove the inheritance of text transform in Edge, Firefox, and IE.
+//  * 1. Remove the inheritance of text transform in Firefox.
+//  */
+
+// button,
+// select { /* 1 */
+//   text-transform: none;
+// }
+
+// /**
+//  * Correct the inability to style clickable types in iOS and Safari.
+//  */
+
+// button,
+// [type="button"],
+// [type="reset"],
+// [type="submit"] {
+//   -webkit-appearance: button;
+// }
+
+// /**
+//  * Remove the inner border and padding in Firefox.
+//  */
+
+// button::-moz-focus-inner,
+// [type="button"]::-moz-focus-inner,
+// [type="reset"]::-moz-focus-inner,
+// [type="submit"]::-moz-focus-inner {
+//   border-style: none;
+//   padding: 0;
+// }
+
+// /**
+//  * Restore the focus styles unset by the previous rule.
+//  */
+
+// button:-moz-focusring,
+// [type="button"]:-moz-focusring,
+// [type="reset"]:-moz-focusring,
+// [type="submit"]:-moz-focusring {
+//   outline: 1px dotted ButtonText;
+// }
+
+// /**
+//  * Correct the padding in Firefox.
+//  */
+
+// fieldset {
+//   padding: .35em .75em .625em;
+// }
+
+// /**
+//  * 1. Correct the text wrapping in Edge and IE.
+//  * 2. Correct the color inheritance from `fieldset` elements in IE.
+//  * 3. Remove the padding so developers are not caught out when they zero out
+//  *    `fieldset` elements in all browsers.
+//  */
+
+// legend {
+//   box-sizing: border-box; /* 1 */
+//   color: inherit; /* 2 */
+//   display: table; /* 1 */
+//   max-width: 100%; /* 1 */
+//   padding: 0; /* 3 */
+//   white-space: normal; /* 1 */
+// }
+
+// /**
+//  * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+//  */
+
+// progress {
+//   vertical-align: baseline;
+// }
+
+// /**
+//  * Remove the default vertical scrollbar in IE 10+.
+//  */
+
+// textarea {
+//   overflow: auto;
+// }
+
+// /**
+//  * 1. Add the correct box sizing in IE 10.
+//  * 2. Remove the padding in IE 10.
+//  */
+
+// [type="checkbox"],
+// [type="radio"] {
+//   box-sizing: border-box; /* 1 */
+//   padding: 0; /* 2 */
+// }
+
+// /**
+//  * Correct the cursor style of increment and decrement buttons in Chrome.
+//  */
+
+// [type="number"]::-webkit-inner-spin-button,
+// [type="number"]::-webkit-outer-spin-button {
+//   height: auto;
+// }
+
+// /**
+//  * 1. Correct the odd appearance in Chrome and Safari.
+//  * 2. Correct the outline style in Safari.
+//  */
+
+// [type="search"] {
+//   -webkit-appearance: textfield; /* 1 */
+//   outline-offset: -2px; /* 2 */
+// }
+
+// /**
+//  * Remove the inner padding in Chrome and Safari on macOS.
+//  */
+
+// [type="search"]::-webkit-search-decoration {
+//   -webkit-appearance: none;
+// }
+
+// /**
+//  * 1. Correct the inability to style clickable types in iOS and Safari.
+//  * 2. Change font properties to `inherit` in Safari.
+//  */
+
+// ::-webkit-file-upload-button {
+//   -webkit-appearance: button; /* 1 */
+//   font: inherit; /* 2 */
+// }
+
+// /* Interactive
+//    ========================================================================== */
+
+// /*
+//  * Add the correct display in Edge, IE 10+, and Firefox.
+//  */
+
+// details {
+//   display: block;
+// }
+
+// /*
+//  * Add the correct display in all browsers.
+//  */
+
+// summary {
+//   display: list-item;
+// }
+
+// /* Misc
+//    ========================================================================== */
+
+// /**
+//  * Add the correct display in IE 10+.
+//  */
+
+// template {
+//   display: none;
+// }
+
+// /**
+//  * Add the correct display in IE 10.
+//  */
+
+// [hidden] {
+//   display: none;
+// }

+ 18 - 18
components/wifi-manager/webapp/src/sass/utils/_mixins.scss

@@ -1,24 +1,24 @@
 
-/* Device = Most of the Smartphones Mobiles (Portrait) */
-$screen-xxs-min: 320px;
-$screen-xxs-max: 480px;
+// /* Device = Most of the Smartphones Mobiles (Portrait) */
+// $screen-xxs-min: 320px;
+// $screen-xxs-max: 480px;
 
-/* Device = Low Resolution Tablets, Mobiles (Landscape) */
-$screen-xs-min: 481px;
-$screen-xs-max: 767px;
+// /* Device = Low Resolution Tablets, Mobiles (Landscape) */
+// $screen-xs-min: 481px;
+// $screen-xs-max: 767px;
 
-/* Device = Tablets, Ipads (portrait) */
-$screen-sm-min: 768px;
-$screen-sm-max: 1024px;
+// /* Device = Tablets, Ipads (portrait) */
+// $screen-sm-min: 768px;
+// $screen-sm-max: 1024px;
 
-/* Device = Laptops, Desktops */
-$screen-md-min: 1025px;
-$screen-md-max: 1280px;
+// /* Device = Laptops, Desktops */
+// $screen-md-min: 1025px;
+// $screen-md-max: 1280px;
 
-/* Device = Desktops */
-$screen-lg-min: 1281px;
-$screen-lg-max: 1440px;
+// /* Device = Desktops */
+// $screen-lg-min: 1281px;
+// $screen-lg-max: 1440px;
 
-/* Higher Resolution Screens */
-$screen-xlg-min: 1441px;
-$screen-xlg-max: 2560px;
+// /* Higher Resolution Screens */
+// $screen-xlg-min: 1441px;
+// $screen-xlg-max: 2560px;

+ 36 - 23
components/wifi-manager/webapp/src/sass/utils/_style.css

@@ -1,4 +1,19 @@
+
+
 body {
+    min-height: 100vh; 
+  }
+.border-bottom  {
+    border-width:3px !important;
+}
+
+.border-top {
+    border-width:3px !important;
+}
+tr.hide {
+    display: none;
+}
+/* body {
     border: 0;
     margin: 0;
     margin-bottom:50px;
@@ -135,7 +150,7 @@ h3 {
 .fr {
     float: right;
     margin-right: 20px;
-}
+} */
 /* .w0 {
     background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTJDBGvsAAABzUlEQVRIS+WUTShEURTH3zyRhjQ+8hWxmCJMoSzEwsbCgi1LZRYW9pONptiwka9iI81CWFpYaEqNMkVKmpWN1IhYKN9ZDL/z3p3mxZh5g9X4168799xz/vPefedeLeuVC+3gdTgc07CsmCQ2DI2gg21Jci30wSpGt/CeghickTsHPVACDkgqp67rPgpO4E0ZZMIj7OHhxSvPtEyomcVDeFXJv+EZNvEsNa01rZfAuSUhThR2wU+ObJkbyhRNMMDaDIThBqy1MdZ3wAPawqfFC2Lj0Ab5kpBGxdAJs9TeW72ITUhCPZMjFYwwbwXpnkwlDzOIx50yXwP5c0MeggHGanNqSDqqBqQ7/Kxvg2zHAfMN8IE8uZhYO6eBnBXGKnOakLWfaQZ9jMRjSPXhZUuC5A9JjVFpKkeNSVVA0Tq8KJN0yFl4gilqbW2tm+SQKoybXIG8jcT34RSsh1Byt6iVg2ZLlRCg6JpROqEDpFheXZ5S9rcLFsl5YJwHad+MVA5y13w5lRY5oRsKjdm/Vz/7LR86zG+5wr+9NX+iOowjEO+aELEic+lv1ILppeUPosRst6QduTANgnE2mC+BnYswI1VwfYzCCL9dZij7pWkf6UeSTYAuE/QAAAAASUVORK5CYII=') no-repeat left top;
     height: 24px;
@@ -157,7 +172,7 @@ h3 {
     height: 24px;
 } */
 /* SpinKit is licensed under the MIT License. Copyright (c) 2015 Tobias Ahlin */
-.spinner {
+/* .spinner {
     width: 40px;
     height: 40px;
   
@@ -197,11 +212,11 @@ h3 {
       transform: scale(1.0);
       -webkit-transform: scale(1.0);
     }
-  }
+  } */
 /* end of SpinKit */
 
 /* daduke stuff */
-input[type='text'], input[type='password'], textarea, select, option {
+/* input[type='text'], input[type='password'], textarea, select, option {
   background: #999;
   border: 0;
   padding: 4px;
@@ -229,8 +244,8 @@ input[type='text'], input[type='password'], textarea, select, option {
   pointer-events: all;
   border-radius: 1rem;
   background-color: #f00;
-}
-
+} */
+/* 
 .custom-switch .custom-control-label::after {
   top: calc(0.25rem + 2px);
   left: calc(-2.25rem + 2px);
@@ -246,8 +261,8 @@ input[type='text'], input[type='password'], textarea, select, option {
   .custom-switch .custom-control-label::after {
     transition: none;
   }
-}
-
+} */
+/* 
 .custom-switch .custom-control-input:checked ~ .custom-control-label::before {
   background-color: #0f0;
 }
@@ -307,7 +322,7 @@ input, textarea {
 span#flash-status {
     padding-left: 15px;
     font-size: 120%;
-}
+} */
 
 /* #info {
     padding-top: 7px;
@@ -342,7 +357,7 @@ ul#navbar {
     border-top: 1px solid black;
 } */
 
-.footer {
+/* .footer {
   position: fixed;
   left: 0;
   bottom: 0;
@@ -350,8 +365,8 @@ ul#navbar {
   background-color: #555;
   color: white;
   text-align: center;
-}
-
+} */
+/* 
 .sl {
     background-color: #053c1e;
 }
@@ -377,23 +392,21 @@ div#message {
     width:20em;
     height:4em;
     text-align: center;
-    margin-left: -10em; /*set to a negative number 1/2 of your width*/
-    margin-top: -2em; /*set to a negative number 1/2 of your height*/
+    margin-left: -10em; 
+    margin-top: -2em; 
     border-radius: 8px;
     box-shadow: 0px 5px 2px -5px rgba(255, 255, 255, 0.5) inset, 0px 10px 20px -5px rgba(255, 255, 255, 0.1) inset, 0 0px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 1px rgba(0, 0, 0, 0.12), 0 1px 10px 0 rgba(0, 0, 0, 0.3);
     z-index: 20;
-}
-
-tr.hide {
-    display: none;
-}
-
+} */
+/* 
+ */
+/* 
 #searchfw {
     float: right;
     display: none;
-}
+} */
 
-button#updateAP {
+/* button#updateAP {
     float: right;
     display: inline;
-}
+} */

+ 3 - 3
components/wifi-manager/webapp/webapp.cmake

@@ -1,5 +1,5 @@
 target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/favicon-32x32.png BINARY)
 target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/index.html.gz BINARY)
-target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/index.e644c0.bundle.js.gz BINARY)
-target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.e644c0.bundle.js.gz BINARY)
-target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.e644c0.bundle.js.gz BINARY)
+target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/index.31a52e.bundle.js.gz BINARY)
+target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.31a52e.bundle.js.gz BINARY)
+target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.31a52e.bundle.js.gz BINARY)

+ 15 - 15
components/wifi-manager/webapp/webpack.c

@@ -4,31 +4,31 @@ extern const uint8_t _favicon_32x32_png_start[] asm("_binary_favicon_32x32_png_s
 extern const uint8_t _favicon_32x32_png_end[] asm("_binary_favicon_32x32_png_end");
 extern const uint8_t _index_html_gz_start[] asm("_binary_index_html_gz_start");
 extern const uint8_t _index_html_gz_end[] asm("_binary_index_html_gz_end");
-extern const uint8_t _index_e644c0_bundle_js_gz_start[] asm("_binary_index_e644c0_bundle_js_gz_start");
-extern const uint8_t _index_e644c0_bundle_js_gz_end[] asm("_binary_index_e644c0_bundle_js_gz_end");
-extern const uint8_t _node_modules_e644c0_bundle_js_gz_start[] asm("_binary_node_modules_e644c0_bundle_js_gz_start");
-extern const uint8_t _node_modules_e644c0_bundle_js_gz_end[] asm("_binary_node_modules_e644c0_bundle_js_gz_end");
-extern const uint8_t _runtime_e644c0_bundle_js_gz_start[] asm("_binary_runtime_e644c0_bundle_js_gz_start");
-extern const uint8_t _runtime_e644c0_bundle_js_gz_end[] asm("_binary_runtime_e644c0_bundle_js_gz_end");
+extern const uint8_t _index_31a52e_bundle_js_gz_start[] asm("_binary_index_31a52e_bundle_js_gz_start");
+extern const uint8_t _index_31a52e_bundle_js_gz_end[] asm("_binary_index_31a52e_bundle_js_gz_end");
+extern const uint8_t _node_modules_31a52e_bundle_js_gz_start[] asm("_binary_node_modules_31a52e_bundle_js_gz_start");
+extern const uint8_t _node_modules_31a52e_bundle_js_gz_end[] asm("_binary_node_modules_31a52e_bundle_js_gz_end");
+extern const uint8_t _runtime_31a52e_bundle_js_gz_start[] asm("_binary_runtime_31a52e_bundle_js_gz_start");
+extern const uint8_t _runtime_31a52e_bundle_js_gz_end[] asm("_binary_runtime_31a52e_bundle_js_gz_end");
 const char * resource_lookups[] = {
 	"/dist/favicon-32x32.png",
 	"/dist/index.html.gz",
-	"/js/index.e644c0.bundle.js.gz",
-	"/js/node-modules.e644c0.bundle.js.gz",
-	"/js/runtime.e644c0.bundle.js.gz",
+	"/js/index.31a52e.bundle.js.gz",
+	"/js/node-modules.31a52e.bundle.js.gz",
+	"/js/runtime.31a52e.bundle.js.gz",
 ""
 };
 const uint8_t * resource_map_start[] = {
 	_favicon_32x32_png_start,
 	_index_html_gz_start,
-	_index_e644c0_bundle_js_gz_start,
-	_node_modules_e644c0_bundle_js_gz_start,
-	_runtime_e644c0_bundle_js_gz_start
+	_index_31a52e_bundle_js_gz_start,
+	_node_modules_31a52e_bundle_js_gz_start,
+	_runtime_31a52e_bundle_js_gz_start
 };
 const uint8_t * resource_map_end[] = {
 	_favicon_32x32_png_end,
 	_index_html_gz_end,
-	_index_e644c0_bundle_js_gz_end,
-	_node_modules_e644c0_bundle_js_gz_end,
-	_runtime_e644c0_bundle_js_gz_end
+	_index_31a52e_bundle_js_gz_end,
+	_node_modules_31a52e_bundle_js_gz_end,
+	_runtime_31a52e_bundle_js_gz_end
 };

+ 25 - 25
components/wifi-manager/webapp/webpack.h

@@ -1,26 +1,26 @@
 /***********************************
 webpack_headers
-Hash: e644c04d107606ae748d
+Hash: 31a52ecfe661f5a02717
 Version: webpack 4.44.2
-Time: 6142ms
-Built at: 2020-12-21 12 h 10 min 00 s
+Time: 6575ms
+Built at: 2021-03-23 17 h 59 min 55 s
                                 Asset       Size  Chunks                                Chunk Names
-          ./js/index.e644c0.bundle.js    230 KiB       0  [emitted] [immutable]         index
-       ./js/index.e644c0.bundle.js.br   31.3 KiB          [emitted]                     
-       ./js/index.e644c0.bundle.js.gz   40.9 KiB          [emitted]                     
-   ./js/node-modules.e644c0.bundle.js    265 KiB       1  [emitted] [immutable]  [big]  node-modules
-./js/node-modules.e644c0.bundle.js.br   76.2 KiB          [emitted]                     
-./js/node-modules.e644c0.bundle.js.gz   88.6 KiB          [emitted]                     
-        ./js/runtime.e644c0.bundle.js   1.46 KiB       2  [emitted] [immutable]         runtime
-     ./js/runtime.e644c0.bundle.js.br  644 bytes          [emitted]                     
-     ./js/runtime.e644c0.bundle.js.gz  722 bytes          [emitted]                     
+          ./js/index.31a52e.bundle.js    227 KiB       0  [emitted] [immutable]         index
+       ./js/index.31a52e.bundle.js.br   30.9 KiB          [emitted]                     
+       ./js/index.31a52e.bundle.js.gz   39.9 KiB          [emitted]                     
+   ./js/node-modules.31a52e.bundle.js    265 KiB       1  [emitted] [immutable]  [big]  node-modules
+./js/node-modules.31a52e.bundle.js.br   76.2 KiB          [emitted]                     
+./js/node-modules.31a52e.bundle.js.gz   88.6 KiB          [emitted]                     
+        ./js/runtime.31a52e.bundle.js   1.46 KiB       2  [emitted] [immutable]         runtime
+     ./js/runtime.31a52e.bundle.js.br  644 bytes          [emitted]                     
+     ./js/runtime.31a52e.bundle.js.gz  722 bytes          [emitted]                     
                     favicon-32x32.png  578 bytes          [emitted]                     
-                           index.html   19.5 KiB          [emitted]                     
-                        index.html.br   4.48 KiB          [emitted]                     
-                        index.html.gz   5.46 KiB          [emitted]                     
+                           index.html   21.5 KiB          [emitted]                     
+                        index.html.br   4.72 KiB          [emitted]                     
+                        index.html.gz   5.73 KiB          [emitted]                     
                            sprite.svg    4.4 KiB          [emitted]                     
                         sprite.svg.br  912 bytes          [emitted]                     
-Entrypoint index [big] = ./js/runtime.e644c0.bundle.js ./js/node-modules.e644c0.bundle.js ./js/index.e644c0.bundle.js
+Entrypoint index [big] = ./js/runtime.31a52e.bundle.js ./js/node-modules.31a52e.bundle.js ./js/index.31a52e.bundle.js
  [6] ./node_modules/bootstrap/dist/js/bootstrap-exposed.js 437 bytes {1} [built]
 [11] ./src/sass/main.scss 1.55 KiB {0} [built]
 [16] ./node_modules/remixicon/icons/Device/signal-wifi-fill.svg 340 bytes {1} [built]
@@ -35,22 +35,22 @@ Entrypoint index [big] = ./js/runtime.e644c0.bundle.js ./js/node-modules.e644c0.
 [25] ./node_modules/remixicon/icons/Device/device-recover-fill.svg 346 bytes {1} [built]
 [26] ./node_modules/remixicon/icons/Device/bluetooth-fill.svg 336 bytes {1} [built]
 [27] ./node_modules/remixicon/icons/Device/bluetooth-connect-fill.svg 352 bytes {1} [built]
-[37] ./src/index.ts + 1 modules 52.6 KiB {0} [built]
+[37] ./src/index.ts + 1 modules 59.9 KiB {0} [built]
      | ./src/index.ts 1.36 KiB [built]
-     | ./src/js/custom.js 51.2 KiB [built]
+     | ./src/js/custom.js 58.4 KiB [built]
     + 23 hidden modules
 
 WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
 This can impact web performance.
 Assets: 
-  ./js/node-modules.e644c0.bundle.js (265 KiB)
+  ./js/node-modules.31a52e.bundle.js (265 KiB)
 
 WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
 Entrypoints:
-  index (497 KiB)
-      ./js/runtime.e644c0.bundle.js
-      ./js/node-modules.e644c0.bundle.js
-      ./js/index.e644c0.bundle.js
+  index (494 KiB)
+      ./js/runtime.31a52e.bundle.js
+      ./js/node-modules.31a52e.bundle.js
+      ./js/index.31a52e.bundle.js
 
 
 WARNING in webpack performance recommendations: 
@@ -58,9 +58,9 @@ You can limit the size of your bundles by using import() or require.ensure to la
 For more info visit https://webpack.js.org/guides/code-splitting/
 Child html-webpack-plugin for "index.html":
          Asset     Size  Chunks  Chunk Names
-    index.html  556 KiB       0  
+    index.html  558 KiB       0  
     Entrypoint undefined = index.html
-    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 21.1 KiB {0} [built]
+    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 23.7 KiB {0} [built]
     [1] ./node_modules/lodash/lodash.js 530 KiB {0} [built]
     [2] (webpack)/buildin/global.js 472 bytes {0} [built]
     [3] (webpack)/buildin/module.js 497 bytes {0} [built]

BIN
components/wifi-manager/webapp/webpack/dist/favicon-32x32.png


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
components/wifi-manager/webapp/webpack/dist/index.html


BIN
components/wifi-manager/webapp/webpack/dist/index.html.br


BIN
components/wifi-manager/webapp/webpack/dist/index.html.gz


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
components/wifi-manager/webapp/webpack/dist/js/index.e644c0.bundle.js


BIN
components/wifi-manager/webapp/webpack/dist/js/index.e644c0.bundle.js.br


BIN
components/wifi-manager/webapp/webpack/dist/js/index.e644c0.bundle.js.gz


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 7
components/wifi-manager/webapp/webpack/dist/js/node-modules.e644c0.bundle.js


BIN
components/wifi-manager/webapp/webpack/dist/js/node-modules.e644c0.bundle.js.br


BIN
components/wifi-manager/webapp/webpack/dist/js/node-modules.e644c0.bundle.js.gz


+ 0 - 1
components/wifi-manager/webapp/webpack/dist/js/runtime.e644c0.bundle.js

@@ -1 +0,0 @@
-!function(e){function r(r){for(var n,l,f=r[0],i=r[1],a=r[2],c=0,s=[];c<f.length;c++)l=f[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,f=1;f<t.length;f++){var i=t[f];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={2:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="";var f=window.webpackJsonp=window.webpackJsonp||[],i=f.push.bind(f);f.push=r,f=f.slice();for(var a=0;a<f.length;a++)r(f[a]);var p=i;t()}([]);

BIN
components/wifi-manager/webapp/webpack/dist/js/runtime.e644c0.bundle.js.br


BIN
components/wifi-manager/webapp/webpack/dist/js/runtime.e644c0.bundle.js.gz


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
components/wifi-manager/webapp/webpack/dist/sprite.svg


BIN
components/wifi-manager/webapp/webpack/dist/sprite.svg.br


+ 42 - 9
components/wifi-manager/webapp/webpack/webpack.dev.js

@@ -9,15 +9,20 @@ const HtmlWebPackPlugin = require('html-webpack-plugin');
 const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
 const { Command } = require('commander');
 let  cmdLines= { };
+var { parseArgsStringToArgv } = require('string-argv');
+
 const data = {
     messages: require("../mock/messages.json"),
     messagequeue: require("../mock/messages.json"),
+    message_queue_sequence: [],
     commands: require("../mock/commands.json"),
     scan: require("../mock/scan.json"),
     ap: require("../mock/ap.json"),
     config: require("../mock/config.json"),
     statusdefinition: require("../mock/statusdefinition.json"),
-    status: require("../mock/status.json")
+    status: require("../mock/status.json"),
+    messages_ota_fail: require("../mock/messages_ota_fail.json"),
+    messages_ota: require("../mock/messages_ota.json")
 };
 const messagingTypes= {
 	MESSAGING_INFO : 'MESSAGING_INFO',
@@ -32,6 +37,7 @@ const messagingClass= {
 	MESSAGING_CLASS_BT: 'MESSAGING_CLASS_BT'
 } ;
 function requeueMessages(){
+    data.messagequeue = [];
     data.messagequeue.push(...data.messages);
     console.log(`Re-queued ${data.messages.length} messages. Total queue length is: ${data.messagequeue.length}`);
 }
@@ -70,7 +76,7 @@ for(const cmdIdx in data.commands.commands){
         cmd: new Command(),
     };
     cmdLines[cmd.name].cmd
-        .storeOptionsAsProperties(false)
+        .storeOptionsAsProperties(true)
         .name(cmd.name)
         .exitOverride();
     for(const argIdx in cmd.argtable){
@@ -107,6 +113,8 @@ module.exports = merge(common, {
         port: 9100,
         host: 'desktop-n8u8515',//your ip address
         disableHostCheck: true,
+        headers: {'Access-Control-Allow-Origin': '*',
+    'Accept-Encoding': 'identity'},
         overlay: true,
 
         before: function(app) {
@@ -117,6 +125,9 @@ module.exports = merge(common, {
             app.get('/config.json', function(req, res) { res.json( data.config ); });
             app.get('/status.json', function(req, res) { res.json( data.status ); });
             app.get('/messages.json', function(req, res) { 
+                if(data.message_queue_sequence.length>0){
+                    data.messagequeue.push(data.message_queue_sequence.shift());
+                }
                 res.json( data.messagequeue ) ; 
                 data.messagequeue=[];
             });
@@ -127,9 +138,12 @@ module.exports = merge(common, {
                 console.log(req.body.command);
                 try {
                     const cmdName=req.body.command.split(" ")[0];
-                    const args=('node '+req.body.command).split(" ");
+                    const args=parseArgsStringToArgv(req.body.command,'node ');
                     let cmd=cmdLines[cmdName].cmd;
                     if(cmd){
+                        for (const property in cmd.opts()) {
+                            delete cmd[property];
+                        }
                         cmd.parse(args);
                         const msg=`Received Options: ${JSON.stringify(cmd.opts())}\n`;
                         console.log('Options: ', cmd.opts());
@@ -142,20 +156,39 @@ module.exports = merge(common, {
                 res.json( { 'Result' : 'Success' } ); 
             });
             app.post('/config.json', function(req, res) { 
+                var fwurl='';
                 console.log(req.body);
                 console.log(data.config);
                 for (const property in req.body.config) {
                     console.log(`${property}: ${req.body.config[property].value}`);
-                    if(data.config[property]=== undefined){
-                        console.log(`Added config value ${property} [${req.body.config[property].value}]`);
-                        data.config[property] = {value: req.body.config[property].value};
+                    if(property=='fwurl'){
+                        fwurl=req.body.config[property].value;
                     }
-                    else if (data.config[property].value!=req.body.config[property].value){
-                        console.log(`Updated config value ${property}\nFrom: ${data.config[property].value}\nTo: ${req.body.config[property].value}]`);
-                        data.config[property].value=req.body.config[property].value;
+                    else {
+                        if(data.config[property]=== undefined){
+                            console.log(`Added config value ${property} [${req.body.config[property].value}]`);
+                            data.config[property] = {value: req.body.config[property].value};
+                        }
+                        else if (data.config[property].value!=req.body.config[property].value){
+                            console.log(`Updated config value ${property}\nFrom: ${data.config[property].value}\nTo: ${req.body.config[property].value}]`);
+                            data.config[property].value=req.body.config[property].value;
+                        }
                     }
+
                   }
                 res.json( {} ); 
+                if(fwurl!==''){
+                    data.status.recovery=1;
+                    requeueMessages();
+                    if(fwurl.toLowerCase().includes('fail')){
+                        console.log(`queuing ${data.messages_ota_fail.length} ota messages `);
+                        data.message_queue_sequence.push(...data.messages_ota_fail);
+                    }
+                    else {
+                        console.log(`queuing ${data.messages_ota.length} ota messages `);
+                        data.message_queue_sequence.push(...data.messages_ota);
+                    }
+                }
             });
             app.post('/status.json', function(req, res) { 
 

+ 71 - 50
components/wifi-manager/webapp/webpack/webpack.prod.js

@@ -125,58 +125,79 @@ module.exports = merge(common, {
         //     }
         // }),
         new WebpackOnBuildPlugin(function(stats) {
-                var getDirectories = function (src, callback) {
-                    glob(`${src}/**/*(*.gz|favicon-32x32.png)`, callback);
-                  };
-                getDirectories('./webpack/dist', function (err, list) {
-                    if (err) {
-                        console.log('Error', err);
-                    } else {
-                        const regex = /^(.*\/)([^\/]*)$/
-                        const relativeRegex = /(\w+\/[^\/]*)$/
-                        const makePathRegex = /([^\.].*)$/
-                        let exportDefHead=
-                        '/***********************************\n'+
-                        'webpack_headers\n'+
-                        stats+'\n'+
-                        '***********************************/\n'+
-                        '#pragma once\n'+
-                        '#include <inttypes.h>\n'+
-                        'extern const char * resource_lookups[];\n'+
-                        'extern const uint8_t * resource_map_start[];\n'+
-                        'extern const uint8_t * resource_map_end[];\n';
-                        let exportDef=  '// Automatically generated. Do not edit manually!.\n'+
-                                        '#include <inttypes.h>\n';
-                        let lookupDef='const char * resource_lookups[] = {\n';
-                        let lookupMapStart='const uint8_t * resource_map_start[] = {\n';
-                        let lookupMapEnd='const uint8_t * resource_map_end[] = {\n';
-                        let cMake='';
-                        list.forEach(fileName=>{
-                              let exportName=fileName.match(regex)[2].replace(/[\. \-]/gm,'_');
-                              let relativeName=fileName.match(relativeRegex)[1];
-                              exportDef+=	'extern const uint8_t _'+exportName+'_start[] asm("_binary_'+exportName+'_start");\n'+
-                                        'extern const uint8_t _'+exportName+'_end[] asm("_binary_'+exportName+'_end");\n';
-                              lookupDef+='\t"/'+relativeName+'",\n';
-                              lookupMapStart+='\t_'+ exportName+'_start,\n';
-                              lookupMapEnd+= '\t_'+ exportName+'_end,\n';
-                              cMake+='target_add_binary_data( __idf_wifi-manager ./webapp'+fileName.match(makePathRegex)[1]+' BINARY)\n';
-                        });
 
-                        lookupDef+='""\n};\n';
-                        lookupMapStart=lookupMapStart.substring(0,lookupMapStart.length-2)+'\n};\n';
-                        lookupMapEnd=lookupMapEnd.substring(0,lookupMapEnd.length-2)+'\n};\n';
+            var getDirectories = function (src, callback) {
+                glob(`${src}/**/*(*.gz|favicon-32x32.png)`, callback);
+                };
+            console.log('Cleaning up previous builds');
+            glob(`../../../build/*.S`, function (err, list) {                  
+                if (err) {
+                    console.error('Error', err);
+                } else {
+                    list.forEach(fileName=>{
                         try {
-                            fs.writeFileSync('webapp.cmake', cMake);
-                            fs.writeFileSync('webpack.c', exportDef+lookupDef+lookupMapStart+lookupMapEnd);
-                            fs.writeFileSync('webpack.h', exportDefHead);
-                            //file written successfully
-                          } catch (e) {
-                            console.error(e);
-                          }        
-                    }
-                    });                
-               }),
-               new BundleAnalyzerPlugin()               
+                            console.log(`Purging old binary file ${fileName} from C project.`);
+                            fs.unlinkSync(fileName)
+                            //file removed
+                            } catch(ferr) {
+                            console.error(ferr)
+                            }
+                    });
+                }
+            }
+            );
+            console.log('Generating C include files from webpack build output');
+            getDirectories('./webpack/dist', function (err, list) {
+                if (err) {
+                    console.log('Error', err);
+                } else {
+                    const regex = /^(.*\/)([^\/]*)$/
+                    const relativeRegex = /(\w+\/[^\/]*)$/
+                    const makePathRegex = /([^\.].*)$/
+                    let exportDefHead=
+                    '/***********************************\n'+
+                    'webpack_headers\n'+
+                    stats+'\n'+
+                    '***********************************/\n'+
+                    '#pragma once\n'+
+                    '#include <inttypes.h>\n'+
+                    'extern const char * resource_lookups[];\n'+
+                    'extern const uint8_t * resource_map_start[];\n'+
+                    'extern const uint8_t * resource_map_end[];\n';
+                    let exportDef=  '// Automatically generated. Do not edit manually!.\n'+
+                                    '#include <inttypes.h>\n';
+                    let lookupDef='const char * resource_lookups[] = {\n';
+                    let lookupMapStart='const uint8_t * resource_map_start[] = {\n';
+                    let lookupMapEnd='const uint8_t * resource_map_end[] = {\n';
+                    let cMake='';
+                    list.forEach(fileName=>{
+                            let exportName=fileName.match(regex)[2].replace(/[\. \-]/gm,'_');
+                            let relativeName=fileName.match(relativeRegex)[1];
+                            exportDef+=	'extern const uint8_t _'+exportName+'_start[] asm("_binary_'+exportName+'_start");\n'+
+                                    'extern const uint8_t _'+exportName+'_end[] asm("_binary_'+exportName+'_end");\n';
+                            lookupDef+='\t"/'+relativeName+'",\n';
+                            lookupMapStart+='\t_'+ exportName+'_start,\n';
+                            lookupMapEnd+= '\t_'+ exportName+'_end,\n';
+                            cMake+='target_add_binary_data( __idf_wifi-manager ./webapp'+fileName.match(makePathRegex)[1]+' BINARY)\n';
+                    });
+
+                    lookupDef+='""\n};\n';
+                    lookupMapStart=lookupMapStart.substring(0,lookupMapStart.length-2)+'\n};\n';
+                    lookupMapEnd=lookupMapEnd.substring(0,lookupMapEnd.length-2)+'\n};\n';
+                    try {
+                        fs.writeFileSync('webapp.cmake', cMake);
+                        fs.writeFileSync('webpack.c', exportDef+lookupDef+lookupMapStart+lookupMapEnd);
+                        fs.writeFileSync('webpack.h', exportDefHead);
+                        //file written successfully
+                        } catch (e) {
+                        console.error(e);
+                        }        
+                }
+            });
+            console.log('Post build completed.');
+
+        }),
+        new BundleAnalyzerPlugin()               
     ]
 });
 

+ 4 - 3
components/wifi-manager/wifi_manager.c

@@ -69,8 +69,9 @@ Contains the freeRTOS task and all necessary support
 #include "monitor.h"
 #include "globdefs.h"
 
-#ifndef SQUEEZELITE_ESP32_RELEASE_URL
-#define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
+#ifndef CONFIG_SQUEEZELITE_ESP32_RELEASE_URL
+#pragma message "Defaulting release url"
+#define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
 #endif
 
 #define STR_OR_BLANK(p) p==NULL?"":p
@@ -330,7 +331,7 @@ void wifi_manager_start(){
 	wifi_manager_safe_update_sta_ip_string(NULL);
 
 	ESP_LOGD(TAG,   "Getting release url ");
-	char * release_url = (char * )config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(SQUEEZELITE_ESP32_RELEASE_URL), 0);
+	char * release_url = (char * )config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(CONFIG_SQUEEZELITE_ESP32_RELEASE_URL), 0);
 	if(release_url == NULL){
 		ESP_LOGE(TAG,  "Unable to retrieve the release url from nvs");
 	}

+ 0 - 113
eclipse_make_wrapper.py

@@ -1,113 +0,0 @@
-#!/usr/bin/env python
-#
-# Wrapper to run make and preprocess any paths in the output from MSYS Unix-style paths
-# to Windows paths, for Eclipse
-from __future__ import print_function, division
-import sys
-import subprocess
-import os.path
-import os
-import re
-import glob
-from test import test_cmd_line
-
-#UNIX_PATH_RE = re.compile(r'(([a-zA-Z]{1}[:]{1}){0,1}[/\\][^\s\'\"\t\[\(]+)+')
-UNIX_PATH_RE = re.compile(r'(([a-zA-Z]{1}[:]{1}){0,1}[/\\][^\s\'\"\t\[\(]+(?![^\\/\n]*$)[/\\]?)')
-INCLUDE_PATH_RE = re.compile(r'-I[\s"]{0,}(.+?)["]{0,}(?=\s-\S)')
-INCLUDE_PATH_ADJ_RE = re.compile(r'^([/]opt[/]esp-idf[/]){1}(.*)')
-INCLUDE_PATH_ADJ2_RE = re.compile(r'^([/]c[/]){1}(.*)')
-
-paths = {}
-names = []
-idf_path= os.environ.get('IDF_PATH').replace("/", "\\")
-cwd_path= os.environ.get('CWD')
-pwd_path= os.environ.get('PWD')         
-         
-def check_path(path):
-    try:
-        return paths[path]
-    except KeyError:
-        pass
-    paths[path] = path
-    winpath =path
-    
-    if not os.path.exists(winpath):
-          # cache as failed, replace with success if it works
-        if re.match(INCLUDE_PATH_ADJ2_RE, path) is not None:
-                winpath = INCLUDE_PATH_ADJ2_RE.sub(r'c:/\2',path) #replace /c/ 
-        try:
-            winpath = subprocess.check_output(["cygpath", "-w", winpath]).strip()
-        except subprocess.CalledProcessError:
-            return path  # something went wrong running cygpath, assume this is not a path!
-    if not os.path.exists(winpath):
-        if not os.path.exists(winpath):
-            winpath=idf_path  + '\\' + re.sub(r'^[/\\]opt[/\\](esp-idf[/\\]){0,}', '', path, 1)
-            try:
-                winpath = subprocess.check_output(["cygpath", "-w", winpath]).strip()
-            except subprocess.CalledProcessError:
-                return path  # something went wrong running cygpath, assume this is not a path!
-            if not os.path.exists(winpath):
-                return path  # not actually a valid path
-    
-    winpath = winpath.replace("/", "\\")  # make consistent with forward-slashes used elsewhere
-    paths[path] = winpath
-    
-    
-    #print("In path: {0}, out path: {1}".format(path,winpath) )
-    return winpath
-def fix_paths(filename):
-    if re.match(r'.*[\\](.*$)',filename) is not None:
-        filename = re.findall(r'.*[\\](.*$)',filename)[0].replace("\\", "/")
-    
-    return filename.rstrip()
-
-def print_paths(path_list, file_name, source_file):
-    
-    new_path_list = list(set(path_list))
-    new_path_list.sort()
-    last_n = ''
-    cmd_line='xtensa-esp32-elf-gcc '
-    for n in new_path_list:
-        if re.match(INCLUDE_PATH_ADJ_RE, n) is not None:
-            n = INCLUDE_PATH_ADJ_RE.sub(idf_path+r"\2",n )
-        if re.match(INCLUDE_PATH_ADJ2_RE, n) is not None:
-            n = INCLUDE_PATH_ADJ2_RE.sub(r'c:/\2',n)
-        if last_n != n:
-            cmd_line = cmd_line + ' -I ' + n.rstrip()
-        last_n = n
-    if source_file:
-        cmd_line = cmd_line + ' -c ' + fix_paths(source_file)
-    cmd_line = cmd_line + ' -o ' + fix_paths(file_name)
-    print(cmd_line)
-def extract_includes():
-    
-    for filename in [y for x in os.walk('build') for y in glob.glob(os.path.join(x[0], '*.d'))]:
-        lines = []
-        source=''
-        with open(filename) as file_in:
-            for line in file_in:
-                if re.match(r'\S*(?=/[^/]*\.[h][p]?)',line) is not None:
-                    lines.extend(re.findall(r'\S*(?=/[^/]*\.[h][p]?)/',line))
-                if re.match(r'\S*(?=\.[cC][pP]{0,})[^\\\s]*',line) is not None:
-                    source = re.findall(r'\S*(?=\.[cC][pP]{0,})[^\\\s]*',line)[0]
-        
-        print_paths(lines,filename,source )
-            
-def main():
-    cwd_path=check_path(os.getcwd())
-    os.environ['CWD']= cwd_path
-    os.environ['PWD']= cwd_path
-    idf_path= os.environ.get('IDF_PATH').replace("/", "\\")
-    cwd_path= os.environ.get('CWD')
-    pwd_path= os.environ.get('PWD')
-    print('Running custom script make in {}, IDF_PATH={}, CWD={}, PWD={}'.format(cwd_path,idf_path,cwd_path,pwd_path))
-    
-    make = subprocess.Popen(["make"] + sys.argv[1:] + ["BATCH_BUILD=1"], stdout=subprocess.PIPE)
-    for line in iter(make.stdout.readline, ''):
-        line = re.sub(UNIX_PATH_RE, lambda m: check_path(m.group(0)), line)
-        names.extend(INCLUDE_PATH_RE.findall(line))
-        print(line.rstrip())
-    sys.exit(make.wait())
-
-if __name__ == "__main__":
-    main()

+ 69 - 50
main/Kconfig.projbuild

@@ -21,7 +21,6 @@ menu "Squeezelite-ESP32"
         	help
         		Set logging level info|debug|sdebug 	
 	endmenu
-	
 	config JACK_LOCKED
 		bool
 	config BAT_LOCKED	
@@ -37,55 +36,75 @@ menu "Squeezelite-ESP32"
 	config MUTE_GPIO_LEVEL
 		int 
 		default 0
-		
-# AGGREGATES - begin
-# these parameters are "aggregates"	that take precedence. The must have a default value	
-	config DAC_CONFIG
-		string 
-		default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP
-		default "model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32" if A1S
-		default "model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22" if TWATCH2020
-		default ""
-	config SPDIF_CONFIG		
-		string
-		default "bck=33,ws=25,do=15" if SQUEEZEAMP
-		default	""
-	config SPI_CONFIG
-		string
-		default "dc=27,data=19,clk=18" if TWATCH2020		
-		default	""
-	config DISPLAY_CONFIG
-		string
-		default "SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip" if TWATCH2020
-		default ""
-	config DAC_CONTROLSET
-		string
-		default "{ \"init\": [ {\"reg\":41, \"val\":128}, {\"reg\":18, \"val\":255} ], \"poweron\": [ {\"reg\":18, \"val\":64, \"mode\":\"or\"} ], \"poweroff\": [ {\"reg\":18, \"val\":191, \"mode\":\"and\"} ] }" if TWATCH2020
-		default ""		
-# AGGREGATES - end		
-		
-	choice OUTPUT_TYPE
-		prompt "Main system"
-	       default BASIC_I2C_BT
-	       help
-	           Type of hardware platform
-	       config SQUEEZEAMP 
-			bool "SqueezeAMP"
-			select JACK_LOCKED
-			select BAT_LOCKED
-			select I2C_LOCKED
-			select LED_LOCKED
-			select SPKFAULT_LOCKED
-		config A1S
-	           bool "ESP32-A1S module"				
-			select I2C_LOCKED
-		config TWATCH2020	
-			bool "T-WATCH2020 by LilyGo"				
-			select I2C_LOCKED				
-	       config BASIC_I2C_BT
-	           bool "Generic I2S & Bluetooth"
-	endchoice		
-
+	menu "Target"
+		choice OUTPUT_TYPE
+			prompt "Main system"
+			   default BASIC_I2C_BT
+			   help
+				   Type of hardware platform
+			config SQUEEZEAMP 
+				bool "SqueezeAMP"
+				select JACK_LOCKED
+				select BAT_LOCKED
+				select I2C_LOCKED
+				select LED_LOCKED
+				select SPKFAULT_LOCKED
+			config A1S
+				   bool "ESP32-A1S module"				
+				select I2C_LOCKED
+			config DAC32
+					bool "DAC32 module"				
+			config TWATCH2020	
+				bool "T-WATCH2020 by LilyGo"				
+				select I2C_LOCKED				
+			   config BASIC_I2C_BT
+				   bool "Generic I2S & Bluetooth"
+		endchoice	
+		config RELEASE_API
+        	string "Software update URL"
+			default "https://api.github.com/repos/sle118/squeezelite-esp32/releases" if !DAC32
+			default "https://yourdomain/api/releases" if DAC32
+        	help
+        		Set the URL of the API that the front-end UI will use to fetch software updates 
+		config SQUEEZELITE_ESP32_RELEASE_URL
+			string "Release URL"
+			default "https://github.com/sle118/squeezelite-esp32/releases" if !DAC32
+			default "https://yourdomain/releases" if DAC32
+			help
+				Set the URL where users can see a list of releases
+		config PROJECT_NAME
+			string "Project Name"
+			default "Squeezelite-A1S" if A1S
+			default "SqueezeAMP" if SQUEEZEAMP
+			default "DAC32" if DAC32
+			default "Squeezelite-TWATCH" if TWATCH2020
+			default "Squeezelite-ESP32" if !A1S && !SQUEEZEAMP && !DAC32 && !TWATCH2020
+		# AGGREGATES - begin
+		# these parameters are "aggregates"	that take precedence. The must have a default value	
+		config DAC_CONFIG
+			string 
+			default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP
+			default "model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32" if A1S
+			default "model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22" if TWATCH2020
+			default ""
+		config SPDIF_CONFIG		
+			string
+			default "bck=33,ws=25,do=15" if SQUEEZEAMP
+			default	""
+		config SPI_CONFIG
+			string
+			default "dc=27,data=19,clk=18" if TWATCH2020		
+			default	""
+		config DISPLAY_CONFIG
+			string
+			default "SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip" if TWATCH2020
+			default ""
+		config DAC_CONTROLSET
+			string
+			default "{ \"init\": [ {\"reg\":41, \"val\":128}, {\"reg\":18, \"val\":255} ], \"poweron\": [ {\"reg\":18, \"val\":64, \"mode\":\"or\"} ], \"poweroff\": [ {\"reg\":18, \"val\":191, \"mode\":\"and\"} ] }" if TWATCH2020
+			default ""		
+		# AGGREGATES - end				
+	endmenu
 	menu "Audio settings"
 		menu "DAC settings" 
 			visible if BASIC_I2C_BT

+ 6 - 3
main/esp_app_main.c

@@ -20,7 +20,6 @@
 #include "esp_system.h"
 #include "esp_spi_flash.h"
 #include "esp_wifi.h"
-#include "esp_system.h"
 #include <esp_event.h>
 #include "nvs_flash.h"
 #include "esp_log.h"
@@ -291,8 +290,8 @@ void register_default_nvs(){
 	ESP_LOGD(TAG,"Registering default value for key %s, value %s", "bt_sink_pin", STR(CONFIG_A2DP_CONTROL_DELAY_MS));
 
 	config_set_default(NVS_TYPE_STR, "bt_sink_pin", STR(CONFIG_BT_SINK_PIN), 0);
-	ESP_LOGD(TAG,"Registering default value for key %s, value %s", "release_url", SQUEEZELITE_ESP32_RELEASE_URL);
-	config_set_default(NVS_TYPE_STR, "release_url", SQUEEZELITE_ESP32_RELEASE_URL, 0);
+	ESP_LOGD(TAG,"Registering default value for key %s, value %s", "release_url", CONFIG_SQUEEZELITE_ESP32_RELEASE_URL);
+	config_set_default(NVS_TYPE_STR, "release_url", CONFIG_SQUEEZELITE_ESP32_RELEASE_URL, 0);
 	ESP_LOGD(TAG,"Registering default value for key %s, value %s","ap_ip_address",CONFIG_DEFAULT_AP_IP );
 	config_set_default(NVS_TYPE_STR, "ap_ip_address",CONFIG_DEFAULT_AP_IP , 0);
 	ESP_LOGD(TAG,"Registering default value for key %s, value %s", "ap_ip_gateway",CONFIG_DEFAULT_AP_GATEWAY );
@@ -382,6 +381,10 @@ void register_default_nvs(){
 	
 	ESP_LOGD(TAG,"Registering default value for key %s", "stats");
 	config_set_default(NVS_TYPE_STR, "stats", "n", 0);
+
+	ESP_LOGD(TAG,"Registering default value for key %s", "rel_api");
+	config_set_default(NVS_TYPE_STR, "rel_api", CONFIG_RELEASE_API, 0);
+
 	wait_for_commit();
 	ESP_LOGD(TAG,"Done setting default values in nvs.");
 }

+ 2 - 2
main/platform_esp32.h

@@ -12,8 +12,8 @@
 #pragma once
 
 #include "esp_pthread.h"
-#ifndef SQUEEZELITE_ESP32_RELEASE_URL
-#define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
+#ifndef CONFIG_SQUEEZELITE_ESP32_RELEASE_URL
+#define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
 #endif
 
 extern void run_command(char * line);

+ 8 - 4
sdkconfig

@@ -76,15 +76,19 @@ CONFIG_LOGGING_STREAM="info"
 CONFIG_LOGGING_DECODE="info"
 CONFIG_LOGGING_OUTPUT="info"
 CONFIG_MUTE_GPIO_LEVEL=0
+# CONFIG_SQUEEZEAMP is not set
+# CONFIG_A1S is not set
+# CONFIG_DAC32 is not set
+# CONFIG_TWATCH2020 is not set
+CONFIG_BASIC_I2C_BT=y
+CONFIG_RELEASE_API="https://api.github.com/repos/sle118/squeezelite-esp32/releases"
+CONFIG_SQUEEZELITE_ESP32_RELEASE_URL="https://github.com/sle118/squeezelite-esp32/releases"
+CONFIG_PROJECT_NAME="Squeezelite-ESP32"
 CONFIG_DAC_CONFIG=""
 CONFIG_SPDIF_CONFIG=""
 CONFIG_SPI_CONFIG=""
 CONFIG_DISPLAY_CONFIG=""
 CONFIG_DAC_CONTROLSET=""
-# CONFIG_SQUEEZEAMP is not set
-# CONFIG_A1S is not set
-# CONFIG_TWATCH2020 is not set
-CONFIG_BASIC_I2C_BT=y
 CONFIG_I2S_NUM=0
 CONFIG_I2S_BCK_IO=-1
 CONFIG_I2S_WS_IO=-1

+ 1 - 1
version.txt

@@ -1 +1 @@
-custom.build
+local.500.cmake-master

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor