浏览代码

UI change of the update mechanism

Sebastien 3 年之前
父节点
当前提交
d61c650f39
共有 36 个文件被更改,包括 590 次插入677 次删除
  1. 2 1
      build-scripts/ESP32-A1S-sdkconfig.defaults
  2. 1 0
      build-scripts/I2S-4MFlash-sdkconfig.defaults
  3. 1 0
      build-scripts/SqueezeAmp-sdkconfig.defaults
  4. 115 4
      components/platform_console/cmd_config.c
  5. 2 1
      components/platform_console/platform_console.c
  6. 88 8
      components/services/accessors.c
  7. 13 1
      components/services/accessors.h
  8. 66 2
      components/squeezelite-ota/squeezelite-ota.c
  9. 1 1
      components/squeezelite-ota/squeezelite-ota.h
  10. 1 0
      components/tools/platform_esp32.h
  11. 1 1
      components/wifi-manager/webapp/.eslintcache
  12. 4 2
      components/wifi-manager/webapp/mock/status.json
  13. 11 9
      components/wifi-manager/webapp/src/index.ejs
  14. 139 498
      components/wifi-manager/webapp/src/js/custom.js
  15. 1 0
      components/wifi-manager/webapp/src/test.ejs
  16. 3 3
      components/wifi-manager/webapp/webapp.cmake
  17. 15 42
      components/wifi-manager/webapp/webpack.c
  18. 25 82
      components/wifi-manager/webapp/webpack.h
  19. 二进制
      components/wifi-manager/webapp/webpack/dist/favicon-32x32.png
  20. 0 0
      components/wifi-manager/webapp/webpack/dist/index.html
  21. 二进制
      components/wifi-manager/webapp/webpack/dist/index.html.br
  22. 二进制
      components/wifi-manager/webapp/webpack/dist/index.html.gz
  23. 0 0
      components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js
  24. 二进制
      components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.br
  25. 二进制
      components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.gz
  26. 0 7
      components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js
  27. 二进制
      components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.br
  28. 二进制
      components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.gz
  29. 0 1
      components/wifi-manager/webapp/webpack/dist/js/runtime.0b6890.bundle.js
  30. 二进制
      components/wifi-manager/webapp/webpack/dist/js/runtime.0b6890.bundle.js.br
  31. 二进制
      components/wifi-manager/webapp/webpack/dist/js/runtime.0b6890.bundle.js.gz
  32. 23 4
      components/wifi-manager/webapp/webpack/webpack.dev.js
  33. 56 3
      components/wifi-manager/wifi_manager.c
  34. 7 0
      main/Kconfig.projbuild
  35. 8 1
      main/esp_app_main.c
  36. 7 6
      sdkconfig

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

@@ -31,7 +31,8 @@ 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_PROJECT_NAME="Squeezelite ESP32-A1S"
+CONFIG_FW_PLATFORM_NAME="ESP32-A1S"
 CONFIG_IDF_TARGET_ESP32=y
 CONFIG_IDF_TARGET="esp32"
 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000

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

@@ -37,6 +37,7 @@ 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"
+CONFIG_FW_PLATFORM_NAME="I2S-4MFlash"
 #
 # SDK tool configuration
 #

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

@@ -33,6 +33,7 @@ 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_FW_PLATFORM_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"
 #

+ 115 - 4
components/platform_console/cmd_config.c

@@ -24,6 +24,7 @@ const char * desc_dac= "DAC Options";
 const char * desc_spdif= "SPDIF Options";
 const char * desc_audio= "General Audio Options";
 const char * desc_bt_source= "Bluetooth Audio Output Options";
+const char * desc_rotary= "Rotary Control";
 
 
 #define CODECS_BASE "flac|pcm|mp3|ogg"
@@ -85,6 +86,19 @@ static struct {
     struct arg_end *end;
 } i2s_args;
 
+static struct {
+	struct arg_rem * rem;
+	struct arg_int * A;
+	struct arg_int * B;
+	struct arg_int * SW;
+	struct arg_lit * volume_lock;
+	struct arg_lit * longpress;
+	struct arg_lit * knobonly;
+	struct arg_int * timer;
+	struct arg_lit * clear;
+	struct arg_end * end;
+} rotary_args;
+//config_rotary_get
 static struct{
 		struct arg_str *sink_name;
 		struct arg_str *pin_code;
@@ -142,7 +156,7 @@ static struct {
     struct arg_end *end;
 } squeezelite_args;
 
-int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory){
+int is_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory, bool output){
 	int res = 0;
 	const char * name = gpio->hdr.longopts?gpio->hdr.longopts:gpio->hdr.glossary;
 	*gpio_out=-1;
@@ -152,7 +166,7 @@ int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandato
 			fprintf(f,"Missing: %s\n", name);
 			res++;
 		}
-	} else  if(!GPIO_IS_VALID_OUTPUT_GPIO(t_gpio)){
+	} else  if((output && !GPIO_IS_VALID_OUTPUT_GPIO(t_gpio)) || (!GPIO_IS_VALID_GPIO(t_gpio))){
 		fprintf(f,"Invalid %s gpio: [%d] %s\n",name, t_gpio, GPIO_IS_VALID_GPIO(t_gpio)?NOT_OUTPUT:NOT_GPIO );
 		res++;
 	}
@@ -161,7 +175,9 @@ int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandato
 	}
 	return res;
 }
-
+int is_output_gpio(struct arg_int * gpio, FILE * f, int * gpio_out, bool mandatory){
+	return is_gpio(gpio,f,gpio_out,mandatory,true);
+}
 int check_missing_parm(struct arg_int * int_parm, FILE * f){
 	int res=0;
 	const char * name = int_parm->hdr.longopts?int_parm->hdr.longopts:int_parm->hdr.glossary;
@@ -482,6 +498,60 @@ static int do_spdif_cmd(int argc, char **argv){
 	return (nerrors==0 && err==ESP_OK)?0:1;
 }
 
+static int do_rotary_cmd(int argc, char **argv){
+	rotary_struct_t rotary={  .A = -1, .B = -1, .SW = -1, .longpress = 0, .knobonly=0,.volume_lock=false};
+	esp_err_t err=ESP_OK;
+	int nerrors = arg_parse(argc, argv,(void **)&rotary_args);
+	if (rotary_args.clear->count) {
+		cmd_send_messaging(argv[0],MESSAGING_WARNING,"rotary config cleared\n");
+		config_set_value(NVS_TYPE_STR, "rotary_config", "");
+		return 0;
+	}
+
+	char *buf = NULL;
+	size_t buf_size = 0;
+	FILE *f = open_memstream(&buf, &buf_size);
+	if (f == NULL) {
+		cmd_send_messaging(argv[0],MESSAGING_ERROR,"Unable to open memory stream.\n");
+		return 1;
+	}
+	if(nerrors >0){
+		arg_print_errors(f,rotary_args.end,desc_rotary);
+		return 1;
+	}
+	nerrors+=is_gpio(rotary_args.A, f, &rotary.A, true,false);
+	nerrors+=is_gpio(rotary_args.B, f, &rotary.B, true,false);
+	nerrors+=is_gpio(rotary_args.SW, f, &rotary.SW,false,false);
+
+
+	if(rotary_args.knobonly->count>0 && (rotary_args.volume_lock->count>0 || rotary_args.longpress->count>0)){
+		fprintf(f,"error: Cannot use volume lock or longpress option when knob only option selected\n");
+		nerrors++;
+	}
+	if(rotary_args.timer->count>0 && rotary_args.timer->ival[0]<0){
+		fprintf(f,"error: knob only timer should be greater than or equal to zero.\n");
+		nerrors++;
+	}
+	else {
+		rotary.timer = rotary_args.timer->count>0?rotary_args.timer->ival[0]:0;
+	}
+	rotary.knobonly = rotary_args.knobonly->count>0;
+	rotary.volume_lock= rotary_args.volume_lock->count>0;
+	rotary.longpress = rotary_args.longpress->count>0;
+	if(!nerrors ){
+		fprintf(f,"Storing rotary parameters.\n");
+		nerrors+=(config_rotary_set(&rotary )!=ESP_OK);
+	}
+	if(!nerrors ){
+		fprintf(f,"Done.\n");
+	}
+	fflush (f);
+	cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
+	fclose(f);
+	FREE_AND_NULL(buf);
+	return (nerrors==0 && err==ESP_OK)?0:1;
+}
+
 static int do_i2s_cmd(int argc, char **argv)
 {
 	i2s_platform_config_t i2s_dac_pin = {
@@ -624,6 +694,23 @@ cJSON * spdif_cb(){
 		
 	return values;
 }
+cJSON * rotary_cb(){
+	cJSON * values = cJSON_CreateObject();
+	const rotary_struct_t *rotary= config_rotary_get();
+	
+	if(GPIO_IS_VALID_GPIO(rotary->A ) && rotary->A>=0 && GPIO_IS_VALID_GPIO(rotary->B) && rotary->B>=0){
+		cJSON_AddNumberToObject(values,"A",rotary->A);
+		cJSON_AddNumberToObject(values,"B",rotary->B);
+		if(GPIO_IS_VALID_GPIO(rotary->SW ) && rotary->SW>=0 ){
+			cJSON_AddNumberToObject(values,"SW",rotary->SW);
+		}
+		cJSON_AddBoolToObject(values,"volume_lock",rotary->volume_lock);
+		cJSON_AddBoolToObject(values,"longpress",rotary->longpress);
+		cJSON_AddBoolToObject(values,"knobonly",rotary->knobonly);
+		cJSON_AddNumberToObject(values,"timer",rotary->timer);
+	}
+	return values;
+}
 cJSON * audio_cb(){
 	cJSON * values = cJSON_CreateObject();
 	char * 	p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0);
@@ -815,6 +902,27 @@ static void register_bt_source_config(void){
     ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
 }
 
+static void register_rotary_config(void){
+	rotary_args.rem = arg_rem("remark","One rotary encoder is supported, quadrature shift with press. Such encoders usually have 2 pins for encoders (A and B), and common C that must be set to ground and an optional SW pin for press. A, B and SW must be pulled up, so automatic pull-up is provided by ESP32, but you can add your own resistors. A bit of filtering on A and B (~470nF) helps for debouncing which is not made by software.\r\nEncoder is normally hard-coded to respectively knob left, right and push on LMS and to volume down/up/play toggle on BT and AirPlay.");
+	rotary_args.A = arg_int1(NULL,"A","gpio","A/DT gpio");
+	rotary_args.B = arg_int1(NULL,"B","gpio","B/CLK gpio");
+	rotary_args.SW = arg_int0(NULL,"SW","gpio","Switch gpio");
+	rotary_args.knobonly = arg_lit0(NULL,"knobonly","Single knob full navigation. Left, Right and Press is navigation, with Press always going to lower submenu item. Longpress is 'Play', Double press is 'Back', a quick left-right movement on the encoder is 'Pause'");
+	rotary_args.timer = arg_int0(NULL,"timer","ms","The speed of double click (or left-right) when knob only option is enabled. Be aware that the longer you set double click speed, the less responsive the interface will be. ");
+	rotary_args.volume_lock = arg_lit0(NULL,"volume_lock", "Force Volume down/up/play toggle all the time (even in LMS). ");
+	rotary_args.longpress = arg_lit0(NULL,"longpress","Enable alternate mode mode on long-press. In that mode, left is previous, right is next and press is toggle. Every long press on SW alternates between modes (the main mode actual behavior depends on 'volume').");
+	rotary_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
+	rotary_args.end = arg_end(3);
+	const esp_console_cmd_t cmd = {
+        .command = CFG_TYPE_HW("rotary"),
+        .help = desc_rotary,
+        .hint = NULL,
+        .func = &do_rotary_cmd,
+        .argtable = &rotary_args
+    };
+    cmd_to_json_with_cb(&cmd,&rotary_cb);
+    ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
+}
 
 static void register_audio_config(void){
 	audio_args.jack_behavior = arg_str0("j", "jack_behavior","Headphones|Subwoofer","On supported DAC, determines the audio jack behavior. Selecting headphones will cause the external amp to be muted on insert, while selecting Subwoofer will keep the amp active all the time.");
@@ -828,7 +936,9 @@ static void register_audio_config(void){
     };
     cmd_to_json_with_cb(&cmd,&audio_cb);
     ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
-}static void register_spdif_config(void){
+}
+
+static void register_spdif_config(void){
 	spdif_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
     spdif_args.clock = arg_int1(NULL,"clock","<n>","Clock GPIO. e.g. 33");
     spdif_args.wordselect = arg_int1(NULL,"wordselect","<n>","Word Select GPIO. e.g. 25");
@@ -893,5 +1003,6 @@ void register_config_cmd(void){
 	register_bt_source_config();
 	register_i2s_config();
 	register_spdif_config();
+	register_rotary_config();
 }
 

+ 2 - 1
components/platform_console/platform_console.c

@@ -97,7 +97,8 @@ cJSON * ParmsToJSON(struct arg_hdr * * argtable){
 		ADD_TO_JSON(entry,table[tabindex],glossary);
 		ADD_TO_JSON(entry,table[tabindex],longopts);
 		ADD_TO_JSON(entry,table[tabindex],shortopts);
-		cJSON_AddBoolToObject(entry, "checkbox", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0);
+		cJSON_AddBoolToObject(entry, "checkbox", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0 && (table[tabindex]->longopts || table[tabindex]->shortopts) );
+		cJSON_AddBoolToObject(entry, "remark", (table[tabindex]->flag & ARG_HASOPTVALUE)==0 && (table[tabindex]->flag & ARG_HASVALUE)==0 && (!table[tabindex]->longopts && !table[tabindex]->shortopts));
 		cJSON_AddBoolToObject(entry, "hasvalue", table[tabindex]->flag & ARG_HASVALUE);
 		cJSON_AddNumberToObject(entry,"mincount",table[tabindex]->mincount);
 		cJSON_AddNumberToObject(entry,"maxcount",table[tabindex]->maxcount);

+ 88 - 8
components/services/accessors.c

@@ -183,6 +183,47 @@ esp_err_t config_i2c_set(const i2c_config_t * config, int port){
 	return err;
 }
 
+/****************************************************************************************
+ * 
+ */
+esp_err_t config_rotary_set(rotary_struct_t * config){
+	int buffer_size=512;
+	esp_err_t err=ESP_OK;
+	char * config_buffer=calloc(buffer_size,1);
+	char * config_buffer2=calloc(buffer_size,1);	
+	if(config_buffer && config_buffer2)  {
+		snprintf(config_buffer,buffer_size,"A=%i,B=%i",config->A, config->B);
+		if(config->SW >=0 ){
+			snprintf(config_buffer2,buffer_size,"%s,SW=%i",config_buffer,config->SW);
+			strcpy(config_buffer,config_buffer2);
+		}
+		if(config->knobonly){
+			strncat(config_buffer,",knobonly",buffer_size);
+			if(config->timer>0){
+				snprintf(config_buffer2,buffer_size,"%s=%i",config_buffer,config->timer);
+				strcpy(config_buffer,config_buffer2);
+			}
+		}
+		if(config->volume_lock){
+			strncat(config_buffer,",volume",buffer_size);
+		}
+		if(config->longpress){
+			strncat(config_buffer,",longpress",buffer_size);
+		}
+			log_send_messaging(MESSAGING_INFO,"Updating rotary configuration to %s",config_buffer);
+		err = config_set_value(NVS_TYPE_STR, "rotary_config", config_buffer);
+		if(err!=ESP_OK){
+			log_send_messaging(MESSAGING_ERROR,"Error: %s",esp_err_to_name(err));
+		}
+	} 
+	else {
+		err = ESP_ERR_NO_MEM;
+	}
+	FREE_AND_NULL(config_buffer);
+	FREE_AND_NULL(config_buffer2);	
+	return err;	
+}
+
 /****************************************************************************************
  * 
  */
@@ -192,7 +233,7 @@ esp_err_t config_display_set(const display_config_t * config){
 	char * config_buffer=calloc(buffer_size,1);
 	char * config_buffer2=calloc(buffer_size,1);
 	if(config_buffer && config_buffer2)  {
-		snprintf(config_buffer,buffer_size,"%s:width=%i,height=%i",config->type,config->width,config->height);
+		snprintf(config_buffer,buffer_size,"%s,width=%i,height=%i",config->type,config->width,config->height);
 		if(strcasecmp("I2C",config->type)==0){
 			if(config->address>0 ){
 				snprintf(config_buffer2,buffer_size,"%s,address=%i",config_buffer,config->address);
@@ -510,6 +551,36 @@ void parse_set_GPIO(void (*cb)(int gpio, char *value)) {
 	free(nvs_item);
 }	
 
+/****************************************************************************************
+ * 
+ */
+const rotary_struct_t * config_rotary_get() {
+
+	static rotary_struct_t rotary={  .A = -1, .B = -1, .SW = -1, .longpress = false, .knobonly=false,.timer=0,.volume_lock=false};
+	char *config = config_alloc_get_default(NVS_TYPE_STR, "rotary_config", NULL, 0);
+	if (config && *config) {
+		char *p;
+		
+		// parse config
+		if ((p = strcasestr(config, "A")) != NULL) rotary.A = atoi(strchr(p, '=') + 1);
+		if ((p = strcasestr(config, "B")) != NULL) rotary.B = atoi(strchr(p, '=') + 1);
+		if ((p = strcasestr(config, "SW")) != NULL) rotary.SW = atoi(strchr(p, '=') + 1);
+		if ((p = strcasestr(config, "knobonly")) != NULL) {
+			p = strchr(p, '=');
+			rotary.knobonly = true;
+			rotary.timer = p ? atoi(p + 1) : 350;
+			rotary.longpress = false;
+		} else {
+			rotary.knobonly = false;
+			rotary.timer = 0;
+			if ((p = strcasestr(config, "volume")) != NULL) rotary.volume_lock = true;
+			if ((p = strcasestr(config, "longpress")) != NULL) rotary.longpress = true;
+		}	
+		free(config);
+	}
+	return &rotary;
+}
+
 /****************************************************************************************
  *
  */
@@ -522,6 +593,17 @@ cJSON * get_gpio_entry(const char * name, const char * prefix, int gpio, bool fi
 	return entry;
 }
 
+/****************************************************************************************
+ *
+ */
+cJSON * add_gpio_for_value(cJSON * list,const char * name,int gpio, const char * prefix, bool fixed){
+	cJSON * llist = list?list:cJSON_CreateArray();
+	if(GPIO_IS_VALID_GPIO(gpio) && gpio>0){
+		cJSON_AddItemToArray(llist,get_gpio_entry(name,prefix,gpio,fixed));
+	}
+	return llist;
+}
+
 /****************************************************************************************
  *
  */
@@ -657,13 +739,11 @@ cJSON * get_SPDIF_GPIO(cJSON * list, bool fixed){
  */
 cJSON * get_Rotary_GPIO(cJSON * list){
 	cJSON * llist = list?list:cJSON_CreateArray();
-	char *config = config_alloc_get_default(NVS_TYPE_STR, "rotary_config", NULL, 0);
-	if(config){
-		llist = add_gpio_for_name(llist,config,"A", "rotary", false);
-		llist = add_gpio_for_name(llist,config,"B", "rotary", false);
-		llist = add_gpio_for_name(llist,config,"SW", "rotary", false);
-		free(config);	
-	}	
+
+	const rotary_struct_t *rotary= config_rotary_get();
+	add_gpio_for_value(llist,"A",rotary->A, "rotary", false);
+	add_gpio_for_value(llist,"B",rotary->B, "rotary", false);
+	add_gpio_for_value(llist,"SW",rotary->SW, "rotary", false);
 	return llist;
 }
 

+ 13 - 1
components/services/accessors.h

@@ -57,6 +57,16 @@ typedef struct {
 	gpio_with_level_t spkfault;	
 } set_GPIO_struct_t;
 
+typedef struct {
+	int A;
+	int B;
+	int SW;
+	bool knobonly;
+	bool volume_lock;
+	bool longpress;
+	int timer;
+} rotary_struct_t;
+
 typedef struct {
 	bool fixed;
 	char * name;
@@ -81,4 +91,6 @@ gpio_entry_t * 				get_gpio_by_name(char * name,char * group, bool refresh);
 gpio_entry_t * 				get_gpio_by_no(int gpionum, bool refresh);
 cJSON * 					get_gpio_list(bool refresh);
 bool 						is_dac_config_locked();
-bool 						are_statistics_enabled();
+bool 						are_statistics_enabled();
+const rotary_struct_t * 	config_rotary_get();
+esp_err_t 					config_rotary_set(rotary_struct_t * rotary);

+ 66 - 2
components/squeezelite-ota/squeezelite-ota.c

@@ -38,6 +38,8 @@
 #include "gds_text.h"
 #include "gds_draw.h"
 #include "platform_esp32.h"
+#include "lwip/sockets.h"
+
 
 extern const char * get_certificate();
 #define IF_DISPLAY(x) if(display) { x; }
@@ -92,6 +94,7 @@ ota_status_t * ota_status;
 struct timeval tv;
 static esp_http_client_config_t http_client_config;
 
+
 void _printMemStats(){
 	ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)",
 			heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
@@ -276,8 +279,8 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt)
 //	int data_len - data length of data
 //	void *user_data -- user_data context, from esp_http_client_config_t user_data
 
-//	char *header_key For HTTP_EVENT_ON_HEADER event_id, its store current http header key
-//	char *header_value For HTTP_EVENT_ON_HEADER event_id, its store current http header value
+//	char *header_key For HTTP_EVENT_ON_HEADER event_id, it�s store current http header key
+//	char *header_value For HTTP_EVENT_ON_HEADER event_id, it�s store current http header value
 // --------------
     switch (evt->event_id) {
     case HTTP_EVENT_ERROR:
@@ -721,5 +724,66 @@ esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t
     return ESP_OK;
 }
 
+extern void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport);
+
+in_addr_t discover_ota_server(int max) {
+	struct sockaddr_in d;
+	struct sockaddr_in s;
+	char buf[32], port_d[] = "JSON", clip_d[] = "CLIP";
+	struct pollfd pollinfo;
+	uint8_t len;
+	uint16_t hport=9000;
+	uint16_t cport=9090;
+
+	int disc_sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+	socklen_t enable = 1;
+	setsockopt(disc_sock, SOL_SOCKET, SO_BROADCAST, (const void *)&enable, sizeof(enable));
+
+	len = sprintf(buf,"e%s%c%s", port_d, '\0', clip_d) + 1;
+
+	memset(&d, 0, sizeof(d));
+	d.sin_family = AF_INET;
+	d.sin_port = htons(3483);
+	d.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+
+	pollinfo.fd = disc_sock;
+	pollinfo.events = POLLIN;
+
+	do {
+
+		ESP_LOGI(TAG,"sending LMS discovery");
+		memset(&s, 0, sizeof(s));
 
+		if (sendto(disc_sock, buf, len, 0, (struct sockaddr *)&d, sizeof(d)) < 0) {
+			ESP_LOGE(TAG,"error sending discovery");
+		}
+		else {
+
+			if (poll(&pollinfo, 1, 5000) == 1) {
+				char readbuf[64], *p;
+				socklen_t slen = sizeof(s);
+				memset(readbuf, 0, sizeof(readbuf));
+				recvfrom(disc_sock, readbuf, sizeof(readbuf) - 1, 0, (struct sockaddr *)&s, &slen);
+				ESP_LOGI(TAG,"got response from: %s:%d - %s", inet_ntoa(s.sin_addr), ntohs(s.sin_port),readbuf);
+
+				if ((p = strstr(readbuf, port_d)) != NULL) {
+					p += strlen(port_d);
+					hport = atoi(p + 1);
+				}
+
+				if ((p = strstr(readbuf, clip_d)) != NULL) {
+					p += strlen(clip_d);
+					cport = atoi(p + 1);
+				}
+				server_notify(s.sin_addr.s_addr, hport, cport);
+			}
+		}
+
+	} while (s.sin_addr.s_addr == 0 && (!max || --max));
+
+	closesocket(disc_sock);
+
+	return s.sin_addr.s_addr;
+}
 

+ 1 - 1
components/squeezelite-ota/squeezelite-ota.h

@@ -31,4 +31,4 @@ const char * ota_get_status();
 uint8_t ota_get_pct_complete();
 
 esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length);
-
+in_addr_t discover_ota_server(int max);

+ 1 - 0
components/tools/platform_esp32.h

@@ -33,3 +33,4 @@ extern void console_start();
 extern pthread_cond_t wifi_connect_suspend_cond;
 extern pthread_t wifi_connect_suspend_mutex;
 
+extern void (*server_notify)(in_addr_t ip, uint16_t hport, uint16_t cport);

+ 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":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",[]]
+[{"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":57729,"mtime":1618063084495,"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",[]]

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

@@ -16,6 +16,8 @@
 	"netmask": "255.255.255.0",
 	"gw": "192.168.10.1",
 	"lms_cport": 9090,
-	"lms_port": 9000,
-	"lms_ip": "127.0.0.1"
+	"lms_port": 9100,
+	"lms_ip": "127.0.0.1",
+	"mock_plugin_has_proxy": "x",
+	"platform_name": "SqueezeAmp"
 }

+ 11 - 9
components/wifi-manager/webapp/src/index.ejs

@@ -157,6 +157,10 @@
 								<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 class="col-auto">
+								<button class="btn-warning ota_element" type="submit" onclick="handleReboot('recovery');" >Recovery</button>
+							</div>
 						</div>
 
 					</div>
@@ -171,7 +175,7 @@
 								</button>
 							</div>
 							<div class="modal-body">
-								<p>Flash URL <span id="selectedFWURL"></span> to device?</p>
+								<p>Flash URL <span id="selectedFWURL" class="text-break"></span> to device?</p>
 							</div>
 							<div class="modal-footer  ">
 								<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
@@ -181,7 +185,7 @@
 						</div>
 					</div>
 				</div>
-				<div class="card text-white  mb-3">
+				<div class="card text-white mb-3 recovery_element" style="display: none;">
 					<div class="card-header">Local Firmware Upload</div>
 					<div class="card-body">
 							<div id="uploaddiv" class="recovery_element form-group row">
@@ -374,12 +378,10 @@
 									<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 class="modal-footer connecting-success connecting-status justify-content-between" style=""><button type="button"
+									class="btn btn-primary" data-dismiss="modal">Ok</button><button type="button" class="btn btn-danger"
+									data-toggle="modal" data-dismiss="modal" data-target="#WiFiDisconnectConfirm">Disconnect</button> 
 							</div>
-
 						</div>
 					</div>
 				</div>
@@ -499,8 +501,8 @@
 	<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);"
+				type="submit" onclick="handleReboot('reboot');" style="display: none;">Reboot</button>
+			<button class="btn-warning recovery_element" id="reboot_ota_nav" type="submit" onclick="handleReboot('reboot_ota');"
 				style="display: none;">Exit Recovery</button><span class="text-center" id="foot-wifi"></span>
 		</div>
 

+ 139 - 498
components/wifi-manager/webapp/src/js/custom.js

@@ -25,6 +25,7 @@ Object.assign(Date.prototype, {
   },
 });
 
+
 const nvsTypes = {
   NVS_TYPE_U8: 0x01,
 
@@ -108,326 +109,152 @@ const taskStates = {
 };
 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,
+  DONE: 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;
+let older_recovery=false;
+function isFlashExecuting(data){
+  return data.ota_dsc!='' || data.ota_pct>0;
+}
+function post_config(data){
+  let confPayload={
+    timestamp: Date.now(),
+    config : data
+  };
+  $.ajax({
+    url: '/config.json',
+    dataType: 'text',
+    method: 'POST',
+    cache: false,
+    contentType: 'application/json; charset=utf-8',
+    data: JSON.stringify(confPayload),
+    error: handleExceptionResponse,
+  });
+}
+function process_ota_event(data){
+  if(data.ota_dsc){
+    flash_ota_dsc=data.ota_dsc;
+  }
+  if(data.ota_pct){
+    flash_ota_pct=data.ota_pct;
+  }
+  if(isFlashExecuting(data)){
+    flash_state=flash_status_codes.FLASHING;
+  }  
+  if(flash_state==flash_status_codes.FLASHING){
+    if(flash_ota_pct ==100){
+      // we were processing OTA, and we've reached 100%
+      flash_state=flash_status_codes.DONE;
+    } 
+    else if(flash_ota_pct<0 && older_recovery){
+      // we were processing OTA on an older recovery and we missed the 
+      // end of flashing.
+      console.log('End of flashing from older recovery');
+      if(data.ota_dsc==''){
+        flash_ota_dsc = 'OTA Process Completed';
+      }
+      flash_state=flash_status_codes.DONE;
+    }
+  }
 }
-// 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) {
+  START_OTA : function() {
+    if (flash_state == flash_status_codes.NONE || flash_state == undefined) {
       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
-        }
-
-      };
+      flash_state=flash_status_codes.REBOOT_TO_RECOVERY;
+      if(!recovery){
+        flash_ota_dsc = 'Starting recovery mode...';
+        // Reboot system to recovery mode
+        const data = {
+          timestamp: Date.now(),
+        };
+
+        $.ajax({
+          url: '/recovery.json',
+          dataType: 'text',
+          method: 'POST',
+          cache: false,
+          contentType: 'application/json; charset=utf-8',
+          data: JSON.stringify(data),
+          error: handleExceptionResponse,
+          complete: function(response) {
+            console.log(response.responseText);
+          },
+        });     
+      }
 
-      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;
+    if(flash_state == flash_status_codes.REBOOT_TO_RECOVERY){
+        flash_ota_dsc = 'Recovery mode found. Flashing device.';
+        flash_state= flash_status_codes.SET_FWURL;
+        let confData= { fwurl: {
+              value: $('#fw-url-input').val(),
+              type: 33,
+          }
+        };
+        post_config(confData);
     }
   },
-  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;
+  PROCESS_OTA_STATUS: function(data){
+    if(data.ota_pct>0){
+      older_recovery = true;
     }
-  },
-  MESSAGES: function(data) {
-    console.log(JSON.stringify(data));
-    if(data.ota_dsc){
-      flash_ota_dsc=data.ota_dsc;
+    if(flash_state == flash_status_codes.REBOOT_TO_RECOVERY){
+      data.event = flash_events.FOUND_RECOVERY;
+      handle_flash_state(data);
     }
-    if(data.ota_pct){
-      flash_ota_pct=data.ota_pct;
+    else if(flash_state==flash_status_codes.DONE && !recovery){
+      flash_state=flash_status_codes.NONE;
+      $('#rTable tr.release').removeClass('table-success table-warning');
+      $('#fw-url-input').val('');
+      $('#otadiv').modal('hide');
     }
-    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;
+    else {
+      process_ota_event(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;
-    }    
+  },
+  PROCESS_OTA: function(data) {
+    process_ota_event(data);
   }
 };
 window.hideSurrounding = function(obj){
   $(obj).parent().parent().hide();
 }
 
-
 function handle_flash_state(data) {
-  if(isFlashExecuting()) {
-    flash_state= flash_status_codes.FLASHING;
-  }
   if(data.event)  {
     data.event(data);
   } 
+  else {
+    console.error('Unexpected error while processing handle_flash_state');
+    return;
+  }
 
+  if(flash_state && flash_state >flash_status_codes.NONE && flash_ota_pct>=0) {
 
-  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 + '%');
+        .attr('aria-valuenow', flash_ota_pct)
+        .text(flash_ota_pct+'%')
+      $('.progress-bar').html((flash_state==flash_status_codes.DONE?100: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 {
@@ -438,12 +265,12 @@ function handle_flash_state(data) {
 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);
+window.handleReboot = function(link){
+  if(link=='reboot_ota'){
+    $('#reboot_ota_nav').removeClass('active'); delayReboot(500,'', 'reboot_ota');
   }
   else {
-    $('#reboot_nav').removeClass('active'); delayReboot(500,'', false);
+    $('#reboot_nav').removeClass('active'); delayReboot(500,'',link);
   }
 }
 
@@ -547,10 +374,12 @@ var output = '';
 let hostName = '';
 let versionName='Squeezelite-ESP32';
 let project_name=versionName;
+let platform_name=versionName;
 let btSinkNamesOptSel='#cfg-audio-bt_source-sink_name';
 let ConnectedToSSID={};
 let ConnectingToSSID={};
 let lmsBaseUrl;
+let prevLMSIP='';
 const ConnectingToActions = {
   'CONN' : 0,'MAN' : 1,'STS' : 2,
 }
@@ -573,14 +402,6 @@ Promise.prototype.delay = function(duration) {
     }
   );
 };
-// function stopCheckStatusInterval() {
-//   if (checkStatusInterval != null) {
-//     clearTimeout(checkStatusInterval);
-//     checkStatusInterval = null;
-//   }
-//   StatusIntervalActive = false;
-// }
-
 
 function startCheckStatusInterval() {
   StatusIntervalActive = true;
@@ -676,8 +497,8 @@ function onChooseFile(event, onLoadFileHandler) {
   fr.readAsText(file);
   input.value = '';
 }
-function delayReboot(duration, cmdname, ota = false) {
-  const url = ota ? '/reboot_ota.json' : '/reboot.json';
+function delayReboot(duration, cmdname, ota = 'reboot') {
+  const url = '/'+ota+'.json';
   $('tbody#tasks').empty();
   $('#tasks_sect').css('visibility', 'collapse');
   Promise.resolve({ cmdname: cmdname, url: url })
@@ -839,11 +660,8 @@ $(document).ready(function() {
   });
   $('.upSrch').on('input', function() {
     const val = this.value;
-    
-    if(val.length==0) {
-      $("#rTable tr").removeClass(this.id+'_hide');
-    }
-    else {
+    $("#rTable tr").removeClass(this.id+'_hide');
+    if(val.length>0) {
       $(`#rTable td:nth-child(${$(this).parent().index()+1})`).filter(function(){ 
         return !$(this).text().toUpperCase().includes(val.toUpperCase());
       }).parent().addClass(this.id+'_hide');
@@ -907,24 +725,6 @@ $(document).ready(function() {
      }
    });
 
-  // $('#cancel').on('click', function() {
-  //   selectedSSID = '';
-  //   $('#connect').slideUp('fast', function() {});
-  //   $('#connect_manual').slideUp('fast', function() {});
-  //   $('#wifi').slideDown('fast', function() {});
-  // });
-
-  // $('#manual_cancel').on('click', function() {
-  //   selectedSSID = '';
-  //   $('#connect').slideUp('fast', function() {});
-  //   $('#connect_manual').slideUp('fast', function() {});
-  //   $('#wifi').slideDown('fast', function() {});
-  // });
-
-  // $('#ok-details').on('click', function() {
-  //   $('#connect-details').slideUp('fast', function() {});
-  //   $('#wifi').slideDown('fast', function() {});
-  // });
 
   $('#ok-credits').on('click', function() {
     $('#credits').slideUp('fast', function() {});
@@ -937,39 +737,6 @@ $(document).ready(function() {
     $('#credits').slideDown('fast', function() {});
   });
 
-  // $('#disconnect').on('click', function() {
-  //   $('#connect-details-wrap').addClass('blur');
-  //   $('#diag-disconnect').slideDown('fast', function() {});
-  // });
-
-  // $('#no-disconnect').on('click', function() {
-  //   $('#diag-disconnect').slideUp('fast', function() {});
-  //   $('#connect-details-wrap').removeClass('blur');
-  // });
-
-  // $('#yes-disconnect').on('click', function() {
-  //   stopCheckStatusInterval();
-  //   selectedSSID = '';
-
-  //   $('#diag-disconnect').slideUp('fast', function() {});
-  //   $('#connect-details-wrap').removeClass('blur');
-
-  //   $.ajax({
-  //     url: '/connect.json',
-  //     dataType: 'text',
-  //     method: 'DELETE',
-  //     cache: false,
-  //     contentType: 'application/json; charset=utf-8',
-  //     data: JSON.stringify({
-  //       timestamp: Date.now(),
-  //     }),
-  //   });
-
-  //   startCheckStatusInterval();
-
-  //   $('#connect-details').slideUp('fast', function() {});
-  //   $('#wifi').slideDown('fast', function() {});
-  // });
   $('input#show-commands').on('click', function() {
     this.checked = this.checked ? 1 : 0;
     if (this.checked) {
@@ -1008,24 +775,7 @@ $(document).ready(function() {
   });
 
   $('#save-nvs').on('click', function() {
-    const headers = {};
-    const data = {
-      timestamp: Date.now(),
-    };
-    const config = getConfigJson(false);
-    data.config = config;
-    $.ajax({
-      url: '/config.json',
-      dataType: 'text',
-      method: 'POST',
-      cache: false,
-      headers: headers,
-      contentType: 'application/json; charset=utf-8',
-      data: JSON.stringify(data),
-      error: handleExceptionResponse,
-    });
-    console.log('sent config JSON with headers:', JSON.stringify(headers));
-    console.log('sent config JSON with data:', JSON.stringify(data));
+    post_config(getConfigJson(false));
   });
   $('#fwUpload').on('click', function() {
     const uploadPath = '/flash.json';
@@ -1062,35 +812,7 @@ $(document).ready(function() {
       xhttp.send(file);
     }
   });
-  // $('#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;
-  // });
-
-  $('[name=output-tmpl]').on('click', function() {
+   $('[name=output-tmpl]').on('click', function() {
     handleTemplateTypeRadio(this.id);
   });
 
@@ -1152,11 +874,19 @@ $(document).ready(function() {
         });
       }
       $('#searchfw').css('display', 'inline');
-      if($('.upf').filter(function(){ return $(this).text().toUpperCase()===project_name.toUpperCase()}).length>0){
+      if(platform_name!=='' && $('.upf').filter(function(){ return $(this).text().toUpperCase()===platform_name.toUpperCase()}).length>0){
+        $('#splf').val(platform_name).trigger('input');
+      }
+      else 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);
+        var url=this.attributes['fwurl'].value;
+        if (lmsBaseUrl) {
+          url = url.replace(/.*\/download\//, lmsBaseUrl + '/plugins/SqueezeESP32/firmware/');
+        }
+        $('#fw-url-input').val(url);
         $('#start-flash').show();
         $('#rTable tr.release').removeClass('table-success table-warning');
         $(this).addClass('table-success table-warning');
@@ -1252,55 +982,6 @@ $(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');
-  //         }
-  //       });
-  //   });
-  // });
-
   $('#updateAP').on('click', function() {
     refreshAP();
     console.log('refresh AP');
@@ -1333,55 +1014,6 @@ window.setURL = function(button) {
   $('#fwurl').val(url);
 }
 
-// function performConnect(conntype) {
-//   // stop the status refresh. This prevents a race condition where a status
-//   // request would be refreshed with wrong ip info from a previous connection
-//   // and the request would automatically shows as succesful.
-//   stopCheckStatusInterval();
-
-//   // stop refreshing wifi list
-
-//   let pwd;
-//   let dhcpname;
-//   if (conntype === 'manual') {
-//     // Grab the manual SSID and PWD
-//     selectedSSID = $('#manual_ssid').val();
-//     pwd = $('#manual_pwd').val();
-//     dhcpname = $('#dhcp-name2').val();
-//   } else {
-//     pwd = $('#pwd').val();
-//     dhcpname = $('#dhcp-name1').val();
-//   }
-
-//   // reset connection
-//   $('#connect-success').hide();
-//   $('#connect-fail').hide();
-
-//   $('#ok-connect').prop('disabled', true);
-//   $('#ssid-wait').text(selectedSSID);
-//   $('#connect').slideUp('fast', function() {});
-//   $('#connect_manual').slideUp('fast', function() {});
-
-//   $.ajax({
-//     url: '/connect.json',
-//     dataType: 'text',
-//     method: 'POST',
-//     cache: false,
-
-//     //        headers: { 'X-Custom-ssid': selectedSSID, 'X-Custom-pwd': pwd, 'X-Custom-host_name': dhcpname },
-//     contentType: 'application/json; charset=utf-8',
-//     data: JSON.stringify({
-//       timestamp: Date.now(),
-//       ssid: selectedSSID,
-//       pwd: pwd,
-//       host_name: dhcpname,
-//     }),
-//     error: handleExceptionResponse,
-//   });
-
-//   // now we can re-set the intervals regardless of result
-//   startCheckStatusInterval();
-// }
 
 function rssiToIcon(rssi) {
   if (rssi >= -55) {
@@ -1501,7 +1133,7 @@ function getBTSinkOpt(name){
   return $(`${btSinkNamesOptSel} option:contains('${name}')`);
 }
 function getMessages() {
-  $.getJSON('/messages.json?1', async function(data) {
+  $.getJSON('/messages.json', async function(data) {
     for (const msg of data) {
       const msgAge = msg.current_time - msg.sent_time;
       var msgTime = new Date();
@@ -1510,10 +1142,9 @@ function getMessages() {
         case 'MESSAGING_CLASS_OTA':
           var otaData = JSON.parse(msg.message);
           handle_flash_state({
-            ota_pct: (otaData.ota_pct ?? 0),
+            ota_pct: (otaData.ota_pct ?? -1),
             ota_dsc: (otaData.ota_dsc ??''),
-            type: msg.type,
-            event: flash_events.MESSAGES
+            event: flash_events.PROCESS_OTA
           });
           break;
         case 'MESSAGING_CLASS_STATS':
@@ -1753,10 +1384,17 @@ function checkStatus() {
     handleRecoveryMode(data);
     handleWifiStatus(data);
     handlebtstate(data);
-    handle_flash_state(data);
+    handle_flash_state({
+      ota_pct: (data.ota_pct ?? -1),
+      ota_dsc: (data.ota_dsc ??''),
+      event: flash_events.PROCESS_OTA_STATUS
+    });
     if (data.project_name && data.project_name !== '') {
       project_name = data.project_name;
     }
+    if(data.platform_name && data.platform_name!==''){
+      platform_name = data.platform_name;
+    }
     if (data.version && data.version !== '') {
       versionName=data.version;
       $("#navtitle").html(`${project_name}${recovery?'<br>[recovery]':''}`);
@@ -1771,10 +1409,13 @@ function checkStatus() {
       $('#battery').hide();
     }
 
-    if (typeof lmsBaseUrl == "undefined" && data.lms_ip && data.lms_port) {
+    if (typeof lmsBaseUrl == "undefined" || data.lms_ip != prevLMSIP && data.lms_ip && data.lms_port) {
       const baseUrl = 'http://' + data.lms_ip + ':' + data.lms_port;
+      prevLMSIP=data.lms_ip;
       $.ajax({
         url: baseUrl + '/plugins/SqueezeESP32/firmware/-99', 
+        dataType: 'text',
+        cache: false,
         error: function() {
           // define the value, so we don't check it any more.
           lmsBaseUrl = '';

+ 1 - 0
components/wifi-manager/webapp/src/test.ejs

@@ -17,6 +17,7 @@
                         <% } %>
     </div>
     <div id="allIcons"></div>
+    
     <div class="card border-primary mb-3">
         <div class="card-header">Status Variables</div>
         <div class="card-body">

+ 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.0b6890.bundle.js.gz BINARY)
-target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.0b6890.bundle.js.gz BINARY)
-target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.0b6890.bundle.js.gz BINARY)
+target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/index.5b6fcc.bundle.js.gz BINARY)
+target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/node-modules.5b6fcc.bundle.js.gz BINARY)
+target_add_binary_data( __idf_wifi-manager ./webapp/webpack/dist/js/runtime.5b6fcc.bundle.js.gz BINARY)

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

@@ -4,58 +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");
-<<<<<<< HEAD
-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");
+extern const uint8_t _index_5b6fcc_bundle_js_gz_start[] asm("_binary_index_5b6fcc_bundle_js_gz_start");
+extern const uint8_t _index_5b6fcc_bundle_js_gz_end[] asm("_binary_index_5b6fcc_bundle_js_gz_end");
+extern const uint8_t _node_modules_5b6fcc_bundle_js_gz_start[] asm("_binary_node_modules_5b6fcc_bundle_js_gz_start");
+extern const uint8_t _node_modules_5b6fcc_bundle_js_gz_end[] asm("_binary_node_modules_5b6fcc_bundle_js_gz_end");
+extern const uint8_t _runtime_5b6fcc_bundle_js_gz_start[] asm("_binary_runtime_5b6fcc_bundle_js_gz_start");
+extern const uint8_t _runtime_5b6fcc_bundle_js_gz_end[] asm("_binary_runtime_5b6fcc_bundle_js_gz_end");
 const char * resource_lookups[] = {
 	"/dist/favicon-32x32.png",
 	"/dist/index.html.gz",
-	"/js/index.31a52e.bundle.js.gz",
-	"/js/node-modules.31a52e.bundle.js.gz",
-	"/js/runtime.31a52e.bundle.js.gz",
-=======
-extern const uint8_t _index_0b6890_bundle_js_gz_start[] asm("_binary_index_0b6890_bundle_js_gz_start");
-extern const uint8_t _index_0b6890_bundle_js_gz_end[] asm("_binary_index_0b6890_bundle_js_gz_end");
-extern const uint8_t _node_modules_0b6890_bundle_js_gz_start[] asm("_binary_node_modules_0b6890_bundle_js_gz_start");
-extern const uint8_t _node_modules_0b6890_bundle_js_gz_end[] asm("_binary_node_modules_0b6890_bundle_js_gz_end");
-extern const uint8_t _runtime_0b6890_bundle_js_gz_start[] asm("_binary_runtime_0b6890_bundle_js_gz_start");
-extern const uint8_t _runtime_0b6890_bundle_js_gz_end[] asm("_binary_runtime_0b6890_bundle_js_gz_end");
-const char * resource_lookups[] = {
-	"/dist/favicon-32x32.png",
-	"/dist/index.html.gz",
-	"/js/index.0b6890.bundle.js.gz",
-	"/js/node-modules.0b6890.bundle.js.gz",
-	"/js/runtime.0b6890.bundle.js.gz",
->>>>>>> master-cmake
+	"/js/index.5b6fcc.bundle.js.gz",
+	"/js/node-modules.5b6fcc.bundle.js.gz",
+	"/js/runtime.5b6fcc.bundle.js.gz",
 ""
 };
 const uint8_t * resource_map_start[] = {
 	_favicon_32x32_png_start,
 	_index_html_gz_start,
-<<<<<<< HEAD
-	_index_31a52e_bundle_js_gz_start,
-	_node_modules_31a52e_bundle_js_gz_start,
-	_runtime_31a52e_bundle_js_gz_start
-=======
-	_index_0b6890_bundle_js_gz_start,
-	_node_modules_0b6890_bundle_js_gz_start,
-	_runtime_0b6890_bundle_js_gz_start
->>>>>>> master-cmake
+	_index_5b6fcc_bundle_js_gz_start,
+	_node_modules_5b6fcc_bundle_js_gz_start,
+	_runtime_5b6fcc_bundle_js_gz_start
 };
 const uint8_t * resource_map_end[] = {
 	_favicon_32x32_png_end,
 	_index_html_gz_end,
-<<<<<<< HEAD
-	_index_31a52e_bundle_js_gz_end,
-	_node_modules_31a52e_bundle_js_gz_end,
-	_runtime_31a52e_bundle_js_gz_end
-=======
-	_index_0b6890_bundle_js_gz_end,
-	_node_modules_0b6890_bundle_js_gz_end,
-	_runtime_0b6890_bundle_js_gz_end
->>>>>>> master-cmake
+	_index_5b6fcc_bundle_js_gz_end,
+	_node_modules_5b6fcc_bundle_js_gz_end,
+	_runtime_5b6fcc_bundle_js_gz_end
 };

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

@@ -1,27 +1,26 @@
 /***********************************
 webpack_headers
-<<<<<<< HEAD
-Hash: 31a52ecfe661f5a02717
+Hash: 5b6fcca7137c495bebc9
 Version: webpack 4.44.2
-Time: 6575ms
-Built at: 2021-03-23 17 h 59 min 55 s
+Time: 8665ms
+Built at: 2021-04-10 09 h 58 min 36 s
                                 Asset       Size  Chunks                                Chunk Names
-          ./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]                     
+          ./js/index.5b6fcc.bundle.js    229 KiB       0  [emitted] [immutable]         index
+       ./js/index.5b6fcc.bundle.js.br   31.3 KiB          [emitted]                     
+       ./js/index.5b6fcc.bundle.js.gz   40.6 KiB          [emitted]                     
+   ./js/node-modules.5b6fcc.bundle.js    265 KiB       1  [emitted] [immutable]  [big]  node-modules
+./js/node-modules.5b6fcc.bundle.js.br   76.2 KiB          [emitted]                     
+./js/node-modules.5b6fcc.bundle.js.gz   88.6 KiB          [emitted]                     
+        ./js/runtime.5b6fcc.bundle.js   1.46 KiB       2  [emitted] [immutable]         runtime
+     ./js/runtime.5b6fcc.bundle.js.br  644 bytes          [emitted]                     
+     ./js/runtime.5b6fcc.bundle.js.gz  722 bytes          [emitted]                     
                     favicon-32x32.png  578 bytes          [emitted]                     
-                           index.html   21.5 KiB          [emitted]                     
-                        index.html.br   4.72 KiB          [emitted]                     
-                        index.html.gz   5.73 KiB          [emitted]                     
+                           index.html   21.7 KiB          [emitted]                     
+                        index.html.br   4.78 KiB          [emitted]                     
+                        index.html.gz   5.78 KiB          [emitted]                     
                            sprite.svg    4.4 KiB          [emitted]                     
                         sprite.svg.br  912 bytes          [emitted]                     
-Entrypoint index [big] = ./js/runtime.31a52e.bundle.js ./js/node-modules.31a52e.bundle.js ./js/index.31a52e.bundle.js
+Entrypoint index [big] = ./js/runtime.5b6fcc.bundle.js ./js/node-modules.5b6fcc.bundle.js ./js/index.5b6fcc.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]
@@ -36,73 +35,22 @@ Entrypoint index [big] = ./js/runtime.31a52e.bundle.js ./js/node-modules.31a52e.
 [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 59.9 KiB {0} [built]
+[37] ./src/index.ts + 1 modules 58.4 KiB {0} [built]
      | ./src/index.ts 1.36 KiB [built]
-     | ./src/js/custom.js 58.4 KiB [built]
-=======
-Hash: 0b6890f4337e767921f7
-Version: webpack 4.46.0
-Time: 273269ms
-Built at: 2021-04-03 1:28:56
-                                Asset       Size  Chunks                                Chunk Names
-          ./js/index.0b6890.bundle.js    231 KiB       0  [emitted] [immutable]         index
-       ./js/index.0b6890.bundle.js.br   31.5 KiB          [emitted]                     
-       ./js/index.0b6890.bundle.js.gz   41.1 KiB          [emitted]                     
-   ./js/node-modules.0b6890.bundle.js    266 KiB       1  [emitted] [immutable]  [big]  node-modules
-./js/node-modules.0b6890.bundle.js.br   76.3 KiB          [emitted]                     
-./js/node-modules.0b6890.bundle.js.gz   88.7 KiB          [emitted]                     
-        ./js/runtime.0b6890.bundle.js   1.46 KiB       2  [emitted] [immutable]         runtime
-     ./js/runtime.0b6890.bundle.js.br  644 bytes          [emitted]                     
-     ./js/runtime.0b6890.bundle.js.gz  722 bytes          [emitted]                     
-                    favicon-32x32.png  634 bytes          [emitted]                     
-                           index.html   19.5 KiB          [emitted]                     
-                        index.html.br   4.48 KiB          [emitted]                     
-                        index.html.gz   5.46 KiB          [emitted]                     
-                           sprite.svg    4.4 KiB          [emitted]                     
-                        sprite.svg.br  912 bytes          [emitted]                     
-Entrypoint index [big] = ./js/runtime.0b6890.bundle.js ./js/node-modules.0b6890.bundle.js ./js/index.0b6890.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 323 bytes {1} [built]
-[17] ./node_modules/remixicon/icons/Device/signal-wifi-3-fill.svg 327 bytes {1} [built]
-[18] ./node_modules/remixicon/icons/Device/signal-wifi-2-fill.svg 327 bytes {1} [built]
-[19] ./node_modules/remixicon/icons/Device/signal-wifi-1-fill.svg 327 bytes {1} [built]
-[20] ./node_modules/remixicon/icons/Device/signal-wifi-line.svg 323 bytes {1} [built]
-[21] ./node_modules/remixicon/icons/Device/battery-line.svg 315 bytes {1} [built]
-[22] ./node_modules/remixicon/icons/Device/battery-low-line.svg 323 bytes {1} [built]
-[23] ./node_modules/remixicon/icons/Device/battery-fill.svg 315 bytes {1} [built]
-[24] ./node_modules/remixicon/icons/Media/headphone-fill.svg 318 bytes {1} [built]
-[25] ./node_modules/remixicon/icons/Device/device-recover-fill.svg 329 bytes {1} [built]
-[26] ./node_modules/remixicon/icons/Device/bluetooth-fill.svg 319 bytes {1} [built]
-[27] ./node_modules/remixicon/icons/Device/bluetooth-connect-fill.svg 335 bytes {1} [built]
-[37] ./src/index.ts + 1 modules 53.3 KiB {0} [built]
-     | ./src/index.ts 1.36 KiB [built]
-     | ./src/js/custom.js 51.8 KiB [built]
->>>>>>> master-cmake
+     | ./src/js/custom.js 57 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: 
-<<<<<<< HEAD
-  ./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 (494 KiB)
-      ./js/runtime.31a52e.bundle.js
-      ./js/node-modules.31a52e.bundle.js
-      ./js/index.31a52e.bundle.js
-=======
-  ./js/node-modules.0b6890.bundle.js (266 KiB)
+  ./js/node-modules.5b6fcc.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 (499 KiB)
-      ./js/runtime.0b6890.bundle.js
-      ./js/node-modules.0b6890.bundle.js
-      ./js/index.0b6890.bundle.js
->>>>>>> master-cmake
+  index (496 KiB)
+      ./js/runtime.5b6fcc.bundle.js
+      ./js/node-modules.5b6fcc.bundle.js
+      ./js/index.5b6fcc.bundle.js
 
 
 WARNING in webpack performance recommendations: 
@@ -110,15 +58,10 @@ 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  558 KiB       0  
+    index.html  559 KiB       0  
     Entrypoint undefined = index.html
-<<<<<<< HEAD
-    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 23.7 KiB {0} [built]
+    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 23.9 KiB {0} [built]
     [1] ./node_modules/lodash/lodash.js 530 KiB {0} [built]
-=======
-    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs 20.3 KiB {0} [built]
-    [1] ./node_modules/lodash/lodash.js 531 KiB {0} [built]
->>>>>>> master-cmake
     [2] (webpack)/buildin/global.js 472 bytes {0} [built]
     [3] (webpack)/buildin/module.js 497 bytes {0} [built]
 ***********************************/

二进制
components/wifi-manager/webapp/webpack/dist/favicon-32x32.png


文件差异内容过多而无法显示
+ 0 - 0
components/wifi-manager/webapp/webpack/dist/index.html


二进制
components/wifi-manager/webapp/webpack/dist/index.html.br


二进制
components/wifi-manager/webapp/webpack/dist/index.html.gz


文件差异内容过多而无法显示
+ 0 - 0
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js


二进制
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.br


二进制
components/wifi-manager/webapp/webpack/dist/js/index.0b6890.bundle.js.gz


文件差异内容过多而无法显示
+ 0 - 7
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js


二进制
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.br


二进制
components/wifi-manager/webapp/webpack/dist/js/node-modules.0b6890.bundle.js.gz


+ 0 - 1
components/wifi-manager/webapp/webpack/dist/js/runtime.0b6890.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()}([]);

二进制
components/wifi-manager/webapp/webpack/dist/js/runtime.0b6890.bundle.js.br


二进制
components/wifi-manager/webapp/webpack/dist/js/runtime.0b6890.bundle.js.gz


+ 23 - 4
components/wifi-manager/webapp/webpack/webpack.dev.js

@@ -15,6 +15,7 @@ const data = {
     messages: require("../mock/messages.json"),
     messagequeue: require("../mock/messages.json"),
     message_queue_sequence: [],
+    message_queue_sequence_post_empty: null,
     commands: require("../mock/commands.json"),
     scan: require("../mock/scan.json"),
     ap: require("../mock/ap.json"),
@@ -124,10 +125,20 @@ module.exports = merge(common, {
             app.get('/scan.json', function(req, res) { res.json( data.scan ); });
             app.get('/config.json', function(req, res) { res.json( data.config ); });
             app.get('/status.json', function(req, res) { res.json( data.status ); });
+            app.get('/plugins/SqueezeESP32/firmware/-99', function(req, res) { 
+                let has_proxy=  data.status.mock_plugin_has_proxy ?? 'n';
+                const statusCode='xy'.includes((has_proxy).toLowerCase())?200:500;
+                console.log(`Checking if plugin has proxy enabled with option mock_plugin_has_proxy = ${data.status.mock_plugin_has_proxy}. Returning status ${statusCode} `);
+                res.status(statusCode ).json(); 
+            });
             app.get('/messages.json', function(req, res) { 
                 if(data.message_queue_sequence.length>0){
                     data.messagequeue.push(data.message_queue_sequence.shift());
                 }
+                else if (data.message_queue_sequence_post_empty){
+                    data.message_queue_sequence_post_empty();
+                    data.message_queue_sequence_post_empty = null;
+                }
                 res.json( data.messagequeue ) ; 
                 data.messagequeue=[];
             });
@@ -157,7 +168,7 @@ module.exports = merge(common, {
             });
             app.post('/config.json', function(req, res) { 
                 var fwurl='';
-                console.log(req.body);
+                console.log(`Processing config.json with request body: ${req.body}`);
                 console.log(data.config);
                 for (const property in req.body.config) {
                     console.log(`${property}: ${req.body.config[property].value}`);
@@ -177,16 +188,24 @@ module.exports = merge(common, {
 
                   }
                 res.json( {} ); 
-                if(fwurl!==''){
-                    data.status.recovery=1;
-                    requeueMessages();
+                if(fwurl!=='' ){
+                    if(data.status.recovery!=1) {
+                        // we're not yet in recovery. Simulate reboot to recovery 
+                        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);
+                        data.message_queue_sequence_post_empty = function(){
+                            data.status.recovery=0;
+                            requeueMessages();
+                        }                        
                     }
                 }
             });

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

@@ -69,6 +69,7 @@ Contains the freeRTOS task and all necessary support
 #include "monitor.h"
 #include "globdefs.h"
 
+
 #ifndef CONFIG_SQUEEZELITE_ESP32_RELEASE_URL
 #pragma message "Defaulting release url"
 #define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
@@ -91,11 +92,13 @@ char *ip_info_json = NULL;
 char * release_url=NULL;
 cJSON * ip_info_cjson=NULL;
 wifi_config_t* wifi_manager_config_sta = NULL;
-
-
+static void	(*chained_notify)(in_addr_t, u16_t, u16_t);	
 static int32_t total_connected_time=0;
 static int64_t last_connected=0;
 static uint16_t num_disconnect=0;
+static char lms_server_ip[IP4ADDR_STRLEN_MAX]={0};
+static uint16_t lms_server_port=0;
+static uint16_t lms_server_cport=0;
 
 void (**cb_ptr_arr)(void*) = NULL;
 
@@ -297,6 +300,22 @@ void wifi_manager_init_wifi(){
     taskYIELD();
     ESP_LOGD(TAG,   "Initializing wifi. done");
 }
+
+void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport){
+	strncpy(lms_server_ip,inet_ntoa(ip),sizeof(lms_server_ip));
+	ESP_LOGI(TAG,"LMS IP: %s, hport: %d, cport: %d",lms_server_ip, hport, cport);
+	lms_server_port = hport;
+	lms_server_cport = cport;
+
+}
+
+static void connect_notify(in_addr_t ip, u16_t hport, u16_t cport) {
+	set_lms_server_details(ip,hport,cport);
+	if (chained_notify) (*chained_notify)(ip, hport, cport);
+	wifi_manager_update_status();
+}
+
+
 void wifi_manager_start(){
 
 
@@ -338,7 +357,8 @@ void wifi_manager_start(){
 	else {
 		ESP_LOGD(TAG,   "Found release url %s", release_url);
 	}
-
+	chained_notify = server_notify;
+	server_notify = connect_notify;
 	ESP_LOGD(TAG,   "About to call init wifi");
 	wifi_manager_init_wifi();
 
@@ -495,6 +515,35 @@ void wifi_manager_update_basic_info(){
 		if(avg_conn_time){
 			cJSON_SetNumberValue(avg_conn_time,	num_disconnect>0?(total_connected_time/num_disconnect):0);
 		}	
+		if(lms_server_cport>0){
+			cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_cport");
+			if(value){
+				cJSON_SetNumberValue(value,lms_server_cport);
+			}			
+			else {
+				cJSON_AddNumberToObject(ip_info_cjson,"lms_cport",lms_server_cport);
+			}
+		}
+
+		if(lms_server_port>0){
+			cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_port");
+			if(value){
+				cJSON_SetNumberValue(value,lms_server_port);
+			}			
+			else {
+				cJSON_AddNumberToObject(ip_info_cjson,"lms_port",lms_server_port);
+			}
+		}
+
+
+		if(strlen(lms_server_ip) >0){
+			cJSON * value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_ip");
+			if(!value){
+				// only create if it does not exist. Since we're creating a reference 
+				// to a char buffer, updates to cJSON aren't needed
+				cJSON_AddItemToObject(ip_info_cjson, "lms_ip", cJSON_CreateStringReference(lms_server_ip));
+			}			
+		}		
 		wifi_manager_unlock_json_buffer();
 	}
 }
@@ -504,6 +553,9 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){
 	ESP_LOGV(TAG,  "wifi_manager_get_basic_info called");
 	cJSON *root = wifi_manager_get_new_json(old);
 	cJSON_AddItemToObject(root, "project_name", cJSON_CreateString(desc->project_name));
+	#ifdef CONFIG_FW_PLATFORM_NAME
+		cJSON_AddItemToObject(root, "platform_name", cJSON_CreateString(CONFIG_FW_PLATFORM_NAME));
+	#endif
 	cJSON_AddItemToObject(root, "version", cJSON_CreateString(desc->version));
 	if(release_url !=NULL) cJSON_AddItemToObject(root, "release_url", cJSON_CreateString(release_url));
 	cJSON_AddNumberToObject(root,"recovery",	is_recovery_running?1:0);
@@ -518,6 +570,7 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){
 #else
 	cJSON_AddFalseToObject(root, "is_i2c_locked");
 #endif
+
 	ESP_LOGV(TAG,  "wifi_manager_get_basic_info done");
 	return root;
 }

+ 7 - 0
main/Kconfig.projbuild

@@ -79,6 +79,13 @@ menu "Squeezelite-ESP32"
 			default "DAC32" if DAC32
 			default "Squeezelite-TWATCH" if TWATCH2020
 			default "Squeezelite-ESP32" if !A1S && !SQUEEZEAMP && !DAC32 && !TWATCH2020
+		config FW_PLATFORM_NAME
+			string "Hardware Platform Name"
+			default "SqueezeAmp" if SQUEEZEAMP
+			default "DAC32" if DAC32
+			default "ESP32-A1S" if A1S
+			default "TWATCH" if TWATCH2020
+			default "I2S-4MFlash" if !A1S && !SQUEEZEAMP && !DAC32 && !TWATCH2020
 		# AGGREGATES - begin
 		# these parameters are "aggregates"	that take precedence. The must have a default value	
 		config DAC_CONFIG

+ 8 - 1
main/esp_app_main.c

@@ -85,11 +85,18 @@ void cb_connection_got_ip(void *pvParameter){
 		esp_restart();
 	}
 	ip.addr = ipInfo.ip.addr;
-	ESP_LOGI(TAG, "I have a connection!");
+	ESP_LOGI(TAG, "Wifi connected!");
 	messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"Wifi connected");
 	xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
 	bWifiConnected=true;
 	led_unpush(LED_GREEN);
+		if(is_recovery_running){
+		// when running in recovery, send a LMS discovery message 
+		// to find a running instance. This is to enable using 
+		// the plugin's proxy mode for FW download and avoid
+		// expired certificate issues.
+		discover_ota_server(5);
+	}
 }
 void cb_connection_sta_disconnected(void *pvParameter){
 	led_blink_pushed(LED_GREEN, 250, 250);

+ 7 - 6
sdkconfig

@@ -75,16 +75,18 @@ CONFIG_LOGGING_SLIMPROTO="info"
 CONFIG_LOGGING_STREAM="info"
 CONFIG_LOGGING_DECODE="info"
 CONFIG_LOGGING_OUTPUT="info"
+CONFIG_I2C_LOCKED=y
 CONFIG_MUTE_GPIO_LEVEL=0
 # CONFIG_SQUEEZEAMP is not set
-# CONFIG_A1S is not set
+CONFIG_A1S=y
 # CONFIG_DAC32 is not set
 # CONFIG_TWATCH2020 is not set
-CONFIG_BASIC_I2C_BT=y
+# CONFIG_BASIC_I2C_BT is not set
 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_PROJECT_NAME="Squeezelite ESP32-A1S"
+CONFIG_FW_PLATFORM_NAME="ESP32-A1S"
+CONFIG_DAC_CONFIG="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32"
 CONFIG_SPDIF_CONFIG=""
 CONFIG_SPI_CONFIG=""
 CONFIG_DISPLAY_CONFIG=""
@@ -93,7 +95,6 @@ CONFIG_I2S_NUM=0
 CONFIG_I2S_BCK_IO=-1
 CONFIG_I2S_WS_IO=-1
 CONFIG_I2S_DO_IO=-1
-CONFIG_I2S_DI_IO=-1
 CONFIG_I2C_SDA=-1
 CONFIG_I2C_SCL=-1
 CONFIG_MUTE_GPIO=-1
@@ -616,7 +617,7 @@ CONFIG_LOG_DEFAULT_LEVEL_INFO=y
 # CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
 CONFIG_LOG_DEFAULT_LEVEL=3
 CONFIG_LOG_COLORS=y
-CONFIG_LWIP_LOCAL_HOSTNAME="squeezelite-esp32"
+CONFIG_LWIP_LOCAL_HOSTNAME="esp32a1s"
 # CONFIG_LWIP_L2_TO_L3_COPY is not set
 # CONFIG_LWIP_IRAM_OPTIMIZATION is not set
 CONFIG_LWIP_TIMERS_ONDEMAND=y

部分文件因为文件数量过多而无法显示