diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 245cc5edb..98378f368 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,7 @@ -/* 6.4.1.19 20190222 +/* 6.4.1.20 20190304 + * Changed webserver content handling from single String to small Chunks increasing RAM + * + * 6.4.1.19 20190222 * Add command SetOption37 for RGBCW color mapping (#5326) * Add Korean language translations (#5344) * Fix Energy TotalStartTime when commands EnergyReset0 and/or EnergyReset3 used (#5373) diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index d4bfa230b..6dc3c6f38 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x06040113 +#define VERSION 0x06040114 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support.ino b/sonoff/support.ino index 8b3cbe58a..67f53d451 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -1279,6 +1279,17 @@ void AddLog_P(uint8_t loglevel, const char *formatP, const char *formatP2) AddLog(loglevel); } +void AddLog_P2(uint8_t loglevel, PGM_P formatP, ...) +{ + // This uses char strings. Be aware of sending %% if % is needed + va_list arg; + va_start(arg, formatP); + int len = vsnprintf_P(log_data, sizeof(log_data), formatP, arg); + va_end(arg); + + AddLog(loglevel); +} + void AddLogBuffer(uint8_t loglevel, uint8_t *buffer, int count) { snprintf_P(log_data, sizeof(log_data), PSTR("DMP:")); diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index cbd52ccee..8df9529b4 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -27,6 +27,8 @@ #define XDRV_01 1 +#define CHUNKED_BUFFER_SIZE 400 // Chunk buffer size + #ifndef WIFI_SOFT_AP_CHANNEL #define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by SmartConfig web GUI #endif @@ -49,7 +51,7 @@ const char HTTP_HEAD[] PROGMEM = "" "" "" - "{h} - {v}" + "%s - %s" ""; + "window.onload=u;"; const char HTTP_SCRIPT_ROOT[] PROGMEM = "function la(p){" @@ -76,17 +77,17 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "a=p;" "clearTimeout(lt);" "}" - "if(x!=null){x.abort();}" // Abort if no response within Settings.web_refresh milliseconds (happens on restart 1) + "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) "x=new XMLHttpRequest();" "x.onreadystatechange=function(){" "if(x.readyState==4&&x.status==200){" - "var s=x.responseText.replace(/{t}/g,\"\").replace(/{s}/g,\"\").replace(/{c}/g,\"%'>
\").replace(/{s}/g,\"
\").replace(/{c}/g,\"%%'>
hasArg("m") "x.send();" - "lt=setTimeout(la,{a});" // Settings.web_refresh + "lt=setTimeout(la,%d);" // Settings.web_refresh "}" "function lb(p){" "la('&d='+p);" // &d related to WebGetArg("d", tmp, sizeof(tmp)); @@ -129,7 +130,7 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "x.onreadystatechange=function(){" "if(x.readyState==4&&x.status==200){" "var z,d;" - "d=x.responseText.split(/\1/);" // Field separator + "d=x.responseText.split(/}1/);" // Field separator "id=d.shift();" "if(d.shift()==0){t.value='';}" "z=d.shift();" @@ -141,18 +142,18 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "x.open('GET','cs?c2='+id+o,true);" // Related to WebServer->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp)) "x.send();" "}" - "lt=setTimeout(l,{a});" + "lt=setTimeout(l,%d);" "return false;" "}" "window.onload=l;"; const char HTTP_MODULE_TEMPLATE_REPLACE[] PROGMEM = - "\2%d'>%s (%d\3"; // \2 and \3 are used in below os.replace + "}2%d'>%s (%d}3"; // }2 and }3 are used in below os.replace const char HTTP_SCRIPT_MODULE_TEMPLATE[] PROGMEM = "var os;" "function sk(s,g){" // s = value, g = id and name - "var o=os.replace(/\2/g,\"
\").replace(/{m}/g,\"\").replace(/{e}/g,\"
\").replace(/{m}/g,\"\").replace(/{e}/g,\"
\").replace(/}2/g,\"\");" "eb('i').innerHTML=s;" "}" - "window.onload=i;" - ""; + "window.onload=i;"; -const char HTTP_HEAD_STYLE[] PROGMEM = +const char HTTP_HEAD_STYLE1[] PROGMEM = "" "" "" @@ -266,11 +268,12 @@ const char HTTP_HEAD_STYLE[] PROGMEM = #endif "
" #ifdef LANGUAGE_MODULE_NAME - "

" D_MODULE " {ha

" + "

" D_MODULE " %s

" #else - "

{ha " D_MODULE "

" + "

%s " D_MODULE "

" #endif - "

{h}

{j}
"; + "

%s

%s"; + const char HTTP_MSG_SLIDER1[] PROGMEM = "
" D_COLDLIGHT "" D_WARMLIGHT "
" "
"; @@ -280,10 +283,11 @@ const char HTTP_MSG_SLIDER2[] PROGMEM = const char HTTP_MSG_RSTRT[] PROGMEM = "
" D_DEVICE_WILL_RESTART "

"; -const char HTTP_BTN_MENU1[] PROGMEM = +const char HTTP_BTN_CONF[] PROGMEM = "
" + "
"; +const char HTTP_BTN_MENU1[] PROGMEM = #ifndef FIRMWARE_MINIMAL - "
" "

" #endif "
" @@ -294,30 +298,30 @@ const char HTTP_BTN_RSTRT[] PROGMEM = const char HTTP_BTN_MENU_MODULE[] PROGMEM = "

" "

"; -const char HTTP_BTN_RESET[] PROGMEM = - "
" - "
"; const char HTTP_BTN_MENU4[] PROGMEM = "

" "

" "

"; + +const char HTTP_BTN_RESET[] PROGMEM = + "
" + "
"; const char HTTP_BTN_MENU5[] PROGMEM = "

" "

"; + const char HTTP_BTN_MAIN[] PROGMEM = "
" "
"; const char HTTP_FORM_LOGIN[] PROGMEM = + "
" "
" - "
" D_USER "

" - "
" D_PASSWORD "

" + "

" D_USER "

" + "

" D_PASSWORD "

" "
" - "
"; - -const char HTTP_BTN_CONF[] PROGMEM = - "
" - "
"; + "" + "
"; const char HTTP_FORM_TEMPLATE[] PROGMEM = "
 " D_TEMPLATE_PARAMETERS " " @@ -333,61 +337,39 @@ const char HTTP_FORM_TEMPLATE_FLAG[] PROGMEM = const char HTTP_FORM_MODULE[] PROGMEM = "
 " D_MODULE_PARAMETERS " " "
" - "

" D_MODULE_TYPE " ({mt)

"; + "

" D_MODULE_TYPE " (%s)

" + "
"; -const char HTTP_LNK_ITEM[] PROGMEM = - "
{v} ({w}) {i} {r}%
"; -const char HTTP_LNK_SCAN[] PROGMEM = - "
"; const char HTTP_FORM_WIFI[] PROGMEM = "
 " D_WIFI_PARAMETERS " " "" - "

" D_AP1_SSID " (" STA_SSID1 ")

" + "

" D_AP1_SSID " (" STA_SSID1 ")

" "

" D_AP1_PASSWORD "

" - "

" D_AP2_SSID " (" STA_SSID2 ")

" + "

" D_AP2_SSID " (" STA_SSID2 ")

" "

" D_AP2_PASSWORD "

" - "

" D_HOSTNAME " (" WIFI_HOSTNAME ")

"; + "

" D_HOSTNAME " (%s)

"; const char HTTP_FORM_LOG1[] PROGMEM = "
 " D_LOGGING_PARAMETERS " " ""; const char HTTP_FORM_LOG2[] PROGMEM = - "

{b0 ({b1)

"; -const char HTTP_FORM_LOG3[] PROGMEM = - "

" D_SYSLOG_HOST " (" SYS_LOG_HOST ")

" - "

" D_SYSLOG_PORT " (" STR(SYS_LOG_PORT) ")

" - "

" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; + "

" D_SYSLOG_HOST " (" SYS_LOG_HOST ")

" + "

" D_SYSLOG_PORT " (" STR(SYS_LOG_PORT) ")

" + "

" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; const char HTTP_FORM_OTHER[] PROGMEM = "
 " D_OTHER_PARAMETERS " " "" "

" "
 " D_TEMPLATE " " - "

" - "

" D_ACTIVATE "

" + "

" + "

" D_ACTIVATE "

" "
" "
" "" D_WEB_ADMIN_PASSWORD "

" "
" - "" D_MQTT_ENABLE "
" + "" D_MQTT_ENABLE "
" "
"; - const char HTTP_FORM_OTHER2[] PROGMEM = - "" D_FRIENDLY_NAME " {1 ({2)

"; -#ifdef USE_EMULATION -const char HTTP_FORM_OTHER3a[] PROGMEM = - "

" // Keep close to Friendlynames so do not use
- "
 " D_EMULATION " 

"; -const char HTTP_FORM_OTHER3b[] PROGMEM = - "{3{4
"; // Different id only used for labels -const char HTTP_FORM_OTHER3c[] PROGMEM = - "

"; -#endif // USE_EMULATION const char HTTP_FORM_END[] PROGMEM = "
" @@ -401,30 +383,34 @@ const char HTTP_FORM_UPG[] PROGMEM = "
" "
 " D_UPGRADE_BY_WEBSERVER " " "" - "
" D_OTA_URL "

" + "
" D_OTA_URL "

" "
" "


" "
 " D_UPGRADE_BY_FILE_UPLOAD " "; const char HTTP_FORM_RST_UPG[] PROGMEM = "
" "

" - "
" + "
" "
" "
" ""; + const char HTTP_FORM_CMND[] PROGMEM = "


" "
" "
" // "
" ""; + const char HTTP_TABLE100[] PROGMEM = "
"; + const char HTTP_COUNTER[] PROGMEM = "
"; + const char HTTP_END[] PROGMEM = "
" - "" + "" "" "" ""; @@ -435,6 +421,11 @@ const char HTTP_DEVICE_STATE[] PROGMEM = "%s"); + WSContentSend(FPSTR(HTTP_TABLE100)); + WSContentSend(F("")); if (SONOFF_IFAN02 == my_module_type) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 36, 1, D_BUTTON_TOGGLE, ""); - page += mqtt_data; + WSContentSend_P(HTTP_DEVICE_CONTROL, 36, 1, D_BUTTON_TOGGLE, ""); for (uint8_t i = 0; i < MAX_FAN_SPEED; i++) { snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 16, i +2, stemp, ""); - page += mqtt_data; + WSContentSend_P(HTTP_DEVICE_CONTROL, 16, i +2, stemp, ""); } } else { for (uint8_t idx = 1; idx <= devices_present; idx++) { snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, - 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); - page += mqtt_data; + WSContentSend_P(HTTP_DEVICE_CONTROL, 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); } } - page += F("
" D_CONFIGURATION_SAVED "
"); - if (2 == type) { - page += F("
" D_TRYING_TO_CONNECT "
"); - } - page += F(""); - } - else { - page.replace(F("{v}"), FPSTR(S_RESTART)); - } - bool reset_only = (HTTP_MANAGER_RESET_ONLY == webserver_state); - page += FPSTR(HTTP_MSG_RSTRT); + WSContentStart((type) ? FPSTR(S_SAVE_CONFIGURATION) : FPSTR(S_RESTART), !reset_only); + WSContentSend(FPSTR(HTTP_SCRIPT_RELOAD)); + WSContentSendStyle(); + if (type) { + WSContentSend(F("
" D_CONFIGURATION_SAVED "
")); + if (2 == type) { + WSContentSend(F("
" D_TRYING_TO_CONNECT "
")); + } + WSContentSend(F("
")); + } + WSContentSend(FPSTR(HTTP_MSG_RSTRT)); if (HTTP_MANAGER == webserver_state || reset_only) { webserver_state = HTTP_ADMIN; } else { - page += FPSTR(HTTP_BTN_MAIN); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); } - ShowPage(page, !reset_only); + WSContentEnd(); ShowWebSource(SRC_WEBGUI); restart_flag = 2; @@ -692,11 +773,19 @@ void WebRestart(uint8_t type) void HandleWifiLogin(void) { - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR( D_CONFIGURE_WIFI )); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_LOGIN); - ShowPage(page, false); // false means show page no matter if the client has or has not credentials + WSContentStart(FPSTR(D_CONFIGURE_WIFI), false); // false means show page no matter if the client has or has not credentials + WSContentSendStyle(); + WSContentSend(FPSTR(HTTP_FORM_LOGIN)); + + if (WifiIsInManagerMode()) { + WSContentSend(F("
")); + WSContentSend(FPSTR(HTTP_BTN_RSTRT)); +#ifndef FIRMWARE_MINIMAL + WSContentSend(FPSTR(HTTP_BTN_RESET)); +#endif // FIRMWARE_MINIMAL + } + + WSContentEnd(); } void HandleRoot(void) @@ -732,68 +821,63 @@ void HandleRoot(void) char stemp[5]; - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_MAIN_MENU)); - page += FPSTR(HTTP_SCRIPT_ROOT); - page += FPSTR(HTTP_HEAD_STYLE); + WSContentStart(FPSTR(S_MAIN_MENU)); + WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh); + WSContentSendStyle(); - page += F("
"); + WSContentSend(F("
")); if (devices_present) { if (light_type) { if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER1, LightGetColorTemp()); - page += mqtt_data; + WSContentSend_P(HTTP_MSG_SLIDER1, LightGetColorTemp()); } - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER2, Settings.light_dimmer); - page += mqtt_data; + WSContentSend_P(HTTP_MSG_SLIDER2, Settings.light_dimmer); } - page += FPSTR(HTTP_TABLE100); - page += F("
"); + WSContentSend(F("
")); } if (SONOFF_BRIDGE == my_module_type) { - page += FPSTR(HTTP_TABLE100); - page += F(""); + WSContentSend(FPSTR(HTTP_TABLE100)); + WSContentSend(F("")); uint8_t idx = 0; for (uint8_t i = 0; i < 4; i++) { - if (idx > 0) { page += F(""); } + if (idx > 0) { WSContentSend(F("")); } for (uint8_t j = 0; j < 4; j++) { idx++; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), idx, idx); // ?k is related to WebGetArg("k", tmp, sizeof(tmp)); - page += mqtt_data; + WSContentSend_P(PSTR(""), idx, idx); // &k is related to WebGetArg("k", tmp, sizeof(tmp)); } } - page += F(""); + WSContentSend(F("")); } #ifndef FIRMWARE_MINIMAL - mqtt_data[0] = '\0'; XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON); XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON); - page += String(mqtt_data); #endif // Not FIRMWARE_MINIMAL if (HTTP_ADMIN == webserver_state) { - page += FPSTR(HTTP_BTN_MENU1); - page += FPSTR(HTTP_BTN_RSTRT); +#ifndef FIRMWARE_MINIMAL + WSContentSend(FPSTR(HTTP_BTN_CONF)); +#else + WSContentSend(F("
")); +#endif // Not FIRMWARE_MINIMAL + WSContentSend(FPSTR(HTTP_BTN_MENU1)); + WSContentSend(FPSTR(HTTP_BTN_RSTRT)); } - ShowPage(page); + WSContentEnd(); } bool HandleRootStatusRefresh(void) @@ -874,19 +958,6 @@ bool HandleRootStatusRefresh(void) return true; } -bool HttpCheckPriviledgedAccess(bool autorequestauth = true) -{ - if (HTTP_USER == webserver_state) { - HandleRoot(); - return false; - } - if (autorequestauth && !WebAuthenticate()) { - WebServer->requestAuthentication(); - return false; - } - return true; -} - /*-------------------------------------------------------------------------------------------*/ #ifndef FIRMWARE_MINIMAL @@ -897,21 +968,18 @@ void HandleConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURATION); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_BTN_MENU_MODULE); + WSContentStart(FPSTR(S_CONFIGURATION)); + WSContentSendStyle(); + WSContentSend(FPSTR(HTTP_BTN_MENU_MODULE)); - mqtt_data[0] = '\0'; XdrvCall(FUNC_WEB_ADD_BUTTON); XsnsCall(FUNC_WEB_ADD_BUTTON); - page += String(mqtt_data); - page += FPSTR(HTTP_BTN_MENU4); - page += FPSTR(HTTP_BTN_RESET); - page += FPSTR(HTTP_BTN_MENU5); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentSend(FPSTR(HTTP_BTN_MENU4)); + WSContentSend(FPSTR(HTTP_BTN_RESET)); + WSContentSend(FPSTR(HTTP_BTN_MENU5)); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); + WSContentEnd(); } /*-------------------------------------------------------------------------------------------*/ @@ -930,7 +998,7 @@ void HandleTemplateConfiguration(void) if (WebServer->hasArg("m")) { String page = ""; - for (uint8_t i = 0; i < MAXMODULE; i++) { // "\2'%d'>%s (%d)\3" - "\2'0'>Sonoff Basic (1)\3" + for (uint8_t i = 0; i < MAXMODULE; i++) { // "}2'%d'>%s (%d)}3" - "}2'0'>Sonoff Basic (1)}3" uint8_t midx = pgm_read_byte(kModuleNiceList + i); snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, midx, AnyModuleName(midx).c_str(), midx +1); page += mqtt_data; @@ -950,12 +1018,12 @@ void HandleTemplateConfiguration(void) Settings.module = module_save; String page = AnyModuleName(module); // NAME: Generic - page += F("\1"); // Field separator + page += F("}1"); // Field separator - for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { // GPIO: \2'0'>None (0)\3\2'17'>Button1 (17)\3... + for (uint8_t i = 0; i < sizeof(kGpioNiceList); i++) { // GPIO: }2'0'>None (0)}3}2'17'>Button1 (17)}3... if (1 == i) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, 255, D_SENSOR_USER, 255); // \2'255'>User (255)\3 + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MODULE_TEMPLATE_REPLACE, 255, D_SENSOR_USER, 255); // }2'255'>User (255)}3 page += mqtt_data; } @@ -964,14 +1032,14 @@ void HandleTemplateConfiguration(void) page += mqtt_data; } - mqtt_data[0] = '\1'; // Field separator - mqtt_data[1] = '\0'; // Char eot + page += F("}1"); // Field separator + mqtt_data[0] = '\0'; for (uint8_t i = 0; i < sizeof(cmodule); i++) { // 17,148,29,149,7,255,255,255,138,255,139,255,255 if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11 snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", cmodule.io[i]); } } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\1%d\1%d"), mqtt_data, flag, Settings.user_template_base); // FLAG: 1 BASE: 17 + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}1%d}1%d"), mqtt_data, flag, Settings.user_template_base); // FLAG: 1 BASE: 17 page += mqtt_data; WSSend(200, CT_PLAIN, page); @@ -980,25 +1048,25 @@ void HandleTemplateConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TEMPLATE); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_TEMPLATE)); - page += FPSTR(HTTP_SCRIPT_MODULE_TEMPLATE); - page += FPSTR(HTTP_SCRIPT_TEMPLATE); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_TEMPLATE); - page += F("
"); + WSContentStart(FPSTR(S_CONFIGURE_TEMPLATE)); + WSContentSend(FPSTR(HTTP_SCRIPT_MODULE_TEMPLATE)); + WSContentSend(FPSTR(HTTP_SCRIPT_TEMPLATE)); + WSContentSendStyle(); + WSContentSend(FPSTR(HTTP_FORM_TEMPLATE)); + + WSContentSend(F("
")); for (uint8_t i = 0; i < 17; i++) { - if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11 - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("" D_GPIO "%d"), + if ((i < 6) || ((i > 8) && (i != 11))) { // Ignore flash pins GPIO06, 7, 8 and 11 + WSContentSend_P(PSTR("" D_GPIO "%d"), (0==i)?" style='width:74px'":"", i, ((9==i)||(10==i))? "ESP8285" :"", (0==i)?" style='width:176px'":"", i, i); - page += mqtt_data; } } - page += F("
%s
%s
"); - page += FPSTR(HTTP_FORM_TEMPLATE_FLAG); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend(F("")); + + WSContentSend(FPSTR(HTTP_FORM_TEMPLATE_FLAG)); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void TemplateSaveSettings(void) @@ -1054,7 +1122,7 @@ void HandleModuleConfiguration(void) if (WebServer->hasArg("m")) { String page = ""; uint8_t vidx = 0; - for (uint8_t i = 0; i <= MAXMODULE; i++) { // "\2'%d'>%s (%d)\3" - "\2'255'>UserTemplate (0)\3" - "\2'0'>Sonoff Basic (1)\3" + for (uint8_t i = 0; i <= MAXMODULE; i++) { // "}2'%d'>%s (%d)}3" - "}2'255'>UserTemplate (0)}3" - "}2'0'>Sonoff Basic (1)}3" if (0 == i) { midx = USER_MODULE; vidx = 0; @@ -1084,34 +1152,28 @@ void HandleModuleConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE)); - page += FPSTR(HTTP_SCRIPT_MODULE_TEMPLATE); - page += FPSTR(HTTP_SCRIPT_MODULE1); - page.replace(F("}4"), String(Settings.module)); + WSContentStart(FPSTR(S_CONFIGURE_MODULE)); + WSContentSend(FPSTR(HTTP_SCRIPT_MODULE_TEMPLATE)); + WSContentSend_P(HTTP_SCRIPT_MODULE1, Settings.module); for (uint8_t i = 0; i < sizeof(cmodule); i++) { if (ValidGPIO(i, cmodule.io[i])) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("sk(%d,%d);"), my_module.io[i], i); // g0 - g16 - page += mqtt_data; + WSContentSend_P(PSTR("sk(%d,%d);"), my_module.io[i], i); // g0 - g16 } } - page += FPSTR(HTTP_SCRIPT_MODULE2); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_MODULE); - page.replace(F("{mt"), AnyModuleName(MODULE)); - page += F("
"); + WSContentSend(FPSTR(HTTP_SCRIPT_MODULE2)); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_MODULE, AnyModuleName(MODULE).c_str()); for (uint8_t i = 0; i < sizeof(cmodule); i++) { if (ValidGPIO(i, cmodule.io[i])) { snprintf_P(stemp, 3, PINS_WEMOS +i*2); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), + WSContentSend_P(PSTR(""), (WEMOS==my_module_type)?stemp:"", i, (0==i)? D_SENSOR_BUTTON "1":(1==i)? D_SERIAL_OUT :(3==i)? D_SERIAL_IN :((9==i)||(10==i))? "ESP8285" :(12==i)? D_SENSOR_RELAY "1":(13==i)? D_SENSOR_LED "1i":(14==i)? D_SENSOR :"", i, i); - page += mqtt_data; } } - page += F("
%s " D_GPIO "%d %s
%s " D_GPIO "%d %s
"); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend(F("")); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void ModuleSaveSettings(void) @@ -1158,7 +1220,7 @@ String htmlEscape(String s) void HandleWifiConfiguration(void) { - if (!HttpCheckPriviledgedAccess()) { return; } + if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI); @@ -1168,10 +1230,9 @@ void HandleWifiConfiguration(void) return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_WIFI)); - page += FPSTR(HTTP_SCRIPT_WIFI); - page += FPSTR(HTTP_HEAD_STYLE); + WSContentStart(FPSTR(S_CONFIGURE_WIFI), !WifiIsInManagerMode()); + WSContentSend(FPSTR(HTTP_SCRIPT_WIFI)); + WSContentSendStyle(); if (HTTP_MANAGER_RESET_ONLY != webserver_state) { if (WebServer->hasArg("scan")) { @@ -1183,8 +1244,8 @@ void HandleWifiConfiguration(void) if (0 == n) { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, S_NO_NETWORKS_FOUND); - page += FPSTR(S_NO_NETWORKS_FOUND); - page += F(". " D_REFRESH_TO_SCAN_AGAIN "."); + WSContentSend(FPSTR(S_NO_NETWORKS_FOUND)); + WSContentSend(F(". " D_REFRESH_TO_SCAN_AGAIN ".")); } else { //sort networks int indices[n]; @@ -1225,7 +1286,7 @@ void HandleWifiConfiguration(void) int quality = WifiGetRssiAsQuality(WiFi.RSSI(indices[i])); if (minimum_signal_quality == -1 || minimum_signal_quality < quality) { - String item = FPSTR(HTTP_LNK_ITEM); + String item = F("
{v} ({w}) {i} {r}%
"); String rssiQ; rssiQ += quality; item.replace(F("{v}"), htmlEscape(WiFi.SSID(indices[i]))); @@ -1233,35 +1294,34 @@ void HandleWifiConfiguration(void) item.replace(F("{r}"), rssiQ); uint8_t auth = WiFi.encryptionType(indices[i]); item.replace(F("{i}"), (ENC_TYPE_WEP == auth) ? F(D_WEP) : (ENC_TYPE_TKIP == auth) ? F(D_WPA_PSK) : (ENC_TYPE_CCMP == auth) ? F(D_WPA2_PSK) : (ENC_TYPE_AUTO == auth) ? F(D_AUTO) : F("")); - page += item; + WSContentSend(item); delay(0); } else { AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI D_SKIPPING_LOW_QUALITY)); } } - page += "
"; + WSContentSend(F("
")); } } else { - page += FPSTR(HTTP_LNK_SCAN); + WSContentSend(F("
" D_SCAN_FOR_WIFI_NETWORKS "

")); } - page += FPSTR(HTTP_FORM_WIFI); - page.replace(F("{h1"), Settings.hostname); - page.replace(F("{s1"), Settings.sta_ssid[0]); - page.replace(F("{s2"), Settings.sta_ssid[1]); - page += FPSTR(HTTP_FORM_END); + // As WIFI_HOSTNAME may contain %s-%04d it cannot be part of HTTP_FORM_WIFI where it will exception + WSContentSend_P(HTTP_FORM_WIFI, Settings.sta_ssid[0], Settings.sta_ssid[1], WIFI_HOSTNAME, WIFI_HOSTNAME, Settings.hostname); + WSContentSend(FPSTR(HTTP_FORM_END)); } + if (WifiIsInManagerMode()) { - page += FPSTR(HTTP_BTN_RSTRT); + WSContentSend(F("
")); + WSContentSend(FPSTR(HTTP_BTN_RSTRT)); #ifndef FIRMWARE_MINIMAL - page += FPSTR(HTTP_BTN_RESET); -#endif // FIRMWARE_MINIMAL + WSContentSend(FPSTR(HTTP_BTN_RESET)); +#endif // FIRMWARE_MINIMAL } else { - page += FPSTR(HTTP_BTN_CONF); + WSContentSend(FPSTR(HTTP_BTN_CONF)); } -// ShowPage(page); - ShowPage(page, !(WifiIsInManagerMode())); + WSContentEnd(); } void WifiSaveSettings(void) @@ -1300,58 +1360,40 @@ void HandleLoggingConfiguration(void) return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_LOGGING)); - page += FPSTR(HTTP_HEAD_STYLE); - - page += FPSTR(HTTP_FORM_LOG1); + WSContentStart(FPSTR(S_CONFIGURE_LOGGING)); + WSContentSendStyle(); + WSContentSend(FPSTR(HTTP_FORM_LOG1)); + char stemp1[32]; + char stemp2[32]; + uint8_t dlevel[3] = { LOG_LEVEL_INFO, LOG_LEVEL_INFO, LOG_LEVEL_NONE }; for (uint8_t idx = 0; idx < 3; idx++) { - page += FPSTR(HTTP_FORM_LOG2); - switch (idx) { - case 0: - page.replace(F("{b0"), F(D_SERIAL_LOG_LEVEL)); - page.replace(F("{b1"), STR(SERIAL_LOG_LEVEL)); - page.replace(F("{b2"), F("ls")); - for (uint8_t i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { - page.replace("{a" + String(i), (i == Settings.seriallog_level) ? F(" selected ") : F(" ")); - } - break; - case 1: - page.replace(F("{b0"), F(D_WEB_LOG_LEVEL)); - page.replace(F("{b1"), STR(WEB_LOG_LEVEL)); - page.replace(F("{b2"), F("lw")); - for (uint8_t i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { - page.replace("{a" + String(i), (i == Settings.weblog_level) ? F(" selected ") : F(" ")); - } - break; - case 2: - page.replace(F("{b0"), F(D_SYS_LOG_LEVEL)); - page.replace(F("{b1"), STR(SYS_LOG_LEVEL)); - page.replace(F("{b2"), F("ll")); - for (uint8_t i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { - page.replace("{a" + String(i), (i == Settings.syslog_level) ? F(" selected ") : F(" ")); - } - break; + uint8_t llevel = (0==idx)?Settings.seriallog_level:(1==idx)?Settings.weblog_level:Settings.syslog_level; + WSContentSend_P(PSTR("

%s (%s)

")); } - page += FPSTR(HTTP_FORM_LOG3); - page.replace(F("{l2"), Settings.syslog_host); - page.replace(F("{l3"), String(Settings.syslog_port)); - page.replace(F("{l4"), String(Settings.tele_period)); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend_P(HTTP_FORM_LOG2, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void LoggingSaveSettings(void) { char tmp[sizeof(Settings.syslog_host)]; // Max length is currently 33 - WebGetArg("ls", tmp, sizeof(tmp)); + WebGetArg("l0", tmp, sizeof(tmp)); Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp); - WebGetArg("lw", tmp, sizeof(tmp)); + WebGetArg("l1", tmp, sizeof(tmp)); Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp); - WebGetArg("ll", tmp, sizeof(tmp)); + WebGetArg("l2", tmp, sizeof(tmp)); Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp); syslog_level = Settings.syslog_level; syslog_timer = 0; @@ -1383,42 +1425,41 @@ void HandleOtherConfiguration(void) return; } - char stemp[sizeof(Settings.friendlyname[0])]; // Max length is currently 33 + WSContentStart(FPSTR(S_CONFIGURE_OTHER)); + WSContentSendStyle(); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_OTHER)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_OTHER); TemplateJson(); - page.replace(F("{t1"), mqtt_data); - page.replace(F("{t2"), (USER_MODULE == Settings.module) ? F(" checked disabled") : F("")); - page.replace(F("{r1"), (Settings.flag.mqtt_enabled) ? F(" checked") : F("")); + char stemp[strlen(mqtt_data) +1]; + strlcpy(stemp, mqtt_data, sizeof(stemp)); // Get JSON template + WSContentSend_P(HTTP_FORM_OTHER, stemp, (USER_MODULE == Settings.module) ? " checked disabled" : "", (Settings.flag.mqtt_enabled) ? " checked" : ""); uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : (!devices_present) ? 1 : devices_present; if (SONOFF_IFAN02 == my_module_type) { maxfn = 1; } for (uint8_t i = 0; i < maxfn; i++) { - page += FPSTR(HTTP_FORM_OTHER2); - page.replace(F("{1"), String(i +1)); - snprintf_P(stemp, sizeof(stemp), PSTR(FRIENDLY_NAME"%d"), i +1); - page.replace(F("{2"), (i) ? stemp : FRIENDLY_NAME); - page.replace(F("{3"), Settings.friendlyname[i]); + snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i +1); + WSContentSend_P(PSTR("" D_FRIENDLY_NAME " %d (" FRIENDLY_NAME "%s)

"), + i +1, + (i) ? stemp : "", + i, i, + (i) ? stemp : "", + Settings.friendlyname[i]); } #ifdef USE_EMULATION - page += FPSTR(HTTP_FORM_OTHER3a); + WSContentSend(PSTR("

 " D_EMULATION " 

")); // Keep close to Friendlynames so do not use
for (uint8_t i = 0; i < EMUL_MAX; i++) { - page += FPSTR(HTTP_FORM_OTHER3b); - page.replace(F("{1"), String(i)); - page.replace(F("{2"), (i == Settings.flag2.emulation) ? F(" checked") : F("")); - page.replace(F("{3"), (i == EMUL_NONE) ? F(D_NONE) : (i == EMUL_WEMO) ? F(D_BELKIN_WEMO) : F(D_HUE_BRIDGE)); - page.replace(F("{4"), (i == EMUL_NONE) ? F("") : (i == EMUL_WEMO) ? F(" " D_SINGLE_DEVICE) : F(" " D_MULTI_DEVICE)); + WSContentSend_P(PSTR("%s %s
"), // Different id only used for labels + i, i, + (i == Settings.flag2.emulation) ? " checked" : "", + GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions), + (i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE); } - page += FPSTR(HTTP_FORM_OTHER3c); + WSContentSend(PSTR("

")); #endif // USE_EMULATION - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void OtherSaveSettings(void) @@ -1436,7 +1477,7 @@ void OtherSaveSettings(void) #endif // USE_EMULATION snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation); for (uint8_t i = 0; i < MAX_FRIENDLYNAMES; i++) { - snprintf_P(webindex, sizeof(webindex), PSTR("a%d"), i +1); + snprintf_P(webindex, sizeof(webindex), PSTR("a%d"), i); WebGetArg(webindex, tmp, sizeof(tmp)); snprintf_P(friendlyname, sizeof(friendlyname), PSTR(FRIENDLY_NAME"%d"), i +1); strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? friendlyname : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i])); @@ -1505,17 +1546,16 @@ void HandleBackupConfiguration(void) void HandleResetConfiguration(void) { - if (!HttpCheckPriviledgedAccess()) { return; } + if (!HttpCheckPriviledgedAccess(!WifiIsInManagerMode())) { return; } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESET_CONFIGURATION); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_RESET_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_CONFIGURATION_RESET "
"); - page += FPSTR(HTTP_MSG_RSTRT); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page, HTTP_MANAGER_RESET_ONLY != webserver_state); + WSContentStart(FPSTR(S_RESET_CONFIGURATION), !WifiIsInManagerMode()); + WSContentSendStyle(); + WSContentSend(F("
" D_CONFIGURATION_RESET "
")); + WSContentSend(FPSTR(HTTP_MSG_RSTRT)); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); + WSContentEnd(); char command[CMDSZ]; snprintf_P(command, sizeof(command), PSTR(D_CMND_RESET " 1")); @@ -1528,14 +1568,12 @@ void HandleRestoreConfiguration(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTORE_CONFIGURATION); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_RESTORE_CONFIGURATION)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_RST); - page += FPSTR(HTTP_FORM_RST_UPG); - page.replace(F("{r1"), F(D_RESTORE)); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentStart(FPSTR(S_RESTORE_CONFIGURATION)); + WSContentSendStyle(); + WSContentSend(FPSTR(HTTP_FORM_RST)); + WSContentSend_P(HTTP_FORM_RST_UPG, D_RESTORE); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); upload_error = 0; upload_file_type = UPL_SETTINGS; @@ -1553,113 +1591,91 @@ void HandleInformation(void) int freeMem = ESP.getFreeHeap(); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_INFORMATION)); - page += FPSTR(HTTP_HEAD_STYLE); - // page += F("
 Information "); - - page += F(""); - page += F("
"); - + WSContentStart(FPSTR(S_INFORMATION)); // Save 1k of code space replacing table html with javascript replace codes // }1 = // }2 = - String func = FPSTR(HTTP_SCRIPT_INFO_BEGIN); - func += F("
"); - func += F(D_PROGRAM_VERSION "}2"); func += my_version; func += my_image; - func += F("}1" D_BUILD_DATE_AND_TIME "}2"); func += GetBuildDateAndTime(); - func += F("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_ESP8266_RELEASE "/"); func += String(ESP.getSdkVersion()); - func += F("}1" D_UPTIME "}2"); func += GetUptime(); - snprintf_P(stopic, sizeof(stopic), PSTR(" at 0x%X"), GetSettingsAddress()); - func += F("}1" D_FLASH_WRITE_COUNT "}2"); func += String(Settings.save_flag); func += stopic; - func += F("}1" D_BOOT_COUNT "}2"); func += String(Settings.bootcount); - func += F("}1" D_RESTART_REASON "}2"); func += GetResetReason(); + WSContentSend(FPSTR(HTTP_SCRIPT_INFO_BEGIN)); + WSContentSend_P(PSTR("
")); + WSContentSend_P(PSTR(D_PROGRAM_VERSION "}2%s%s"), my_version, my_image); + WSContentSend_P(PSTR("}1" D_BUILD_DATE_AND_TIME "}2%s"), GetBuildDateAndTime().c_str()); + WSContentSend_P(PSTR("}1" D_CORE_AND_SDK_VERSION "}2" ARDUINO_ESP8266_RELEASE "/%s"), ESP.getSdkVersion()); + WSContentSend_P(PSTR("}1" D_UPTIME "}2%s"), GetUptime().c_str()); + WSContentSend_P(PSTR("}1" D_FLASH_WRITE_COUNT "}2%d at 0x%X"), Settings.save_flag, GetSettingsAddress()); + WSContentSend_P(PSTR("}1" D_BOOT_COUNT "}2%d"), Settings.bootcount); + WSContentSend_P(PSTR("}1" D_RESTART_REASON "}2%s"), GetResetReason().c_str()); uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present; if (SONOFF_IFAN02 == my_module_type) { maxfn = 1; } for (uint8_t i = 0; i < maxfn; i++) { - func += F("}1" D_FRIENDLY_NAME " "); func += i +1; func += F("}2"); func += Settings.friendlyname[i]; + WSContentSend_P(PSTR("}1" D_FRIENDLY_NAME " %d}2%s"), i +1, Settings.friendlyname[i]); } - - func += F("}1}2 "); // Empty line - func += F("}1" D_AP); func += String(Settings.sta_active +1); - func += F(" " D_SSID " (" D_RSSI ")}2"); func += Settings.sta_ssid[Settings.sta_active]; func += F(" ("); func += WifiGetRssiAsQuality(WiFi.RSSI()); func += F("%)"); - func += F("}1" D_HOSTNAME "}2"); func += my_hostname; - if (mdns_begun) { func += F(".local"); } + WSContentSend_P(PSTR("}1}2 ")); // Empty line + WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%)"), Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WifiGetRssiAsQuality(WiFi.RSSI())); + WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (mdns_begun) ? ".local" : ""); if (static_cast(WiFi.localIP()) != 0) { - func += F("}1" D_IP_ADDRESS "}2"); func += WiFi.localIP().toString(); - func += F("}1" D_GATEWAY "}2"); func += IPAddress(Settings.ip_address[1]).toString(); - func += F("}1" D_SUBNET_MASK "}2"); func += IPAddress(Settings.ip_address[2]).toString(); - func += F("}1" D_DNS_SERVER "}2"); func += IPAddress(Settings.ip_address[3]).toString(); - func += F("}1" D_MAC_ADDRESS "}2"); func += WiFi.macAddress(); + WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.localIP().toString().c_str()); + WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), IPAddress(Settings.ip_address[1]).toString().c_str()); + WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%s"), IPAddress(Settings.ip_address[2]).toString().c_str()); + WSContentSend_P(PSTR("}1" D_DNS_SERVER "}2%s"), IPAddress(Settings.ip_address[3]).toString().c_str()); + WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str()); } if (static_cast(WiFi.softAPIP()) != 0) { - func += F("}1" D_AP " " D_IP_ADDRESS "}2"); func += WiFi.softAPIP().toString(); - func += F("}1" D_AP " " D_GATEWAY "}2"); func += WiFi.softAPIP().toString(); - func += F("}1" D_AP " " D_MAC_ADDRESS "}2"); func += WiFi.softAPmacAddress(); + WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.softAPIP().toString().c_str()); + WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str()); + WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.softAPmacAddress().c_str()); } - - func += F("}1}2 "); // Empty line + WSContentSend_P(PSTR("}1}2 ")); // Empty line if (Settings.flag.mqtt_enabled) { - func += F("}1" D_MQTT_HOST "}2"); func += Settings.mqtt_host; - func += F("}1" D_MQTT_PORT "}2"); func += String(Settings.mqtt_port); - func += F("}1" D_MQTT_USER "}2"); func += Settings.mqtt_user; - func += F("}1" D_MQTT_CLIENT "}2"); func += mqtt_client; - func += F("}1" D_MQTT_TOPIC "}2"); func += Settings.mqtt_topic; - func += F("}1" D_MQTT_GROUP_TOPIC "}2"); func += Settings.mqtt_grptopic; - func += F("}1" D_MQTT_FULL_TOPIC "}2"); func += GetTopic_P(stopic, CMND, mqtt_topic, ""); - func += F("}1" D_MQTT " " D_FALLBACK_TOPIC "}2"); func += GetFallbackTopic_P(stopic, CMND, ""); + WSContentSend_P(PSTR("}1" D_MQTT_HOST "}2%s"), Settings.mqtt_host); + WSContentSend_P(PSTR("}1" D_MQTT_PORT "}2%d"), Settings.mqtt_port); + WSContentSend_P(PSTR("}1" D_MQTT_USER "}2%s"), Settings.mqtt_user); + WSContentSend_P(PSTR("}1" D_MQTT_CLIENT "}2%s"), mqtt_client); + WSContentSend_P(PSTR("}1" D_MQTT_TOPIC "}2%s"), Settings.mqtt_topic); + WSContentSend_P(PSTR("}1" D_MQTT_GROUP_TOPIC "}2%s"), Settings.mqtt_grptopic); + WSContentSend_P(PSTR("}1" D_MQTT_FULL_TOPIC "}2%s"), GetTopic_P(stopic, CMND, mqtt_topic, "")); + WSContentSend_P(PSTR("}1" D_MQTT " " D_FALLBACK_TOPIC "}2%s"), GetFallbackTopic_P(stopic, CMND, "")); } else { - func += F("}1" D_MQTT "}2" D_DISABLED); + WSContentSend_P(PSTR("}1" D_MQTT "}2" D_DISABLED)); } + WSContentSend_P(PSTR("}1}2 ")); // Empty line - func += F("}1}2 "); // Empty line - func += F("}1" D_EMULATION "}2"); #ifdef USE_EMULATION - if (EMUL_WEMO == Settings.flag2.emulation) { - func += F(D_BELKIN_WEMO); - } - else if (EMUL_HUE == Settings.flag2.emulation) { - func += F(D_HUE_BRIDGE); - } - else { - func += F(D_NONE); - } + WSContentSend_P(PSTR("}1" D_EMULATION "}2%s"), GetTextIndexed(stopic, sizeof(stopic), Settings.flag2.emulation, kEmulationOptions)); #else - func += F(D_DISABLED); + WSContentSend_P(PSTR("}1" D_EMULATION "}2" D_DISABLED)); #endif // USE_EMULATION - func += F("}1" D_MDNS_DISCOVERY "}2"); + #ifdef USE_DISCOVERY + WSContentSend_P(PSTR("}1" D_MDNS_DISCOVERY "}2%s"), (Settings.flag3.mdns_enabled) ? D_ENABLED : D_DISABLED); if (Settings.flag3.mdns_enabled) { - func += F(D_ENABLED); - func += F("}1" D_MDNS_ADVERTISE "}2"); #ifdef WEBSERVER_ADVERTISE - func += F(D_WEB_SERVER); + WSContentSend_P(PSTR("}1" D_MDNS_ADVERTISE "}2" D_WEB_SERVER)); #else - func += F(D_DISABLED); + WSContentSend_P(PSTR("}1" D_MDNS_ADVERTISE "}2" D_DISABLED)); #endif // WEBSERVER_ADVERTISE - } else { - func += F(D_DISABLED); } #else - func += F(D_DISABLED); + WSContentSend_P(PSTR("}1" D_MDNS_DISCOVERY "}2" D_DISABLED)); #endif // USE_DISCOVERY - func += F("}1}2 "); // Empty line - func += F("}1" D_ESP_CHIP_ID "}2"); func += String(ESP.getChipId()); - snprintf_P(stopic, sizeof(stopic), PSTR("0x%06X"), ESP.getFlashChipId()); - func += F("}1" D_FLASH_CHIP_ID "}2"); func += stopic; - func += F("}1" D_FLASH_CHIP_SIZE "}2"); func += String(ESP.getFlashChipRealSize() / 1024); func += F("kB"); - func += F("}1" D_PROGRAM_FLASH_SIZE "}2"); func += String(ESP.getFlashChipSize() / 1024); func += F("kB"); - func += F("}1" D_PROGRAM_SIZE "}2"); func += String(ESP.getSketchSize() / 1024); func += F("kB"); - func += F("}1" D_FREE_PROGRAM_SPACE "}2"); func += String(ESP.getFreeSketchSpace() / 1024); func += F("kB"); - func += F("}1" D_FREE_MEMORY "}2"); func += String(freeMem / 1024); func += F("kB"); - func += F("
"); - func += FPSTR(HTTP_SCRIPT_INFO_END); - page.replace(F(""), func); + WSContentSend_P(PSTR("}1}2 ")); // Empty line + WSContentSend_P(PSTR("}1" D_ESP_CHIP_ID "}2%d"), ESP.getChipId()); + WSContentSend_P(PSTR("}1" D_FLASH_CHIP_ID "}20x%06X"), ESP.getFlashChipId()); + WSContentSend_P(PSTR("}1" D_FLASH_CHIP_SIZE "}2%dkB"), ESP.getFlashChipRealSize() / 1024); + WSContentSend_P(PSTR("}1" D_PROGRAM_FLASH_SIZE "}2%dkB"), ESP.getFlashChipSize() / 1024); + WSContentSend_P(PSTR("}1" D_PROGRAM_SIZE "}2%dkB"), ESP.getSketchSize() / 1024); + WSContentSend_P(PSTR("}1" D_FREE_PROGRAM_SPACE "}2%dkB"), ESP.getFreeSketchSpace() / 1024); + WSContentSend_P(PSTR("}1" D_FREE_MEMORY "}2%dkB"), freeMem / 1024); + WSContentSend_P(PSTR("
")); - // page += F("
"); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentSend(FPSTR(HTTP_SCRIPT_INFO_END)); + WSContentSendStyle(); + // WSContentSend(F("
 Information ")); + WSContentSend_P(PSTR("" + "
")); + // WSContentSend(F("
")); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); + WSContentEnd(); } #endif // Not FIRMWARE_MINIMAL @@ -1671,15 +1687,12 @@ void HandleUpgradeFirmware(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_FIRMWARE_UPGRADE); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_FIRMWARE_UPGRADE)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_UPG); - page.replace(F("{o1"), Settings.ota_url); - page += FPSTR(HTTP_FORM_RST_UPG); - page.replace(F("{r1"), F(D_UPGRADE)); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentStart(FPSTR(S_FIRMWARE_UPGRADE)); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_UPG, Settings.ota_url); + WSContentSend_P(HTTP_FORM_RST_UPG, D_UPGRADE); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); + WSContentEnd(); upload_error = 0; upload_file_type = UPL_TASMOTA; @@ -1701,14 +1714,13 @@ void HandleUpgradeFirmwareStart(void) ExecuteWebCommand(command, SRC_WEBGUI); } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_INFORMATION)); - page += FPSTR(HTTP_SCRIPT_RELOAD_OTA); - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_UPGRADE_STARTED " ...
"); - page += FPSTR(HTTP_MSG_RSTRT); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentStart(FPSTR(S_INFORMATION)); + WSContentSend(FPSTR(HTTP_SCRIPT_RELOAD_OTA)); + WSContentSendStyle(); + WSContentSend(F("
" D_UPGRADE_STARTED " ...
")); + WSContentSend(FPSTR(HTTP_MSG_RSTRT)); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); + WSContentEnd(); snprintf_P(command, sizeof(command), PSTR(D_CMND_UPGRADE " 1")); ExecuteWebCommand(command, SRC_WEBGUI); @@ -1726,15 +1738,14 @@ void HandleUploadDone(void) restart_flag = 0; MqttRetryCounter(0); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_INFORMATION)); + WSContentStart(FPSTR(S_INFORMATION)); if (!upload_error) { - page += FPSTR(HTTP_SCRIPT_RELOAD_OTA); // Refesh main web ui after OTA upgrade + WSContentSend(FPSTR(HTTP_SCRIPT_RELOAD_OTA)); // Refesh main web ui after OTA upgrade } - page += FPSTR(HTTP_HEAD_STYLE); - page += F("
" D_UPLOAD " " D_UPLOAD " " D_FAILED "

"); + WSContentSend(F("red'>" D_FAILED "


")); #ifdef USE_RF_FLASH if (upload_error < 14) { #else @@ -1744,20 +1755,20 @@ void HandleUploadDone(void) } else { snprintf_P(error, sizeof(error), PSTR(D_UPLOAD_ERROR_CODE " %d"), upload_error); } - page += error; + WSContentSend(error); snprintf_P(log_data, sizeof(log_data), PSTR(D_UPLOAD ": %s"), error); AddLog(LOG_LEVEL_DEBUG); stop_flash_rotate = Settings.flag.stop_flash_rotate; } else { - page += F("green'>" D_SUCCESSFUL "
"); - page += FPSTR(HTTP_MSG_RSTRT); + WSContentSend(F("green'>" D_SUCCESSFUL "
")); + WSContentSend(FPSTR(HTTP_MSG_RSTRT)); ShowWebSource(SRC_WEBGUI); restart_flag = 2; // Always restart to re-enable disabled features during update } SettingsBufferFree(); - page += F("

"); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentSend(F("
")); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); + WSContentEnd(); } void HandleUploadLoop(void) @@ -2016,7 +2027,7 @@ void HandleHttpCommand(void) } else { message += F(D_NEED_USER_AND_PASSWORD "\"}"); } - SetHeader(); + WSHeaderSend(); WSSend(200, CT_JSON, message); } @@ -2033,13 +2044,12 @@ void HandleConsole(void) AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONSOLE); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONSOLE)); - page += FPSTR(HTTP_SCRIPT_CONSOL); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_CMND); - page += FPSTR(HTTP_BTN_MAIN); - ShowPage(page); + WSContentStart(FPSTR(S_CONSOLE)); + WSContentSend_P(HTTP_SCRIPT_CONSOL, Settings.web_refresh); + WSContentSendStyle(); + WSContentSend(FPSTR(HTTP_FORM_CMND)); + WSContentSend(FPSTR(HTTP_BTN_MAIN)); + WSContentEnd(); } void HandleConsoleRefresh(void) @@ -2060,7 +2070,7 @@ void HandleConsoleRefresh(void) bool last_reset_web_log_flag = reset_web_log_flag; // mqtt_data used as scratch space - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%d\1%d\1"), web_log_index, last_reset_web_log_flag); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%d}1%d}1"), web_log_index, last_reset_web_log_flag); String message = mqtt_data; if (!reset_web_log_flag) { counter = 0; @@ -2089,7 +2099,7 @@ void HandleConsoleRefresh(void) if (!counter) { counter++; } // Skip log index 0 as it is not allowed } while (counter != web_log_index); } - message += F("\1"); + message += F("}1"); WSSend(200, CT_PLAIN, message); } @@ -2114,7 +2124,7 @@ void HandleNotFound(void) for (uint8_t i = 0; i < WebServer->args(); i++) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s %s: %s\n"), mqtt_data, WebServer->argName(i).c_str(), WebServer->arg(i).c_str()); } - SetHeader(); + WSHeaderSend(); WSSend(404, CT_PLAIN, mqtt_data); } } diff --git a/sonoff/xdrv_02_mqtt.ino b/sonoff/xdrv_02_mqtt.ino index 8721b42b2..ea0cc01e5 100644 --- a/sonoff/xdrv_02_mqtt.ino +++ b/sonoff/xdrv_02_mqtt.ino @@ -900,16 +900,17 @@ const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT; const char HTTP_BTN_MENU_MQTT[] PROGMEM = "

"; -const char HTTP_FORM_MQTT[] PROGMEM = +const char HTTP_FORM_MQTT1[] PROGMEM = "
 " D_MQTT_PARAMETERS " " "
" - "

" D_HOST " (" MQTT_HOST ")

" - "

" D_PORT " (" STR(MQTT_PORT) ")

" - "

" D_CLIENT " ({m0)

" - "

" D_USER " (" MQTT_USER ")

" + "

" D_HOST " (" MQTT_HOST ")

" + "

" D_PORT " (" STR(MQTT_PORT) ")

" + "

" D_CLIENT " (%s)

"; +const char HTTP_FORM_MQTT2[] PROGMEM = + "

" D_USER " (" MQTT_USER ")

" "

" D_PASSWORD "

" - "

" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" - "

" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; + "

" D_TOPIC " = %%topic%% (" MQTT_TOPIC ")

" + "

" D_FULL_TOPIC " (%s)

"; void HandleMqttConfiguration(void) { @@ -923,23 +924,24 @@ void HandleMqttConfiguration(void) return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT)); - page += FPSTR(HTTP_HEAD_STYLE); - - page += FPSTR(HTTP_FORM_MQTT); char str[sizeof(Settings.mqtt_client)]; - page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client))); - page.replace(F("{m1"), Settings.mqtt_host); - page.replace(F("{m2"), String(Settings.mqtt_port)); - page.replace(F("{m3"), Settings.mqtt_client); - page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); - page.replace(F("{m6"), Settings.mqtt_topic); - page.replace(F("{m7"), Settings.mqtt_fulltopic); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentStart(FPSTR(S_CONFIGURE_MQTT)); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_MQTT1, + Settings.mqtt_host, + Settings.mqtt_port, + Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client)), + MQTT_CLIENT_ID, + Settings.mqtt_client); + WSContentSend_P(HTTP_FORM_MQTT2, + (Settings.mqtt_user[0] == '\0') ? "0" : Settings.mqtt_user, + Settings.mqtt_topic, + MQTT_FULLTOPIC, MQTT_FULLTOPIC, + Settings.mqtt_fulltopic); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void MqttSaveSettings(void) @@ -988,7 +990,7 @@ bool Xdrv02(uint8_t function) switch (function) { #ifdef USE_WEBSERVER case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_MQTT, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend(FPSTR(HTTP_BTN_MENU_MQTT)); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration); diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index 65711cd68..ec4e4f142 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -439,14 +439,14 @@ const char HTTP_FORM_DOMOTICZ[] PROGMEM = "
" ""; const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = - "" - ""; + "" + ""; const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = - ""; + ""; const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = - ""; + ""; const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = - ""; + ""; void HandleDomoticzConfiguration(void) { @@ -462,35 +462,30 @@ void HandleDomoticzConfiguration(void) char stemp[32]; - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_DOMOTICZ)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_DOMOTICZ); + WSContentStart(FPSTR(S_CONFIGURE_DOMOTICZ)); + WSContentSendStyle(); + WSContentSend(FPSTR(HTTP_FORM_DOMOTICZ)); for (int i = 0; i < MAX_DOMOTICZ_IDX; i++) { if (i < devices_present) { - page += FPSTR(HTTP_FORM_DOMOTICZ_RELAY); - page.replace("{2", String((int)Settings.domoticz_relay_idx[i])); - page.replace("{3", String((int)Settings.domoticz_key_idx[i])); + WSContentSend_P(HTTP_FORM_DOMOTICZ_RELAY, + i +1, i, i, Settings.domoticz_relay_idx[i], + i +1, i, i, Settings.domoticz_key_idx[i]); } if (pin[GPIO_SWT1 +i] < 99) { - page += FPSTR(HTTP_FORM_DOMOTICZ_SWITCH); - page.replace("{4", String((int)Settings.domoticz_switch_idx[i])); + WSContentSend_P(HTTP_FORM_DOMOTICZ_SWITCH, + i +1, i, i, Settings.domoticz_switch_idx[i]); } - page.replace("{1", String(i +1)); if ((SONOFF_IFAN02 == my_module_type) && (1 == i)) { break; } } for (int i = 0; i < DZ_MAX_SENSORS; i++) { - page += FPSTR(HTTP_FORM_DOMOTICZ_SENSOR); - page.replace("{1", String(i +1)); - page.replace("{2", GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors)); - page.replace("{5", String((int)Settings.domoticz_sensor_idx[i])); + WSContentSend_P(HTTP_FORM_DOMOTICZ_SENSOR, + i +1, GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors), i, i, Settings.domoticz_sensor_idx[i]); } - page += FPSTR(HTTP_FORM_DOMOTICZ_TIMER); - page.replace("{6", String((int)Settings.domoticz_update_timer)); - page += F("
" D_DOMOTICZ_IDX " {1
" D_DOMOTICZ_KEY_IDX " {1
" D_DOMOTICZ_IDX " %d
" D_DOMOTICZ_KEY_IDX " %d
" D_DOMOTICZ_SWITCH_IDX " {1
" D_DOMOTICZ_SWITCH_IDX " %d
" D_DOMOTICZ_SENSOR_IDX " {1 {2
" D_DOMOTICZ_SENSOR_IDX " %d %s
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")
"); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend_P(HTTP_FORM_DOMOTICZ_TIMER, Settings.domoticz_update_timer); + WSContentSend(F("")); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void DomoticzSaveSettings(void) @@ -500,19 +495,19 @@ void DomoticzSaveSettings(void) char tmp[100]; for (uint8_t i = 0; i < MAX_DOMOTICZ_IDX; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i +1); + snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_relay_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i +1); + snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_key_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); - snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i +1); + snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_switch_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); } ssensor_indices[0] = '\0'; for (uint8_t i = 0; i < DZ_MAX_SENSORS; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i +1); + snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i); WebGetArg(stemp, tmp, sizeof(tmp)); Settings.domoticz_sensor_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp); snprintf_P(ssensor_indices, sizeof(ssensor_indices), PSTR("%s%s%d"), ssensor_indices, (strlen(ssensor_indices)) ? "," : "", Settings.domoticz_sensor_idx[i]); @@ -541,7 +536,7 @@ bool Xdrv07(uint8_t function) switch (function) { #ifdef USE_WEBSERVER case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_DOMOTICZ, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend(FPSTR(HTTP_BTN_MENU_DOMOTICZ)); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration); diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 3c3b1f376..094fbcd96 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -519,7 +519,7 @@ const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; const char HTTP_BTN_MENU_TIMER[] PROGMEM = "

"; -const char HTTP_TIMER_SCRIPT[] PROGMEM = +const char HTTP_TIMER_SCRIPT1[] PROGMEM = "var pt=[],ct=99;" "function qs(s){" // Alias to save code space "return document.querySelector(s);" @@ -528,8 +528,9 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "var o=document.createElement('option');" "o.textContent=i;" "q.appendChild(o);" - "}" + "}"; #ifdef USE_SUNRISE +const char HTTP_TIMER_SCRIPT2[] PROGMEM = "function gt(){" // Set hours and minutes according to mode "var m,p,q;" "m=qs('input[name=\"rd\"]:checked').value;" // Get mode @@ -558,8 +559,9 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "qs('#dr').disabled='disabled';" "if(e<23){for(i=12;i<=23;i++){ce(i,o);}}" // Create hours select options "}" - "}" + "}"; #endif +const char HTTP_TIMER_SCRIPT3[] PROGMEM = "function st(){" // Save parameters to hidden area "var i,l,m,n,p,s;" "m=0;s=0;" @@ -570,7 +572,7 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "m=qs('input[name=\"rd\"]:checked').value;" // Check mode "s|=(qs('input[name=\"rd\"]:checked').value<<29);" // Get mode #endif - "if(}1>0){" + "if(%d>0){" "i=qs('#d1').selectedIndex;if(i>=0){s|=(i<<23);}" // Get output "s|=(qs('#p1').selectedIndex<<27);" // Get action "}else{" @@ -587,7 +589,8 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = "s|=((qs('#mw').selectedIndex)&0x0F)<<11;" // Get window minutes "pt[ct]=s;" "eb('t0').value=pt.join();" // Save parameters from array to hidden area - "}" + "}"; +const char HTTP_TIMER_SCRIPT4[] PROGMEM = "function ot(t,e){" // Select tab and update elements "var i,n,o,p,q,s;" "if(ct<99){st();}" // Save changes @@ -602,23 +605,24 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = #else "p=s&0x7FF;" // Get time "q=Math.floor(p/60);if(q<10){q='0'+q;}qs('#ho').value=q;" // Set hours - "q=p%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes + "q=p%%60;if(q<10){q='0'+q;}qs('#mi').value=q;" // Set minutes #endif "q=(s>>11)&0xF;if(q<10){q='0'+q;}qs('#mw').value=q;" // Set window minutes "for(i=0;i<7;i++){p=(s>>(16+i))&1;eb('w'+i).checked=p;}" // Set weekdays - "if(}1>0){" + "if(%d>0){" "p=(s>>23)&0xF;qs('#d1').value=p+1;" // Set output "p=(s>>27)&3;qs('#p1').selectedIndex=p;" // Set action "}" "p=(s>>15)&1;eb('r0').checked=p;" // Set repeat "p=(s>>31)&1;eb('a0').checked=p;" // Set arm - "}" + "}"; +const char HTTP_TIMER_SCRIPT5[] PROGMEM = "function it(){" // Initialize elements and select first tab "var b,i,o,s;" "pt=eb('t0').value.split(',').map(Number);" // Get parameters from hidden area to array "s='';for(i=0;i<" STR(MAX_TIMERS) ";i++){b='';if(0==i){b=\" id='dP'\";}s+=\"\"}" "eb('bt').innerHTML=s;" // Create tabs - "if(}1>0){" // Create Output and Action drop down boxes + "if(%d>0){" // Create Output and Action drop down boxes "eb('oa').innerHTML=\"" D_TIMER_OUTPUT " " D_TIMER_ACTION " \";" "o=qs('#p1');ce('" D_OFF "',o);ce('" D_ON "',o);ce('" D_TOGGLE "',o);" // Create offset direction select options #ifdef USE_RULES @@ -628,48 +632,52 @@ const char HTTP_TIMER_SCRIPT[] PROGMEM = #endif "}else{" "eb('oa').innerHTML=\"" D_TIMER_ACTION " " D_RULE "\";" // No outputs but rule is allowed - "}" + "}"; +const char HTTP_TIMER_SCRIPT6[] PROGMEM = #ifdef USE_SUNRISE "o=qs('#dr');ce('+',o);ce('-',o);" // Create offset direction select options #endif "o=qs('#ho');for(i=0;i<=23;i++){ce((i<10)?('0'+i):i,o);}" // Create hours select options "o=qs('#mi');for(i=0;i<=59;i++){ce((i<10)?('0'+i):i,o);}" // Create minutes select options "o=qs('#mw');for(i=0;i<=15;i++){ce((i<10)?('0'+i):i,o);}" // Create window minutes select options - "o=qs('#d1');for(i=0;i<}1;i++){ce(i+1,o);}" // Create outputs + "o=qs('#d1');for(i=0;i<%d;i++){ce(i+1,o);}" // Create outputs "var a='" D_DAY3LIST "';" "s='';for(i=0;i<7;i++){s+=\"\"+a.substring(i*3,(i*3)+3)+\" \"}" "eb('ds').innerHTML=s;" // Create weekdays "eb('dP').click();" // Get the element with id='dP' and click on it - "}"; + "}" + "window.onload=it;"; const char HTTP_TIMER_STYLE[] PROGMEM = - ".tl{float:left;border-radius:0;border:1px solid #f2f2f2;padding:1px;width:6.25%;}" // Border color needs to be the same as Fieldset background color from HTTP_HEAD_STYLE (transparent won't work) - ""; -const char HTTP_FORM_TIMER[] PROGMEM = + ".tl{float:left;border-radius:0;border:1px solid #f2f2f2;padding:1px;width:6.25%;}"; // Border color needs to be the same as Fieldset background color from HTTP_HEAD_STYLE1 (transparent won't work) +const char HTTP_FORM_TIMER1[] PROGMEM = "
" " " D_TIMER_PARAMETERS " " "
" - "
" D_TIMER_ENABLE "


" + "
" D_TIMER_ENABLE "


" "



" "

" "
" "" D_TIMER_ARM " " "" D_TIMER_REPEAT "" "

" - "
" + "
"; #ifdef USE_SUNRISE - "
" // 299 used in page.replace(F("299") +const char HTTP_FORM_TIMER3[] PROGMEM = + "
" "" D_TIMER_TIME "
" - "" D_SUNRISE " (}8)
" - "" D_SUNSET " (}9)
" + "" D_SUNRISE " (%s)
" + "" D_SUNSET " (%s)
" "
" "

" "" - " " + " "; #else - "" D_TIMER_TIME " " +const char HTTP_FORM_TIMER3[] PROGMEM = + "" D_TIMER_TIME " "; #endif // USE_SUNRISE +const char HTTP_FORM_TIMER4[] PROGMEM = "" " " D_HOUR_MINUTE_SEPARATOR " " "" @@ -690,28 +698,30 @@ void HandleTimerConfiguration(void) return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_TIMER)); - page += FPSTR(HTTP_TIMER_SCRIPT); - page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F(""), FPSTR(HTTP_TIMER_STYLE)); - page += FPSTR(HTTP_FORM_TIMER); - page.replace(F("{e0"), (Settings.flag3.timers_enable) ? F(" checked") : F("")); - for (uint8_t i = 0; i < MAX_TIMERS; i++) { - if (i > 0) { page += F(","); } - page += String(Settings.timer[i].data); - } - page += FPSTR(HTTP_FORM_TIMER1); - page.replace(F("}1"), String(devices_present)); + WSContentStart(FPSTR(S_CONFIGURE_TIMER)); + WSContentSend(FPSTR(HTTP_TIMER_SCRIPT1)); #ifdef USE_SUNRISE - page.replace(F("}8"), GetSun(0)); // Add Sunrise - page.replace(F("}9"), GetSun(1)); // Add Sunset - page.replace(F("299"), String(100 + (strlen(D_SUNSET) *12))); // Fix string length to keep radios centered + WSContentSend(FPSTR(HTTP_TIMER_SCRIPT2)); #endif // USE_SUNRISE - page += FPSTR(HTTP_FORM_END); - page += F(""); // Init elements and select first tab/button - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentSend_P(HTTP_TIMER_SCRIPT3, devices_present); + WSContentSend_P(HTTP_TIMER_SCRIPT4, devices_present); + WSContentSend_P(HTTP_TIMER_SCRIPT5, devices_present); + WSContentSend_P(HTTP_TIMER_SCRIPT6, devices_present); + WSContentSendStyle(FPSTR(HTTP_TIMER_STYLE)); + WSContentSend_P(HTTP_FORM_TIMER1, (Settings.flag3.timers_enable) ? " checked" : ""); + for (uint8_t i = 0; i < MAX_TIMERS; i++) { + WSContentSend_P(PSTR("%s%u"), (i > 0) ? "," : "", Settings.timer[i].data); + } + WSContentSend(FPSTR(HTTP_FORM_TIMER2)); +#ifdef USE_SUNRISE + WSContentSend_P(HTTP_FORM_TIMER3, 100 + (strlen(D_SUNSET) *12), GetSun(0).c_str(), GetSun(1).c_str()); +#else + WSContentSend(FPSTR(HTTP_FORM_TIMER3)); +#endif // USE_SUNRISE + WSContentSend(FPSTR(HTTP_FORM_TIMER4)); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void TimerSaveSettings(void) @@ -754,9 +764,9 @@ bool Xdrv09(uint8_t function) #ifdef USE_TIMERS_WEB case FUNC_WEB_ADD_BUTTON: #ifdef USE_RULES - strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend(FPSTR(HTTP_BTN_MENU_TIMER)); #else - if (devices_present) { strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data) - strlen(mqtt_data) -1); } + if (devices_present) { WSContentSend(FPSTR(HTTP_BTN_MENU_TIMER)); } #endif // USE_RULES break; case FUNC_WEB_ADD_HANDLER: diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino index 461094162..379f01157 100644 --- a/sonoff/xdrv_11_knx.ino +++ b/sonoff/xdrv_11_knx.ino @@ -755,13 +755,14 @@ const char HTTP_BTN_MENU_KNX[] PROGMEM = "

"; const char HTTP_FORM_KNX[] PROGMEM = - "
 " D_KNX_PARAMETERS " " - "
" + "
" + " " D_KNX_PARAMETERS " " + "" "
" "" D_KNX_PHYSICAL_ADDRESS " " - " . " - " . " - "" + " . " + " . " + "" "

" D_KNX_PHYSICAL_ADDRESS_NOTE "

" "{nop}"; + ""; const char HTTP_FORM_KNX_GA[] PROGMEM = - " / " - " / " - " "; + " / " + " / " + " "; const char HTTP_FORM_KNX_ADD_BTN[] PROGMEM = - "

" - ""; + "

" + "
"; const char HTTP_FORM_KNX_ADD_TABLE_ROW[] PROGMEM = - "" - ""; + "" + ""; const char HTTP_FORM_KNX3[] PROGMEM = "
{optex} -> GAfnum / GAarea / GAfdef
%s -> %d / %d / %d

" @@ -801,8 +802,8 @@ const char HTTP_FORM_KNX4[] PROGMEM = "-> -> "); - page += FPSTR(HTTP_FORM_KNX_GA); - page.replace(F("GAfnum"), F("GA_FNUM")); - page.replace(F("GAarea"), F("GA_AREA")); - page.replace(F("GAfdef"), F("GA_FDEF")); - page.replace(F("GAfnum"), F("GA_FNUM")); - page.replace(F("GAarea"), F("GA_AREA")); - page.replace(F("GAfdef"), F("GA_FDEF")); - page += FPSTR(HTTP_FORM_KNX_ADD_BTN); - page.replace(F("{btnval}"), String(1)); - if (Settings.knx_GA_registered < MAX_KNX_GA) { - page.replace(F("btndis"), F(" ")); - } - else - { - page.replace(F("btndis"), F("disabled")); - } - page.replace(F("fncbtnadd"), F("GAwarning")); - for (uint8_t i = 0; i < Settings.knx_GA_registered ; ++i) - { - if ( Settings.knx_GA_param[i] ) - { - page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW); - page.replace(F("{opval}"), String(i+1)); - page.replace(F("{optex}"), String(device_param_ga[Settings.knx_GA_param[i]-1])); - KNX_addr.value = Settings.knx_GA_addr[i]; - page.replace(F("GAfnum"), String(KNX_addr.ga.area)); - page.replace(F("GAarea"), String(KNX_addr.ga.line)); - page.replace(F("GAfdef"), String(KNX_addr.ga.member)); - } - } - - page += FPSTR(HTTP_FORM_KNX3); - page += FPSTR(HTTP_FORM_KNX_GA); - page.replace(F("GAfnum"), F("CB_FNUM")); - page.replace(F("GAarea"), F("CB_AREA")); - page.replace(F("GAfdef"), F("CB_FDEF")); - page.replace(F("GAfnum"), F("CB_FNUM")); - page.replace(F("GAarea"), F("CB_AREA")); - page.replace(F("GAfdef"), F("CB_FDEF")); - page += FPSTR(HTTP_FORM_KNX4); - uint8_t j; - for (uint8_t i = 0; i < KNX_MAX_device_param ; i++) - { - // Check How many Relays are available and add: RelayX and TogleRelayX - if ( (i > 8) && (i < 16) ) { j=i-8; } else { j=i; } - if ( i == 8 ) { j = 0; } - if ( device_param[j].show ) - { - page += FPSTR(HTTP_FORM_KNX_OPT); - page.replace(F("{vop}"), String(device_param[i].type)); - page.replace(F("{nop}"), String(device_param_cb[i])); - } - } - page += F(" "); - page += FPSTR(HTTP_FORM_KNX_ADD_BTN); - page.replace(F("{btnval}"), String(2)); - if (Settings.knx_CB_registered < MAX_KNX_CB) { - page.replace(F("btndis"), F(" ")); - } - else - { - page.replace(F("btndis"), F("disabled")); - } - page.replace(F("fncbtnadd"), F("CBwarning")); - - for (uint8_t i = 0; i < Settings.knx_CB_registered ; ++i) - { - if ( Settings.knx_CB_param[i] ) - { - page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW2); - page.replace(F("{opval}"), String(i+1)); - page.replace(F("{optex}"), String(device_param_cb[Settings.knx_CB_param[i]-1])); - KNX_addr.value = Settings.knx_CB_addr[i]; - page.replace(F("GAfnum"), String(KNX_addr.ga.area)); - page.replace(F("GAarea"), String(KNX_addr.ga.line)); - page.replace(F("GAfdef"), String(KNX_addr.ga.member)); - } - } - page += F("
"); - page += F("
"); - page += FPSTR(HTTP_BTN_CONF); - - page.replace( F(""), + WSContentStart(FPSTR(S_CONFIGURE_KNX)); + WSContentSend( F("function GAwarning()" "{" "var GA_FNUM = eb('GA_FNUM');" @@ -995,9 +891,63 @@ void HandleKNXConfiguration(void) "if ( CB_FNUM != null && CB_FNUM.value == '0' && CB_AREA.value == '0' && CB_FDEF.value == '0' ) {" "alert('" D_KNX_WARNING "');" "}" - "}" - "") ); - ShowPage(page); + "}")); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_KNX, KNX_physs_addr.pa.area, KNX_physs_addr.pa.line, KNX_physs_addr.pa.member); + if ( Settings.flag.knx_enabled ) { WSContentSend(F(" checked")); } + WSContentSend(FPSTR(HTTP_FORM_KNX1)); + if ( Settings.flag.knx_enable_enhancement ) { WSContentSend(F(" checked")); } + + WSContentSend(FPSTR(HTTP_FORM_KNX2)); + for (uint8_t i = 0; i < KNX_MAX_device_param ; i++) + { + if ( device_param[i].show ) + { + WSContentSend_P(HTTP_FORM_KNX_OPT, device_param[i].type, device_param_ga[i]); + } + } + WSContentSend(F(" -> ")); + WSContentSend_P(HTTP_FORM_KNX_GA, "GA_FNUM", "GA_FNUM", "GA_AREA", "GA_AREA", "GA_FDEF", "GA_FDEF"); + WSContentSend_P(HTTP_FORM_KNX_ADD_BTN, "GAwarning", (Settings.knx_GA_registered < MAX_KNX_GA) ? "" : "disabled", 1); + for (uint8_t i = 0; i < Settings.knx_GA_registered ; ++i) + { + if ( Settings.knx_GA_param[i] ) + { + KNX_addr.value = Settings.knx_GA_addr[i]; + WSContentSend_P(HTTP_FORM_KNX_ADD_TABLE_ROW, device_param_ga[Settings.knx_GA_param[i]-1], KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, i +1); + } + } + + WSContentSend(FPSTR(HTTP_FORM_KNX3)); + WSContentSend_P(HTTP_FORM_KNX_GA, "CB_FNUM", "CB_FNUM", "CB_AREA", "CB_AREA", "CB_FDEF", "CB_FDEF"); + WSContentSend(FPSTR(HTTP_FORM_KNX4)); + + uint8_t j; + for (uint8_t i = 0; i < KNX_MAX_device_param ; i++) + { + // Check How many Relays are available and add: RelayX and TogleRelayX + if ( (i > 8) && (i < 16) ) { j=i-8; } else { j=i; } + if ( i == 8 ) { j = 0; } + if ( device_param[j].show ) + { + WSContentSend_P(HTTP_FORM_KNX_OPT, device_param[i].type, device_param_cb[i]); + } + } + WSContentSend(F(" ")); + WSContentSend_P(HTTP_FORM_KNX_ADD_BTN, "CBwarning", (Settings.knx_CB_registered < MAX_KNX_CB) ? "" : "disabled", 2); + + for (uint8_t i = 0; i < Settings.knx_CB_registered ; ++i) + { + if ( Settings.knx_CB_param[i] ) + { + KNX_addr.value = Settings.knx_CB_addr[i]; + WSContentSend_P(HTTP_FORM_KNX_ADD_TABLE_ROW2, KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member, device_param_cb[Settings.knx_CB_param[i]-1], i +1); + } + } + WSContentSend(F("
")); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } } @@ -1299,7 +1249,7 @@ bool Xdrv11(uint8_t function) #ifdef USE_WEBSERVER #ifdef USE_KNX_WEB_MENU case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_KNX, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend(FPSTR(HTTP_BTN_MENU_KNX)); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/kn", HandleKNXConfiguration); diff --git a/sonoff/xsns_34_hx711.ino b/sonoff/xsns_34_hx711.ino index 148f7f860..2de8b985a 100644 --- a/sonoff/xsns_34_hx711.ino +++ b/sonoff/xsns_34_hx711.ino @@ -382,14 +382,14 @@ const char HTTP_BTN_MENU_HX711[] PROGMEM = const char HTTP_FORM_HX711[] PROGMEM = "
 " D_CALIBRATION " " "
" - "

" D_REFERENCE_WEIGHT " (" D_UNIT_KILOGRAM ")

" + "

" D_REFERENCE_WEIGHT " (" D_UNIT_KILOGRAM ")

" "
" "
" "


" "
 " D_HX711_PARAMETERS " " "
" - "

" D_ITEM_WEIGHT " (" D_UNIT_KILOGRAM ")

"; + "

" D_ITEM_WEIGHT " (" D_UNIT_KILOGRAM ")

"; void HandleHxAction(void) { @@ -403,41 +403,38 @@ void HandleHxAction(void) return; } - char tmp[100]; + char stemp1[20]; if (WebServer->hasArg("reset")) { - snprintf_P(tmp, sizeof(tmp), PSTR("Sensor34 1")); // Reset - ExecuteWebCommand(tmp, SRC_WEBGUI); + snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 1")); // Reset + ExecuteWebCommand(stemp1, SRC_WEBGUI); HandleRoot(); // Return to main screen return; } if (WebServer->hasArg("calibrate")) { - WebGetArg("p1", tmp, sizeof(tmp)); - Settings.weight_reference = (!strlen(tmp)) ? 0 : (unsigned long)(CharToDouble(tmp) * 1000); + WebGetArg("p1", stemp1, sizeof(stemp1)); + Settings.weight_reference = (!strlen(stemp1)) ? 0 : (unsigned long)(CharToDouble(stemp1) * 1000); HxLogUpdates(); - snprintf_P(tmp, sizeof(tmp), PSTR("Sensor34 2")); // Start calibration - ExecuteWebCommand(tmp, SRC_WEBGUI); + snprintf_P(stemp1, sizeof(stemp1), PSTR("Sensor34 2")); // Start calibration + ExecuteWebCommand(stemp1, SRC_WEBGUI); HandleRoot(); // Return to main screen return; } - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(D_CONFIGURE_HX711)); - page += FPSTR(HTTP_HEAD_STYLE); - page += FPSTR(HTTP_FORM_HX711); - dtostrfd((float)Settings.weight_reference / 1000, 3, tmp); - page.replace("{1", String(tmp)); - dtostrfd((float)Settings.weight_item / 10000, 4, tmp); - page.replace("{2", String(tmp)); - - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); + WSContentStart(FPSTR(D_CONFIGURE_HX711)); + WSContentSendStyle(); + dtostrfd((float)Settings.weight_reference / 1000, 3, stemp1); + char stemp2[20]; + dtostrfd((float)Settings.weight_item / 10000, 4, stemp2); + WSContentSend_P(HTTP_FORM_HX711, stemp1, stemp2); + WSContentSend(FPSTR(HTTP_FORM_END)); + WSContentSend(FPSTR(HTTP_BTN_CONF)); + WSContentEnd(); } void HxSaveSettings(void) @@ -495,10 +492,10 @@ bool Xsns34(uint8_t function) break; #ifdef USE_HX711_GUI case FUNC_WEB_ADD_MAIN_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_MAIN_HX711, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend(FPSTR(HTTP_BTN_MENU_MAIN_HX711)); break; case FUNC_WEB_ADD_BUTTON: - strncat_P(mqtt_data, HTTP_BTN_MENU_HX711, sizeof(mqtt_data) - strlen(mqtt_data) -1); + WSContentSend(FPSTR(HTTP_BTN_MENU_HX711)); break; case FUNC_WEB_ADD_HANDLER: WebServer->on("/" WEB_HANDLE_HX711, HandleHxAction);