2018-10-10 21:21:44 +01:00
/*
2019-10-27 10:13:24 +00:00
xdrv_01_webserver . ino - webserver for Tasmota
2018-10-10 21:21:44 +01:00
2021-07-05 14:00:10 +01:00
Copyright ( C ) 2021 Theo Arends and Adrian Scillato
2018-10-10 21:21:44 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2019-11-21 18:17:57 +00:00
2018-10-10 21:21:44 +01:00
# ifdef USE_WEBSERVER
/*********************************************************************************************\
* Web server and WiFi Manager
*
* Enables configuration and reconfiguration of WiFi credentials using a Captive Portal
* Based on source by AlexT ( https : //github.com/tzapu)
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-04-13 11:52:09 +01:00
# define XDRV_01 1
2018-11-07 09:30:03 +00:00
2021-02-02 13:57:53 +00:00
// Enable below demo feature only if defines USE_UNISHOX_COMPRESSION and USE_SCRIPT_WEB_DISPLAY are disabled
//#define USE_WEB_SSE
2023-08-04 15:11:58 +01:00
# define USE_CONSOLE_CSS_FLEX
2018-12-22 15:13:07 +00:00
# ifndef WIFI_SOFT_AP_CHANNEL
2021-04-13 11:52:09 +01:00
# define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by WifiManager web GUI
2018-12-22 15:13:07 +00:00
# endif
2021-04-12 17:36:43 +01:00
# ifndef MAX_WIFI_NETWORKS_TO_SHOW
2021-04-13 11:52:09 +01:00
# define MAX_WIFI_NETWORKS_TO_SHOW 3 // Maximum number of Wifi Networks to show in the Wifi Configuration Menu BEFORE clicking on Show More Networks.
2021-04-12 17:36:43 +01:00
# endif
# ifndef RESTART_AFTER_INITIAL_WIFI_CONFIG
# define RESTART_AFTER_INITIAL_WIFI_CONFIG true // Restart Tasmota after initial Wifi Config of a blank device
# endif // If disabled, Tasmota will keep both the wifi AP and the wifi connection to the router
// but only until next restart.
# ifndef AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP // If RESTART_AFTER_INITIAL_WIFI_CONFIG and AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP are true,
# define AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP true // the user will be redirected to the new IP of Tasmota (in the new Network).
# endif // If the first is true, but this is false, the device will restart but the user will see
// a window telling that the WiFi Configuration was Ok and that the window can be closed.
2021-06-19 14:22:17 +01:00
const uint16_t CHUNKED_BUFFER_SIZE = 500 ; // Chunk buffer size (needs to be well below stack space (4k for ESP8266, 8k for ESP32) but large enough to cache some small messages)
2019-03-31 10:59:04 +01:00
const uint16_t HTTP_REFRESH_TIME = 2345 ; // milliseconds
2020-11-21 16:12:17 +00:00
const uint16_t HTTP_RESTART_RECONNECT_TIME = 10000 ; // milliseconds - Allow time for restart and wifi reconnect
2020-11-28 17:12:29 +00:00
# ifdef ESP8266
2020-11-20 16:51:16 +00:00
const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 24000 ; // milliseconds - Allow time for uploading binary, unzip/write to final destination and wifi reconnect
2020-11-28 17:12:29 +00:00
# endif // ESP8266
# ifdef ESP32
const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 10000 ; // milliseconds - Allow time for restart and wifi reconnect
# endif // ESP32
2018-10-10 21:21:44 +01:00
2018-11-26 16:00:18 +00:00
# include <ESP8266WebServer.h>
# include <DNSServer.h>
2018-11-19 17:07:25 +00:00
2020-06-06 20:52:20 +01:00
# ifdef USE_UNISHOX_COMPRESSION
2022-04-03 14:01:47 +01:00
# include "./html_compressed/HTTP_HEADER1_ES6.h"
2020-06-06 20:52:20 +01:00
# else
2022-04-03 14:01:47 +01:00
# include "./html_uncompressed/HTTP_HEADER1_ES6.h"
2020-12-29 09:53:15 +00:00
# endif
2018-11-10 16:30:23 +00:00
const char HTTP_SCRIPT_COUNTER [ ] PROGMEM =
2019-02-18 10:35:49 +00:00
" var cn=180; " // seconds
2018-10-10 21:21:44 +01:00
" function u(){ "
" if(cn>=0){ "
" eb('t').innerHTML=' " D_RESTART_IN " '+cn+' " D_SECONDS " '; "
" cn--; "
" setTimeout(u,1000); "
" } "
" } "
2019-06-02 15:44:02 +01:00
" wl(u); " ;
2018-11-10 16:30:23 +00:00
2020-06-06 20:52:20 +01:00
# ifdef USE_UNISHOX_COMPRESSION
2020-12-29 09:53:15 +00:00
# ifdef USE_SCRIPT_WEB_DISPLAY
# include "./html_compressed/HTTP_SCRIPT_ROOT_WEB_DISPLAY.h"
# else
# include "./html_compressed/HTTP_SCRIPT_ROOT_NO_WEB_DISPLAY.h"
# endif
# include "./html_compressed/HTTP_SCRIPT_ROOT_PART2.h"
2020-06-06 20:52:20 +01:00
# else
2020-12-29 09:53:15 +00:00
# ifdef USE_SCRIPT_WEB_DISPLAY
# include "./html_uncompressed/HTTP_SCRIPT_ROOT_WEB_DISPLAY.h"
# else
2021-02-02 13:57:53 +00:00
# ifdef USE_WEB_SSE
# include "./html_uncompressed/HTTP_SCRIPT_ROOT_SSE_NO_WEB_DISPLAY.h"
# else
# include "./html_uncompressed/HTTP_SCRIPT_ROOT_NO_WEB_DISPLAY.h"
# endif // USE_WEB_SSE
2020-12-29 09:53:15 +00:00
# endif
# include "./html_uncompressed/HTTP_SCRIPT_ROOT_PART2.h"
# endif
2018-11-10 16:30:23 +00:00
const char HTTP_SCRIPT_WIFI [ ] PROGMEM =
" function c(l){ "
" eb('s1').value=l.innerText||l.textContent; "
" eb('p1').focus(); "
" } " ;
2018-10-10 21:21:44 +01:00
2021-04-12 17:36:43 +01:00
const char HTTP_SCRIPT_HIDE [ ] PROGMEM =
2022-04-03 15:45:08 +01:00
" function hidBtns(){ "
2021-04-13 11:52:09 +01:00
" eb('butmo').style.display='none'; "
" eb('butmod').style.display='none'; "
" eb('but0').style.display='block'; "
" eb('but1').style.display='block'; "
" eb('but13').style.display='block'; "
" eb('but0d').style.display='block'; "
" eb('but13d').style.display='block'; "
2021-04-12 17:36:43 +01:00
" } " ;
2020-06-05 10:53:53 +01:00
const char HTTP_SCRIPT_RELOAD_TIME [ ] PROGMEM =
2022-04-06 11:41:06 +01:00
" setTimeout(function(){location.href='.';},%d); " ;
2018-10-10 21:21:44 +01:00
2020-06-06 20:52:20 +01:00
# ifdef USE_UNISHOX_COMPRESSION
2020-12-29 09:53:15 +00:00
# include "./html_compressed/HTTP_SCRIPT_CONSOL.h"
2020-06-06 20:52:20 +01:00
# else
2020-12-29 09:53:15 +00:00
# include "./html_uncompressed/HTTP_SCRIPT_CONSOL.h"
# endif
2020-05-07 17:10:54 +01:00
const char HTTP_MODULE_TEMPLATE_REPLACE_INDEX [ ] PROGMEM =
" }2%d'>%s (%d)}3 " ; // }2 and }3 are used in below os.replace
const char HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX [ ] PROGMEM =
" }2%d'>%s}3 " ; // }2 and }3 are used in below os.replace
2020-06-06 20:52:20 +01:00
# ifdef USE_UNISHOX_COMPRESSION
2020-12-29 09:53:15 +00:00
# include "./html_compressed/HTTP_SCRIPT_MODULE_TEMPLATE.h"
# include "./html_compressed/HTTP_SCRIPT_TEMPLATE.h"
2020-06-06 20:52:20 +01:00
# else
2020-12-29 09:53:15 +00:00
# include "./html_uncompressed/HTTP_SCRIPT_MODULE_TEMPLATE.h"
# include "./html_uncompressed/HTTP_SCRIPT_TEMPLATE.h"
# endif
2023-08-21 15:18:21 +01:00
# ifdef ESP8266
const char HTTP_SCRIPT_TEMPLATE2 [ ] PROGMEM =
" j=0; "
" for(i=0;i< " STR ( MAX_USER_PINS ) " ;i++){ " // Supports 13 GPIOs
" if(6==i){j=9;} "
" if(8==i){j=12;} "
" sk(g[i],j); " // Set GPIO
" j++; "
" } " ;
# endif // ESP8266
# ifdef ESP32
# if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
2021-06-08 19:31:01 +01:00
const char HTTP_SCRIPT_TEMPLATE2 [ ] PROGMEM =
2021-06-14 20:32:07 +01:00
" for(i=0;i< " STR ( MAX_USER_PINS ) " ;i++){ "
" sk(g[i],i); " // Set GPIO
2021-06-08 19:31:01 +01:00
" } " ;
2023-08-21 15:18:21 +01:00
# elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
2021-09-04 13:20:09 +01:00
const char HTTP_SCRIPT_TEMPLATE2 [ ] PROGMEM =
" j=0; "
" for(i=0;i< " STR ( MAX_USER_PINS ) " ;i++){ " // Skip 22-32
" if(22==i){j=33;} "
" sk(g[i],j); " // Set GPIO
" j++; "
" } " ;
2023-08-21 15:18:21 +01:00
# else // ESP32
2021-09-05 18:43:53 +01:00
const char HTTP_SCRIPT_TEMPLATE2 [ ] PROGMEM =
" j=0; "
" for(i=0;i< " STR ( MAX_USER_PINS ) " ;i++){ " // Skip 28-31
" if(28==i){j=32;} "
" sk(g[i],j); " // Set GPIO
" j++; "
" } " ;
2023-08-21 15:18:21 +01:00
# endif // Non plain ESP32
# endif // ESP32
2020-04-25 14:34:18 +01:00
const char HTTP_SCRIPT_TEMPLATE3 [ ] PROGMEM =
" \" ; "
2020-09-29 13:08:48 +01:00
" sk(g[13], " STR ( ADC0_PIN ) " ); " ; // Set ADC0
2020-10-08 17:27:12 +01:00
2020-05-01 15:47:41 +01:00
const char HTTP_SCRIPT_TEMPLATE4 [ ] PROGMEM =
2020-09-29 13:08:48 +01:00
" g=o.shift(); " // FLAG
2019-02-18 14:13:37 +00:00
" for(i=0;i< " STR ( GPIO_FLAG_USED ) " ;i++){ "
2019-02-24 14:05:18 +00:00
" p=(g>>i)&1; "
2019-02-18 10:35:49 +00:00
" eb('c'+i).checked=p; " // Set FLAG checkboxes
" } "
" if( " STR ( USER_MODULE ) " ==c){ "
2019-02-24 14:05:18 +00:00
" g=o.shift(); "
" eb('g99').value=g; " // Set BASE for initial select
2019-02-18 10:35:49 +00:00
" } "
" } "
2019-02-17 10:32:53 +00:00
" function st(t){ "
2019-02-18 10:35:49 +00:00
" c=t; " // Needed for initial BASE select
" var a='tp?t='+t; "
" ld(a,x1); " // ?t related to WebGetArg("t", stemp, sizeof(stemp));
2019-02-17 10:32:53 +00:00
" } "
2020-04-25 14:34:18 +01:00
" function sl(){ "
" os= \" " ; // }2'0'>Sonoff Basic (1)}3...
2020-05-01 15:47:41 +01:00
const char HTTP_SCRIPT_TEMPLATE5 [ ] PROGMEM =
2020-04-25 14:34:18 +01:00
" \" ; "
2020-04-12 17:17:35 +01:00
" sk( " STR ( WEMOS_MODULE ) " ,99); " // 17 = WEMOS
2019-02-18 10:35:49 +00:00
" st( " STR ( USER_MODULE ) " ); "
2018-10-10 21:21:44 +01:00
" } "
2019-06-02 15:44:02 +01:00
" wl(sl); " ;
2019-02-17 10:32:53 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_SCRIPT_INFO_BEGIN [ ] PROGMEM =
" function i(){ "
" var s,o= \" " ;
const char HTTP_SCRIPT_INFO_END [ ] PROGMEM =
2019-05-13 14:56:01 +01:00
" \" ; " // "}1" and "}2" means do not use "}x" in Information text
2018-10-10 21:21:44 +01:00
" s=o.replace(/}1/g, \" </td></tr><tr><th> \" ).replace(/}2/g, \" </th><td> \" ); "
" eb('i').innerHTML=s; "
" } "
2019-06-02 15:44:02 +01:00
" wl(i); " ;
2020-06-06 20:52:20 +01:00
# ifdef USE_UNISHOX_COMPRESSION
2020-12-29 09:53:15 +00:00
# include "./html_compressed/HTTP_HEAD_LAST_SCRIPT.h"
2022-05-02 16:25:31 +01:00
# include "./html_compressed/HTTP_HEAD_LAST_SCRIPT32.h"
2020-12-29 09:53:15 +00:00
# include "./html_compressed/HTTP_HEAD_STYLE1.h"
# include "./html_compressed/HTTP_HEAD_STYLE2.h"
2020-06-06 20:52:20 +01:00
# else
2020-12-29 09:53:15 +00:00
# include "./html_uncompressed/HTTP_HEAD_LAST_SCRIPT.h"
2022-05-02 16:25:31 +01:00
# include "./html_uncompressed/HTTP_HEAD_LAST_SCRIPT32.h"
2020-12-29 09:53:15 +00:00
# include "./html_uncompressed/HTTP_HEAD_STYLE1.h"
# include "./html_uncompressed/HTTP_HEAD_STYLE2.h"
# endif
2020-06-06 20:52:20 +01:00
2020-08-24 20:07:03 +01:00
# ifdef USE_ZIGBEE
// Styles used for Zigbee Web UI
// Battery icon from https://css.gg/battery
//
2020-12-29 09:53:15 +00:00
# ifdef USE_UNISHOX_COMPRESSION
# include "./html_compressed/HTTP_HEAD_STYLE_ZIGBEE.h"
# else
# include "./html_uncompressed/HTTP_HEAD_STYLE_ZIGBEE.h"
# endif
2020-08-24 20:07:03 +01:00
# endif // USE_ZIGBEE
2020-12-27 15:25:34 +00:00
const char HTTP_HEAD_STYLE_SSI [ ] PROGMEM =
// Signal Strength Indicator
" .si{display:inline-flex;align-items:flex-end;height:15px;padding:0} "
" .si i{width:3px;margin-right:1px;border-radius:3px;background-color:#%06x} "
" .si .b0{height:25%%}.si .b1{height:50%%}.si .b2{height:75%%}.si .b3{height:100%%}.o30{opacity:.3} " ;
2019-03-04 17:16:07 +00:00
const char HTTP_HEAD_STYLE3 [ ] PROGMEM =
2018-11-10 16:30:23 +00:00
" </style> "
" </head> "
" <body> "
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
" <div style='text-align:left;display:inline-block;color:#%06x;min-width:340px;'> " // COLOR_TEXT
2019-02-08 13:55:45 +00:00
# ifdef FIRMWARE_MINIMAL
2022-05-05 10:19:39 +01:00
# ifdef FIRMWARE_SAFEBOOT
" <span style='text-align:center;color:#%06x;'><h3> " D_SAFEBOOT " </h3></span> " // COLOR_TEXT_WARNING
2022-05-03 10:19:02 +01:00
# else
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
" <div style='text-align:center;color:#%06x;'><h3> " D_MINIMAL_FIRMWARE_PLEASE_UPGRADE " </h3></div> " // COLOR_TEXT_WARNING
2022-05-05 10:19:39 +01:00
# endif // FIRMWARE_SAFEBOOT
2022-05-04 09:07:24 +01:00
# endif // FIRMWARE_MINIMAL
2019-11-02 04:33:40 +00:00
" <div style='text-align:center;color:#%06x;'><noscript> " D_NOSCRIPT " <br></noscript> " // COLOR_TITLE
2021-03-21 13:23:02 +00:00
/*
2018-11-10 16:30:23 +00:00
# ifdef LANGUAGE_MODULE_NAME
2019-03-04 17:16:07 +00:00
" <h3> " D_MODULE " %s</h3> "
2018-11-10 16:30:23 +00:00
# else
2019-03-04 17:16:07 +00:00
" <h3>%s " D_MODULE " </h3> "
2018-11-10 16:30:23 +00:00
# endif
2021-03-21 13:23:02 +00:00
*/
" <h3>%s</h3> " // Module name
" <h2>%s</h2> " ; // Device name
2019-03-04 17:16:07 +00:00
2019-11-22 16:24:56 +00:00
const char HTTP_MSG_SLIDER_GRADIENT [ ] PROGMEM =
2019-11-25 14:20:44 +00:00
" <div id='%s' class='r' style='background-image:linear-gradient(to right,%s,%s);'> "
" <input id='sl%d' type='range' min='%d' max='%d' value='%d' onchange='lc( \" %c \" ,%d,value)'> "
" </div> " ;
2019-11-22 16:01:11 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_MSG_RSTRT [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <br><div style='text-align:center;'> " D_DEVICE_WILL_RESTART " </div><br> " ;
2019-02-13 15:05:25 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_LOGIN [ ] PROGMEM =
2019-03-07 17:18:30 +00:00
" <fieldset> "
2018-10-10 21:21:44 +01:00
" <form method='post' action='/'> "
2019-05-31 17:24:56 +01:00
" <p><b> " D_USER " </b><br><input name='USER1' placeholder=' " D_USER " '></p> "
" <p><b> " D_PASSWORD " </b><br><input name='PASS1' type='password' placeholder=' " D_PASSWORD " '></p> "
" <br> "
2019-03-07 17:18:30 +00:00
" <button> " D_OK " </button> "
" </form></fieldset> " ;
2019-02-13 15:05:25 +00:00
2019-02-17 10:32:53 +00:00
const char HTTP_FORM_TEMPLATE [ ] PROGMEM =
" <fieldset><legend><b> " D_TEMPLATE_PARAMETERS " </b></legend> "
2019-03-15 13:10:42 +00:00
" <form method='get' action='tp'> " ;
2019-02-17 10:32:53 +00:00
const char HTTP_FORM_TEMPLATE_FLAG [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <p></p> " // Keep close so do not use <br>
2019-02-17 10:32:53 +00:00
" <fieldset><legend><b> " D_TEMPLATE_FLAGS " </b></legend><p> "
2020-04-05 13:11:49 +01:00
// "<label><input id='c0' name='c0' type='checkbox'><b>" D_OPTION_TEXT "</b></label><br>"
2019-02-17 10:32:53 +00:00
" </p></fieldset> " ;
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_MODULE [ ] PROGMEM =
2019-02-17 10:32:53 +00:00
" <fieldset><legend><b> " D_MODULE_PARAMETERS " </b></legend> "
" <form method='get' action='md'> "
2019-06-02 15:44:02 +01:00
" <p></p><b> " D_MODULE_TYPE " </b> (%s)<br><select id='g99'></select><br> "
2019-05-31 17:24:56 +01:00
" <br><table> " ;
2019-01-07 15:33:18 +00:00
2021-04-13 11:00:42 +01:00
const char HTTP_FORM_WIFI_PART1 [ ] PROGMEM =
2021-04-12 17:36:43 +01:00
" <fieldset><legend><b> " D_WIFI_PARAMETERS " </b></legend> "
" <form method='get' action='wi'> "
2021-04-13 11:00:42 +01:00
" <p><b> " D_AP1_SSID " </b>%s<br><input id='s1' placeholder= \" " D_AP1_SSID_HELP " \" value= \" %s \" ></p> " // Need \" instead of ' to be able to use ' in text (#8489)
" <p><label><b> " D_AP_PASSWORD " </b><input type='checkbox' onclick='sp( \" p1 \" )'></label><br><input id='p1' type='password' placeholder= \" " D_AP_PASSWORD_HELP " \" " ;
2021-04-12 17:36:43 +01:00
2021-04-13 11:00:42 +01:00
const char HTTP_FORM_WIFI_PART2 [ ] PROGMEM =
" value= \" " D_ASTERISK_PWD " \" ></p> "
2021-04-12 17:36:43 +01:00
" <p><b> " D_AP2_SSID " </b> ( " STA_SSID2 " )<br><input id='s2' placeholder= \" " D_AP2_SSID_HELP " \" value= \" %s \" ></p> "
" <p><label><b> " D_AP_PASSWORD " </b><input type='checkbox' onclick='sp( \" p2 \" )'></label><br><input id='p2' type='password' placeholder= \" " D_AP_PASSWORD_HELP " \" value= \" " D_ASTERISK_PWD " \" ></p> "
2020-05-21 16:49:59 +01:00
" <p><b> " D_HOSTNAME " </b> (%s)<br><input id='h' placeholder= \" %s \" value= \" %s \" ></p> "
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
" <p><b> " D_CORS_DOMAIN " </b><input id='c' placeholder= \" " CORS_DOMAIN " \" value= \" %s \" ></p> "
# endif
;
2019-02-13 15:05:25 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_LOG1 [ ] PROGMEM =
2019-02-13 15:05:25 +00:00
" <fieldset><legend><b> " D_LOGGING_PARAMETERS " </b> "
" </legend><form method='get' action='lg'> " ;
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_LOG2 [ ] PROGMEM =
2020-05-21 16:49:59 +01:00
" <p><b> " D_SYSLOG_HOST " </b> ( " SYS_LOG_HOST " )<br><input id='lh' placeholder= \" " SYS_LOG_HOST " \" value= \" %s \" ></p> "
2019-05-31 17:24:56 +01:00
" <p><b> " D_SYSLOG_PORT " </b> ( " STR ( SYS_LOG_PORT ) " )<br><input id='lp' placeholder=' " STR ( SYS_LOG_PORT ) " ' value='%d'></p> "
" <p><b> " D_TELEMETRY_PERIOD " </b> ( " STR ( TELE_PERIOD ) " )<br><input id='lt' placeholder=' " STR ( TELE_PERIOD ) " ' value='%d'></p> " ;
2019-02-13 15:05:25 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_OTHER [ ] PROGMEM =
2019-02-13 15:05:25 +00:00
" <fieldset><legend><b> " D_OTHER_PARAMETERS " </b></legend> "
" <form method='get' action='co'> "
" <p></p> "
" <fieldset><legend><b> " D_TEMPLATE " </b></legend> "
2020-05-26 16:38:34 +01:00
" <p><input id='t1' placeholder= \" " D_TEMPLATE " \" value='%s'></p> " // We need ' apostrophe here as the template contains " quotation mark
2020-04-05 13:11:49 +01:00
" <p><label><input id='t2' type='checkbox'%s><b> " D_ACTIVATE " </b></label></p> "
2019-02-13 15:05:25 +00:00
" </fieldset> "
" <br> "
2020-05-21 16:49:59 +01:00
" <label><b> " D_WEB_ADMIN_PASSWORD " </b><input type='checkbox' onclick='sp( \" wp \" )'></label><br><input id='wp' type='password' placeholder= \" " D_WEB_ADMIN_PASSWORD " \" value= \" " D_ASTERISK_PWD " \" ><br> "
2019-05-31 17:24:56 +01:00
" <br> "
2021-08-20 14:54:26 +01:00
" <label><input id='b3' type='checkbox'%s><b> " D_HTTP_API_ENABLE " </b></label><br> "
2020-04-05 13:11:49 +01:00
" <label><input id='b1' type='checkbox'%s><b> " D_MQTT_ENABLE " </b></label><br> "
2020-05-17 16:10:17 +01:00
" <br> "
2020-05-21 16:49:59 +01:00
" <label><b> " D_DEVICE_NAME " </b> (%s)</label><br><input id='dn' placeholder= \" \" value= \" %s \" ><br> "
2019-05-31 17:24:56 +01:00
" <br> " ;
2019-02-13 15:05:25 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_END [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <br> "
2019-02-13 15:05:25 +00:00
" <button name='save' type='submit' class='button bgrn'> " D_SAVE " </button> "
" </form></fieldset> " ;
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_RST [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <div id='f1' style='display:block;'> "
2018-10-10 21:21:44 +01:00
" <fieldset><legend><b> " D_RESTORE_CONFIGURATION " </b></legend> " ;
const char HTTP_FORM_UPG [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <div id='f1' style='display:block;'> "
2018-10-10 21:21:44 +01:00
" <fieldset><legend><b> " D_UPGRADE_BY_WEBSERVER " </b></legend> "
" <form method='get' action='u1'> "
2020-05-21 16:49:59 +01:00
" <br><b> " D_OTA_URL " </b><br><input id='o' placeholder= \" OTA_URL \" value= \" %s \" ><br> "
2019-05-31 17:24:56 +01:00
" <br><button type='submit'> " D_START_UPGRADE " </button></form> "
" </fieldset><br><br> "
2018-10-10 21:21:44 +01:00
" <fieldset><legend><b> " D_UPGRADE_BY_FILE_UPLOAD " </b></legend> " ;
const char HTTP_FORM_RST_UPG [ ] PROGMEM =
2022-05-13 08:30:31 +01:00
" <form method='post' action='u2?fsz=' enctype='multipart/form-data'> "
2022-11-24 13:47:26 +00:00
" <br><input type='file' name='u2'><br> "
2022-05-13 08:30:31 +01:00
" <br><button type='submit' "
" onclick='eb( \" f1 \" ).style.display= \" none \" ;eb( \" f2 \" ).style.display= \" block \" ;this.form.action+=this.form[ \" u2 \" ].files[0].size;this.form.submit();' "
" > " D_START " %s</button></form> "
2018-10-10 21:21:44 +01:00
" </fieldset> "
" </div> "
2022-05-02 20:25:35 +01:00
" <div id='f2' style='display:none;text-align:center;'><b> " D_UPLOAD_STARTED " ...</b></div> " ;
2019-03-04 17:16:07 +00:00
2022-05-02 16:25:31 +01:00
// upload via factory partition
const char HTTP_FORM_RST_UPG_FCT [ ] PROGMEM =
2022-05-13 08:30:31 +01:00
" <form method='post' action='u2?fsz=' enctype='multipart/form-data'> "
2022-11-24 13:47:26 +00:00
" <br><input type='file' name='u2'><br> "
2022-05-13 08:30:31 +01:00
" <br><button type='submit' "
" onclick='eb( \" f1 \" ).style.display= \" none \" ;eb( \" f3 \" ).style.display= \" block \" ;this.form.action+=this.form[ \" u2 \" ].files[0].size;return upl(this);' "
" > " D_START " %s</button></form> "
2022-05-02 16:25:31 +01:00
" </fieldset> "
" </div> "
2022-05-02 20:25:35 +01:00
" <div id='f3' style='display:none;text-align:center;'><b> " D_UPLOAD_FACTORY " ...</b></div> "
" <div id='f2' style='display:none;text-align:center;'><b> " D_UPLOAD_STARTED " ...</b></div> " ;
2022-05-02 16:25:31 +01:00
2023-08-04 15:11:58 +01:00
# ifdef USE_CONSOLE_CSS_FLEX
const char HTTP_CMND_STYLE [ ] PROGMEM = // Overrule CSS for flex console
2023-08-04 16:24:05 +01:00
" html,body{height:99%%;} "
" body{display:flex;flex-flow:column;} "
2023-08-05 10:56:06 +01:00
" textarea{resize:none;flex:auto;min-height:99px} " ;
2023-08-04 15:11:58 +01:00
const char HTTP_FORM_CMND [ ] PROGMEM =
" </div> " // Close HTTP_HEAD_STYLE3 <div>
2023-08-05 11:35:03 +01:00
" <textarea readonly id='t1' wrap='off'></textarea> "
2023-08-04 15:11:58 +01:00
" <form method='get' onsubmit='return l(1);'> "
2023-08-05 11:35:03 +01:00
" <br> " // <br> here fixes Firefox layout
" <input id='c1' placeholder=' " D_ENTER_COMMAND " ' autofocus> "
2023-08-04 15:11:58 +01:00
// "<br><button type='submit'>Send command</button>"
" </form> "
" <div style='padding:0;'> " ; // Add dummy <div> replacing HTTP_HEAD_STYLE3 closed <div>
# else
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_CMND [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <br><textarea readonly id='t1' cols='340' wrap='off'></textarea><br><br> "
2018-10-10 21:21:44 +01:00
" <form method='get' onsubmit='return l(1);'> "
2019-05-31 17:24:56 +01:00
" <input id='c1' placeholder=' " D_ENTER_COMMAND " ' autofocus><br> "
// "<br><button type='submit'>Send command</button>"
2018-10-10 21:21:44 +01:00
" </form> " ;
2023-08-04 15:11:58 +01:00
# endif // USE_CONSOLE_CSS_FLEX
2019-03-04 17:16:07 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_TABLE100 [ ] PROGMEM =
2019-03-10 14:36:34 +00:00
" <table style='width:100%%'> " ;
2019-03-04 17:16:07 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_COUNTER [ ] PROGMEM =
2019-05-31 17:24:56 +01:00
" <br><div id='t' style='text-align:center;'></div> " ;
2019-03-04 17:16:07 +00:00
2018-10-10 21:21:44 +01:00
const char HTTP_END [ ] PROGMEM =
2019-10-27 10:13:24 +00:00
" <div style='text-align:right;font-size:11px;'><hr/><a href='https://bit.ly/tasmota' target='_blank' style='color:#aaa;'>Tasmota %s " D_BY " Theo Arends</a></div> "
2018-10-10 21:21:44 +01:00
" </div> "
" </body> "
" </html> " ;
2022-01-05 09:44:58 +00:00
const char HTTP_DEVICE_CONTROL [ ] PROGMEM = " <td style='width:%d%%'><button onclick='la( \" &o=%d \" );'>%s%s</button></td> " ; // ?o is related to WebGetArg(PSTR("o"), tmp, sizeof(tmp))
2021-04-03 15:17:48 +01:00
const char HTTP_DEVICE_STATE [ ] PROGMEM = " <td style='width:%d%%;text-align:center;font-weight:%s;font-size:%dpx'>%s</td> " ;
2018-10-10 21:21:44 +01:00
2019-03-11 09:38:41 +00:00
enum ButtonTitle {
BUTTON_RESTART , BUTTON_RESET_CONFIGURATION ,
2021-04-16 10:40:38 +01:00
BUTTON_MAIN , BUTTON_CONFIGURATION , BUTTON_INFORMATION , BUTTON_FIRMWARE_UPGRADE , BUTTON_MANAGEMENT ,
BUTTON_MODULE , BUTTON_WIFI , BUTTON_LOGGING , BUTTON_OTHER , BUTTON_TEMPLATE , BUTTON_BACKUP , BUTTON_RESTORE ,
BUTTON_CONSOLE } ;
2019-03-11 09:38:41 +00:00
const char kButtonTitle [ ] PROGMEM =
D_RESTART " | " D_RESET_CONFIGURATION " | "
2021-04-16 10:40:38 +01:00
D_MAIN_MENU " | " D_CONFIGURATION " | " D_INFORMATION " | " D_FIRMWARE_UPGRADE " | " D_MANAGEMENT " | "
D_CONFIGURE_MODULE " | " D_CONFIGURE_WIFI " | " D_CONFIGURE_LOGGING " | " D_CONFIGURE_OTHER " | " D_CONFIGURE_TEMPLATE " | " D_BACKUP_CONFIGURATION " | " D_RESTORE_CONFIGURATION " | "
D_CONSOLE ;
2019-03-11 09:38:41 +00:00
const char kButtonAction [ ] PROGMEM =
" .|rt| "
2021-04-16 10:40:38 +01:00
" .|cn|in|up|mn| "
" md|wi|lg|co|tp|dl|rs| "
" cs " ;
2019-03-11 09:38:41 +00:00
const char kButtonConfirm [ ] PROGMEM = D_CONFIRM_RESTART " | " D_CONFIRM_RESET_CONFIGURATION ;
2021-02-02 13:57:53 +00:00
enum CTypes { CT_HTML , CT_PLAIN , CT_XML , CT_STREAM , CT_APP_JSON , CT_APP_STREAM } ;
const char kContentTypes [ ] PROGMEM = " text/html|text/plain|text/xml|text/event-stream|application/json|application/octet-stream " ;
2018-10-10 21:21:44 +01:00
2019-10-03 13:45:24 +01:00
const char kLoggingOptions [ ] PROGMEM = D_SERIAL_LOG_LEVEL " | " D_WEB_LOG_LEVEL " | " D_MQTT_LOG_LEVEL " | " D_SYS_LOG_LEVEL ;
2019-03-04 17:16:07 +00:00
const char kLoggingLevels [ ] PROGMEM = D_NONE " | " D_ERROR " | " D_INFO " | " D_DEBUG " | " D_MORE_DEBUG ;
const char kEmulationOptions [ ] PROGMEM = D_NONE " | " D_BELKIN_WEMO " | " D_HUE_BRIDGE ;
2019-02-23 12:17:02 +00:00
const char kUploadErrors [ ] PROGMEM =
2021-07-22 14:14:58 +01:00
// D_UPLOAD_ERR_1 "|" D_UPLOAD_ERR_2 "|" D_UPLOAD_ERR_3 "|" D_UPLOAD_ERR_4 "|" D_UPLOAD_ERR_5 "|" D_UPLOAD_ERR_6 "|" D_UPLOAD_ERR_7 "|" D_UPLOAD_ERR_8 "|" D_UPLOAD_ERR_9;
D_UPLOAD_ERR_1 " | " D_UPLOAD_ERR_2 " | " D_UPLOAD_ERR_3 " | " D_UPLOAD_ERR_4 " | | " D_UPLOAD_ERR_6 " | " D_UPLOAD_ERR_7 " | " D_UPLOAD_ERR_8 " | " D_UPLOAD_ERR_9 ;
2019-02-23 12:17:02 +00:00
2019-03-31 10:59:04 +01:00
const uint16_t DNS_PORT = 53 ;
2022-08-03 06:35:16 +01:00
enum HttpOptions { HTTP_OFF , HTTP_USER , HTTP_ADMIN , HTTP_MANAGER , HTTP_MANAGER_RESET_ONLY } ;
2021-09-01 20:30:54 +01:00
enum WebCmndStatus { WEBCMND_DONE = 0 , WEBCMND_WRONG_PARAMETERS , WEBCMND_CONNECT_FAILED , WEBCMND_HOST_NOT_FOUND , WEBCMND_MEMORY_ERROR
# ifdef USE_WEBGETCONFIG
, WEBCMND_FILE_NOT_FOUND , WEBCMND_OTHER_HTTP_ERROR , WEBCMND_CONNECTION_LOST , WEBCMND_INVALID_FILE
# endif // USE_WEBGETCONFIG
2022-08-03 06:35:16 +01:00
} ;
2021-09-01 20:30:54 +01:00
2018-10-10 21:21:44 +01:00
DNSServer * DnsServer ;
2020-04-15 08:58:38 +01:00
ESP8266WebServer * Webserver ;
2018-10-10 21:21:44 +01:00
2019-08-15 12:50:28 +01:00
struct WEB {
String chunk_buffer = " " ; // Could be max 2 * CHUNKED_BUFFER_SIZE
2022-05-13 08:30:31 +01:00
uint32_t upload_size = 0 ;
2020-12-08 16:24:52 +00:00
uint16_t upload_error = 0 ;
2019-08-15 12:50:28 +01:00
uint8_t state = HTTP_OFF ;
uint8_t upload_file_type ;
uint8_t config_block_count = 0 ;
2021-01-10 16:46:30 +00:00
bool upload_services_stopped = false ;
2020-11-28 17:12:29 +00:00
bool reset_web_log_flag = false ; // Reset web console log
2021-04-12 17:36:43 +01:00
bool initial_config = false ;
2019-08-15 12:50:28 +01:00
} Web ;
2018-10-10 21:21:44 +01:00
// Helper function to avoid code duplication (saves 4k Flash)
2021-01-18 20:48:04 +00:00
// arg can be in PROGMEM
2018-10-10 21:21:44 +01:00
static void WebGetArg ( const char * arg , char * out , size_t max )
{
2021-01-18 20:48:04 +00:00
String s = Webserver - > arg ( ( const __FlashStringHelper * ) arg ) ;
2018-10-10 21:21:44 +01:00
strlcpy ( out , s . c_str ( ) , max ) ;
// out[max-1] = '\0'; // Ensure terminating NUL
}
2021-05-03 15:15:47 +01:00
String AddWebCommand ( const char * command , const char * arg , const char * dflt ) {
2021-05-04 15:35:21 +01:00
/*
2021-05-03 15:15:47 +01:00
// OK but fixed max argument
char param [ 200 ] ; // Allow parameter with lenght up to 199 characters
WebGetArg ( arg , param , sizeof ( param ) ) ;
uint32_t len = strlen ( param ) ;
char cmnd [ 232 ] ;
snprintf_P ( cmnd , sizeof ( cmnd ) , PSTR ( " ;%s %s " ) , command , ( 0 = = len ) ? dflt : ( StrCaseStr_P ( command , PSTR ( " Password " ) ) & & ( len < 5 ) ) ? " " : param ) ;
2021-05-03 11:49:41 +01:00
return String ( cmnd ) ;
2021-05-04 15:35:21 +01:00
*/
2021-05-03 15:15:47 +01:00
/*
// Any argument size (within stack space) +48 bytes
String param = Webserver - > arg ( ( const __FlashStringHelper * ) arg ) ;
uint32_t len = param . length ( ) ;
// char cmnd[len + strlen_P(command) + strlen_P(dflt) + 4];
char cmnd [ 64 + len ] ;
snprintf_P ( cmnd , sizeof ( cmnd ) , PSTR ( " ;%s %s " ) , command , ( 0 = = len ) ? dflt : ( StrCaseStr_P ( command , PSTR ( " Password " ) ) & & ( len < 5 ) ) ? " " : param . c_str ( ) ) ;
return String ( cmnd ) ;
*/
2021-05-04 15:35:21 +01:00
// Any argument size (within heap space) +24 bytes
// Exception (3) if not first moved from flash to stack
// Exception (3) if not using __FlashStringHelper
// Exception (3) if not FPSTR()
// char rcommand[strlen_P(command) +1];
// snprintf_P(rcommand, sizeof(rcommand), command);
// char rdflt[strlen_P(dflt) +1];
// snprintf_P(rdflt, sizeof(rdflt), dflt);
2021-05-03 15:15:47 +01:00
String result = F ( " ; " ) ;
2021-05-04 15:35:21 +01:00
// result += rcommand;
// result += (const __FlashStringHelper *)command;
result + = FPSTR ( command ) ;
2021-05-03 15:15:47 +01:00
result + = F ( " " ) ;
2021-05-04 15:35:21 +01:00
String param = Webserver - > arg ( FPSTR ( arg ) ) ;
2021-05-03 15:15:47 +01:00
uint32_t len = param . length ( ) ;
if ( 0 = = len ) {
2021-05-04 15:35:21 +01:00
// result += rdflt;
// result += (const __FlashStringHelper *)dflt;
result + = FPSTR ( dflt ) ;
2021-05-03 15:15:47 +01:00
}
else if ( ! ( StrCaseStr_P ( command , PSTR ( " Password " ) ) & & ( len < 5 ) ) ) {
result + = param ;
}
return result ;
2021-05-03 11:49:41 +01:00
}
2019-02-21 16:49:11 +00:00
static bool WifiIsInManagerMode ( ) {
2019-08-15 12:50:28 +01:00
return ( HTTP_MANAGER = = Web . state | | HTTP_MANAGER_RESET_ONLY = = Web . state ) ;
2019-02-21 16:49:11 +00:00
}
2019-09-04 11:58:37 +01:00
void ShowWebSource ( uint32_t source )
2018-10-10 21:21:44 +01:00
{
if ( ( source > 0 ) & & ( source < SRC_MAX ) ) {
char stemp1 [ 20 ] ;
2021-01-27 11:03:20 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " SRC: %s from %_I " ) , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , source , kCommandSource ) , ( uint32_t ) Webserver - > client ( ) . remoteIP ( ) ) ;
2018-10-10 21:21:44 +01:00
}
}
2021-04-07 17:10:34 +01:00
void ExecuteWebCommand ( char * svalue , uint32_t source ) {
2018-10-10 21:21:44 +01:00
ShowWebSource ( source ) ;
2020-10-30 11:29:48 +00:00
TasmotaGlobal . last_source = source ;
2018-10-10 21:21:44 +01:00
ExecuteCommand ( svalue , SRC_IGNORE ) ;
}
2021-04-07 17:10:34 +01:00
void ExecuteWebCommand ( char * svalue ) {
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2020-10-19 18:35:58 +01:00
// replace the series of `Webserver->on()` with a table in PROGMEM
typedef struct WebServerDispatch_t {
char uri [ 3 ] ; // the prefix "/" is added automatically
uint8_t method ;
void ( * handler ) ( void ) ;
} WebServerDispatch_t ;
const WebServerDispatch_t WebServerDispatch [ ] PROGMEM = {
{ " " , HTTP_ANY , HandleRoot } ,
{ " up " , HTTP_ANY , HandleUpgradeFirmware } ,
{ " u1 " , HTTP_ANY , HandleUpgradeFirmwareStart } , // OTA
{ " u2 " , HTTP_OPTIONS , HandlePreflightRequest } ,
{ " u3 " , HTTP_ANY , HandleUploadDone } ,
2022-05-01 22:16:21 +01:00
# ifdef ESP32
2022-05-05 18:13:58 +01:00
{ " u4 " , HTTP_GET , HandleSwitchBootPartition } ,
2022-05-01 22:16:21 +01:00
# endif // ESP32
2021-04-16 10:40:38 +01:00
{ " mn " , HTTP_GET , HandleManagement } ,
2020-10-19 18:35:58 +01:00
{ " cs " , HTTP_GET , HandleConsole } ,
{ " cs " , HTTP_OPTIONS , HandlePreflightRequest } ,
{ " cm " , HTTP_ANY , HandleHttpCommand } ,
# ifndef FIRMWARE_MINIMAL
{ " cn " , HTTP_ANY , HandleConfiguration } ,
{ " md " , HTTP_ANY , HandleModuleConfiguration } ,
{ " wi " , HTTP_ANY , HandleWifiConfiguration } ,
{ " lg " , HTTP_ANY , HandleLoggingConfiguration } ,
{ " tp " , HTTP_ANY , HandleTemplateConfiguration } ,
{ " co " , HTTP_ANY , HandleOtherConfiguration } ,
{ " dl " , HTTP_ANY , HandleBackupConfiguration } ,
{ " rs " , HTTP_ANY , HandleRestoreConfiguration } ,
{ " rt " , HTTP_ANY , HandleResetConfiguration } ,
# endif // Not FIRMWARE_MINIMAL
2022-05-15 11:31:27 +01:00
# ifndef FIRMWARE_MINIMAL_ONLY
{ " in " , HTTP_ANY , HandleInformation } ,
# endif // Not FIRMWARE_MINIMAL_ONLY
2020-10-19 18:35:58 +01:00
} ;
2020-10-20 17:56:18 +01:00
void WebServer_on ( const char * prefix , void ( * func ) ( void ) , uint8_t method = HTTP_ANY ) {
2021-05-29 13:27:01 +01:00
if ( Webserver = = nullptr ) { return ; }
2020-10-31 16:28:33 +00:00
# ifdef ESP8266
2020-10-20 17:56:18 +01:00
Webserver - > on ( ( const __FlashStringHelper * ) prefix , ( HTTPMethod ) method , func ) ;
2020-11-28 15:39:15 +00:00
# endif // ESP8266
# ifdef ESP32
2020-10-31 16:28:33 +00:00
Webserver - > on ( prefix , ( HTTPMethod ) method , func ) ;
2020-11-28 15:39:15 +00:00
# endif // ESP32
2020-10-20 17:56:18 +01:00
}
2022-12-27 20:59:34 +00:00
// Always listens to all interfaces, so we don't need an IP address anymore
void StartWebserver ( int type )
2018-10-10 21:21:44 +01:00
{
2021-06-11 17:14:12 +01:00
if ( ! Settings - > web_refresh ) { Settings - > web_refresh = HTTP_REFRESH_TIME ; }
2019-08-15 12:50:28 +01:00
if ( ! Web . state ) {
2020-04-15 08:58:38 +01:00
if ( ! Webserver ) {
Webserver = new ESP8266WebServer ( ( HTTP_MANAGER = = type | | HTTP_MANAGER_RESET_ONLY = = type ) ? 80 : WEB_PORT ) ;
2021-08-15 12:15:33 +01:00
2021-08-15 14:51:29 +01:00
const char * headerkeys [ ] = { " Referer " } ;
size_t headerkeyssize = sizeof ( headerkeys ) / sizeof ( char * ) ;
Webserver - > collectHeaders ( headerkeys , headerkeyssize ) ;
2021-08-15 12:15:33 +01:00
2020-10-19 18:35:58 +01:00
// call `Webserver->on()` on each entry
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( WebServerDispatch ) ; i + + ) {
2020-10-19 18:35:58 +01:00
const WebServerDispatch_t & line = WebServerDispatch [ i ] ;
// copy uri in RAM and prefix with '/'
char uri [ 4 ] ;
uri [ 0 ] = ' / ' ;
2020-10-20 17:56:18 +01:00
uri [ 1 ] = pgm_read_byte ( & line . uri [ 0 ] ) ;
uri [ 2 ] = pgm_read_byte ( & line . uri [ 1 ] ) ;
uri [ 3 ] = ' \0 ' ;
2020-10-19 18:35:58 +01:00
// register
2020-10-20 17:56:18 +01:00
WebServer_on ( uri , line . handler , pgm_read_byte ( & line . method ) ) ;
2020-10-19 18:35:58 +01:00
}
2020-04-15 08:58:38 +01:00
Webserver - > onNotFound ( HandleNotFound ) ;
2021-02-03 11:22:17 +00:00
// Webserver->on(F("/u2"), HTTP_POST, HandleUploadDone, HandleUploadLoop); // this call requires 2 functions so we keep a direct call
Webserver - > on ( " /u2 " , HTTP_POST , HandleUploadDone , HandleUploadLoop ) ; // this call requires 2 functions so we keep a direct call
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2022-11-11 08:57:00 +00:00
XdrvXsnsCall ( FUNC_WEB_ADD_HANDLER ) ;
2019-02-08 13:55:45 +00:00
# endif // Not FIRMWARE_MINIMAL
2022-08-03 06:35:16 +01:00
if ( ! Web . initial_config ) {
2022-08-24 16:09:26 +01:00
Web . initial_config = ( ! strlen ( SettingsText ( SET_STASSID1 ) ) & & ! strlen ( SettingsText ( SET_STASSID2 ) ) ) ;
2022-08-03 06:35:16 +01:00
if ( Web . initial_config ) { AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP " Blank Device - Initial Configuration " ) ) ; }
}
2018-10-10 21:21:44 +01:00
}
2019-08-15 12:50:28 +01:00
Web . reset_web_log_flag = false ;
2019-08-06 09:57:50 +01:00
2020-04-15 08:58:38 +01:00
Webserver - > begin ( ) ; // Web server start
2018-10-10 21:21:44 +01:00
}
2019-08-15 12:50:28 +01:00
if ( Web . state ! = type ) {
2022-12-27 20:59:34 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s " ) ,
NetworkHostname ( ) , ( Mdns . begun ) ? PSTR ( " .local " ) : " " , IPGetListeningAddressStr ( ) . c_str ( ) ) ;
2020-10-29 12:58:50 +00:00
TasmotaGlobal . rules_flag . http_init = 1 ;
2021-04-12 17:36:43 +01:00
Web . state = type ;
2018-10-10 21:21:44 +01:00
}
}
2018-11-14 13:32:09 +00:00
void StopWebserver ( void )
2018-10-10 21:21:44 +01:00
{
2019-08-15 12:50:28 +01:00
if ( Web . state ) {
2020-04-15 08:58:38 +01:00
Webserver - > close ( ) ;
2019-08-15 12:50:28 +01:00
Web . state = HTTP_OFF ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP D_WEBSERVER_STOPPED ) ) ;
2018-10-10 21:21:44 +01:00
}
}
2019-02-21 16:49:11 +00:00
void WifiManagerBegin ( bool reset_only )
2018-10-10 21:21:44 +01:00
{
// setup AP
2021-04-12 17:36:43 +01:00
if ( ! Web . initial_config ) { AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_WCFG_2_WIFIMANAGER " " D_ACTIVE_FOR_3_MINUTES ) ) ; }
2020-10-30 11:29:48 +00:00
if ( ! TasmotaGlobal . global_state . wifi_down ) {
2019-11-08 12:00:32 +00:00
WifiSetMode ( WIFI_AP_STA ) ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION ) ) ;
2018-10-10 21:21:44 +01:00
} else {
2019-11-08 12:00:32 +00:00
WifiSetMode ( WIFI_AP ) ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT ) ) ;
2018-10-10 21:21:44 +01:00
}
2021-04-12 17:36:43 +01:00
//StopWebserver();
2018-10-10 21:21:44 +01:00
DnsServer = new DNSServer ( ) ;
2018-12-22 15:13:07 +00:00
int channel = WIFI_SOFT_AP_CHANNEL ;
if ( ( channel < 1 ) | | ( channel > 13 ) ) { channel = 1 ; }
2020-02-10 13:24:53 +00:00
2020-02-10 12:54:27 +00:00
// bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4);
2020-10-30 11:29:48 +00:00
WiFi . softAP ( TasmotaGlobal . hostname , WIFI_AP_PASSPHRASE , channel , 0 , 1 ) ;
2018-10-10 21:21:44 +01:00
delay ( 500 ) ; // Without delay I've seen the IP address blank
/* Setup the DNS server redirecting all the domains to the apIP */
DnsServer - > setErrorReplyCode ( DNSReplyCode : : NoError ) ;
DnsServer - > start ( DNS_PORT , " * " , WiFi . softAPIP ( ) ) ;
2022-12-27 20:59:34 +00:00
StartWebserver ( ( reset_only ? HTTP_MANAGER_RESET_ONLY : HTTP_MANAGER ) ) ;
2018-10-10 21:21:44 +01:00
}
2018-11-14 13:32:09 +00:00
void PollDnsWebserver ( void )
2018-10-10 21:21:44 +01:00
{
if ( DnsServer ) { DnsServer - > processNextRequest ( ) ; }
2020-04-15 08:58:38 +01:00
if ( Webserver ) { Webserver - > handleClient ( ) ; }
2018-10-10 21:21:44 +01:00
}
/*********************************************************************************************/
bool WebAuthenticate ( void )
{
2019-12-16 14:13:57 +00:00
if ( strlen ( SettingsText ( SET_WEBPWD ) ) & & ( HTTP_MANAGER_RESET_ONLY ! = Web . state ) ) {
2020-04-15 08:58:38 +01:00
return Webserver - > authenticate ( WEB_USERNAME , SettingsText ( SET_WEBPWD ) ) ;
2019-03-04 17:16:07 +00:00
} else {
return true ;
2018-10-10 21:21:44 +01:00
}
}
2019-03-04 17:16:07 +00:00
bool HttpCheckPriviledgedAccess ( bool autorequestauth = true )
2018-10-10 21:21:44 +01:00
{
2019-08-15 12:50:28 +01:00
if ( HTTP_USER = = Web . state ) {
2019-03-04 17:16:07 +00:00
HandleRoot ( ) ;
return false ;
2018-10-10 21:21:44 +01:00
}
2019-03-04 17:16:07 +00:00
if ( autorequestauth & & ! WebAuthenticate ( ) ) {
2020-04-15 08:58:38 +01:00
Webserver - > requestAuthentication ( ) ;
2019-03-04 17:16:07 +00:00
return false ;
}
2021-08-15 12:15:33 +01:00
if ( ! Settings - > flag5 . disable_referer_chk & & ! WifiIsInManagerMode ( ) ) {
2021-08-15 14:51:29 +01:00
String referer = Webserver - > header ( F ( " Referer " ) ) ; // http://demo/? or http://192.168.2.153/?
if ( referer . length ( ) ) {
referer . toUpperCase ( ) ;
2022-01-13 14:27:24 +00:00
String hostname = TasmotaGlobal . hostname ;
2021-08-15 14:51:29 +01:00
hostname . toUpperCase ( ) ;
2022-12-27 20:59:34 +00:00
// TODO rework if IPv6
2022-01-13 14:27:24 +00:00
if ( ( referer . indexOf ( hostname ) = = 7 ) | | ( referer . indexOf ( WiFi . localIP ( ) . toString ( ) ) = = 7 ) ) {
2021-08-15 14:51:29 +01:00
return true ;
}
2022-01-13 14:27:24 +00:00
# if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET)
hostname = EthernetHostname ( ) ;
hostname . toUpperCase ( ) ;
2022-12-27 20:59:34 +00:00
// TODO rework if IPv6
2022-01-13 14:27:24 +00:00
if ( ( referer . indexOf ( hostname ) = = 7 ) | | ( referer . indexOf ( EthernetLocalIP ( ) . toString ( ) ) = = 7 ) ) {
return true ;
}
# endif // USE_ETHERNET
2021-08-15 12:15:33 +01:00
}
2021-08-20 14:54:26 +01:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP " Referer '%s' denied. Use 'SO128 1' for HTTP API commands. 'Webpassword' is recommended. " ) , referer . c_str ( ) ) ;
2021-08-15 12:15:33 +01:00
return false ;
} else {
return true ;
}
2019-03-04 17:16:07 +00:00
}
2018-10-10 21:21:44 +01:00
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
2019-10-28 12:36:04 +00:00
void HttpHeaderCors ( void )
{
2019-12-16 14:13:57 +00:00
if ( strlen ( SettingsText ( SET_CORS ) ) ) {
2020-04-15 08:58:38 +01:00
Webserver - > sendHeader ( F ( " Access-Control-Allow-Origin " ) , SettingsText ( SET_CORS ) ) ;
2019-10-28 12:36:04 +00:00
}
}
2021-08-05 16:55:07 +01:00
# endif
2019-10-28 12:36:04 +00:00
2019-03-04 17:16:07 +00:00
void WSHeaderSend ( void )
{
2021-02-04 17:06:34 +00:00
char server [ 32 ] ;
snprintf_P ( server , sizeof ( server ) , PSTR ( " Tasmota/%s (%s) " ) , TasmotaGlobal . version , GetDeviceHardware ( ) . c_str ( ) ) ;
Webserver - > sendHeader ( F ( " Server " ) , server ) ;
2020-04-15 08:58:38 +01:00
Webserver - > sendHeader ( F ( " Cache-Control " ) , F ( " no-cache, no-store, must-revalidate " ) ) ;
Webserver - > sendHeader ( F ( " Pragma " ) , F ( " no-cache " ) ) ;
Webserver - > sendHeader ( F ( " Expires " ) , F ( " -1 " ) ) ;
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
2019-10-28 12:36:04 +00:00
HttpHeaderCors ( ) ;
2021-08-05 16:55:07 +01:00
# endif
2019-03-04 17:16:07 +00:00
}
2019-03-10 14:36:34 +00:00
/**********************************************************************************************
* HTTP Content Page handler
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-03-04 17:16:07 +00:00
void WSSend ( int code , int ctype , const String & content )
{
char ct [ 25 ] ; // strlen("application/octet-stream") +1 = Longest Content type string
2020-04-15 08:58:38 +01:00
Webserver - > send ( code , GetTextIndexed ( ct , sizeof ( ct ) , ctype , kContentTypes ) , content ) ;
2019-03-04 17:16:07 +00:00
}
2019-03-10 14:36:34 +00:00
/**********************************************************************************************
* HTTP Content Chunk handler
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-05-31 15:58:32 +01:00
void WSContentBegin ( int code , int ctype ) {
2020-04-15 08:58:38 +01:00
Webserver - > client ( ) . flush ( ) ;
2019-03-16 15:23:41 +00:00
WSHeaderSend ( ) ;
2020-04-15 08:58:38 +01:00
Webserver - > setContentLength ( CONTENT_LENGTH_UNKNOWN ) ;
2021-05-31 15:58:32 +01:00
WSSend ( code , ctype , " " ) ; // Signal start of chunked content
2019-08-15 12:50:28 +01:00
Web . chunk_buffer = " " ;
2019-03-16 15:23:41 +00:00
}
2021-05-31 15:58:32 +01:00
void _WSContentSend ( const char * content , size_t size ) { // Lowest level sendContent for all core versions
Webserver - > sendContent ( content , size ) ;
2019-03-04 17:16:07 +00:00
2021-06-25 16:09:53 +01:00
SHOW_FREE_MEM ( PSTR ( " WSContentSend " ) ) ;
2021-06-04 10:04:52 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Chunk size %d " ) , size ) ;
2019-03-04 17:16:07 +00:00
}
2021-05-31 15:58:32 +01:00
void _WSContentSend ( const String & content ) { // Low level sendContent for all core versions
_WSContentSend ( content . c_str ( ) , content . length ( ) ) ;
}
void WSContentFlush ( void ) {
2019-08-15 12:50:28 +01:00
if ( Web . chunk_buffer . length ( ) > 0 ) {
2021-05-31 15:58:32 +01:00
_WSContentSend ( Web . chunk_buffer ) ; // Flush chunk buffer
2019-08-15 12:50:28 +01:00
Web . chunk_buffer = " " ;
2019-03-04 17:16:07 +00:00
}
}
2021-06-19 14:22:17 +01:00
void _WSContentSendBufferChunk ( const char * content ) {
int len = strlen ( content ) ;
if ( len < CHUNKED_BUFFER_SIZE ) { // Append chunk buffer with small content
Web . chunk_buffer + = content ;
len = Web . chunk_buffer . length ( ) ;
}
if ( len > = CHUNKED_BUFFER_SIZE ) { // Either content or chunk buffer is oversize
WSContentFlush ( ) ; // Send chunk buffer before possible content oversize
}
if ( strlen ( content ) > = CHUNKED_BUFFER_SIZE ) { // Content is oversize
_WSContentSend ( content ) ; // Send content
}
}
2021-06-04 16:16:04 +01:00
void WSContentSend ( const char * content , size_t size ) {
2021-06-19 14:22:17 +01:00
// To speed up transmission use chunked buffer if possible
if ( size < CHUNKED_BUFFER_SIZE ) {
// Terminate non-terminated content
char buffer [ size + 1 ] ;
strlcpy ( buffer , content , sizeof ( buffer ) ) ; // Terminate with '\0'
_WSContentSendBufferChunk ( buffer ) ;
} else {
WSContentFlush ( ) ; // Flush chunk buffer
_WSContentSend ( content , size ) ;
}
2021-06-04 16:16:04 +01:00
}
void _WSContentSendBuffer ( bool decimal , const char * formatP , va_list arg ) {
char * content = ext_vsnprintf_malloc_P ( formatP , arg ) ;
2021-06-04 10:04:52 +01:00
if ( content = = nullptr ) { return ; } // Avoid crash
2019-03-04 17:16:07 +00:00
2021-06-04 10:04:52 +01:00
int len = strlen ( content ) ;
2021-06-04 16:16:04 +01:00
if ( 0 = = len ) { return ; } // No content
if ( decimal & & ( D_DECIMAL_SEPARATOR [ 0 ] ! = ' . ' ) ) {
for ( uint32_t i = 0 ; i < len ; i + + ) {
if ( ' . ' = = content [ i ] ) {
content [ i ] = D_DECIMAL_SEPARATOR [ 0 ] ;
}
}
2019-03-04 17:16:07 +00:00
}
2021-06-04 16:16:04 +01:00
2021-06-19 14:22:17 +01:00
_WSContentSendBufferChunk ( content ) ;
2021-06-04 16:16:04 +01:00
free ( content ) ;
2021-05-31 15:58:32 +01:00
}
2021-06-04 10:04:52 +01:00
void WSContentSend_P ( const char * formatP , . . . ) { // Content send snprintf_P char data
2019-03-19 16:31:43 +00:00
// This uses char strings. Be aware of sending %% if % is needed
va_list arg ;
va_start ( arg , formatP ) ;
2021-06-04 16:16:04 +01:00
_WSContentSendBuffer ( false , formatP , arg ) ;
2019-03-19 16:31:43 +00:00
va_end ( arg ) ;
}
2021-06-04 10:04:52 +01:00
void WSContentSend_PD ( const char * formatP , . . . ) { // Content send snprintf_P char data checked for decimal separator
2019-03-19 16:31:43 +00:00
// This uses char strings. Be aware of sending %% if % is needed
va_list arg ;
va_start ( arg , formatP ) ;
2021-06-04 16:16:04 +01:00
_WSContentSendBuffer ( true , formatP , arg ) ;
2019-03-19 16:31:43 +00:00
va_end ( arg ) ;
}
2021-06-19 14:22:17 +01:00
void WSContentStart_P ( const char * title , bool auth ) {
2021-01-08 13:10:34 +00:00
if ( auth & & ! WebAuthenticate ( ) ) {
2020-04-15 08:58:38 +01:00
return Webserver - > requestAuthentication ( ) ;
2019-03-04 17:16:07 +00:00
}
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_HTML ) ;
2019-03-04 17:16:07 +00:00
2019-03-26 17:26:50 +00:00
if ( title ! = nullptr ) {
2021-01-18 20:48:04 +00:00
WSContentSend_P ( HTTP_HEADER1 , PSTR ( D_HTML_LANGUAGE ) , SettingsText ( SET_DEVICENAME ) , title ) ;
2019-03-16 15:23:41 +00:00
}
2019-03-04 17:16:07 +00:00
}
2018-10-29 11:21:27 +00:00
2021-06-19 14:22:17 +01:00
void WSContentStart_P ( const char * title ) {
2019-03-10 14:36:34 +00:00
WSContentStart_P ( title , true ) ;
2019-03-04 17:16:07 +00:00
}
2021-06-19 14:22:17 +01:00
void WSContentSendStyle_P ( const char * formatP , . . . ) {
2021-04-12 17:36:43 +01:00
if ( WifiIsInManagerMode ( ) & & ( ! Web . initial_config ) ) {
2018-10-10 21:21:44 +01:00
if ( WifiConfigCounter ( ) ) {
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_SCRIPT_COUNTER ) ;
2018-10-10 21:21:44 +01:00
}
}
2022-05-02 16:25:31 +01:00
# ifdef ESP32
WSContentSend_P ( HTTP_HEAD_LAST_SCRIPT32 ) ;
# else
2019-06-02 15:44:02 +01:00
WSContentSend_P ( HTTP_HEAD_LAST_SCRIPT ) ;
2022-05-02 16:25:31 +01:00
# endif
2019-06-02 15:44:02 +01:00
2019-11-06 10:16:43 +00:00
WSContentSend_P ( HTTP_HEAD_STYLE1 , WebColor ( COL_FORM ) , WebColor ( COL_INPUT ) , WebColor ( COL_INPUT_TEXT ) , WebColor ( COL_INPUT ) ,
WebColor ( COL_INPUT_TEXT ) , WebColor ( COL_CONSOLE ) , WebColor ( COL_CONSOLE_TEXT ) , WebColor ( COL_BACKGROUND ) ) ;
WSContentSend_P ( HTTP_HEAD_STYLE2 , WebColor ( COL_BUTTON ) , WebColor ( COL_BUTTON_TEXT ) , WebColor ( COL_BUTTON_HOVER ) ,
WebColor ( COL_BUTTON_RESET ) , WebColor ( COL_BUTTON_RESET_HOVER ) , WebColor ( COL_BUTTON_SAVE ) , WebColor ( COL_BUTTON_SAVE_HOVER ) ,
WebColor ( COL_BUTTON ) ) ;
2020-08-24 20:07:03 +01:00
# ifdef USE_ZIGBEE
WSContentSend_P ( HTTP_HEAD_STYLE_ZIGBEE ) ;
# endif // USE_ZIGBEE
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
if ( formatP ! = nullptr ) {
// This uses char strings. Be aware of sending %% if % is needed
va_list arg ;
va_start ( arg , formatP ) ;
2021-06-04 16:16:04 +01:00
_WSContentSendBuffer ( false , formatP , arg ) ;
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
va_end ( arg ) ;
}
2019-04-09 12:56:19 +01:00
WSContentSend_P ( HTTP_HEAD_STYLE3 , WebColor ( COL_TEXT ) ,
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
# ifdef FIRMWARE_MINIMAL
2021-01-27 11:03:20 +00:00
WebColor ( COL_TEXT_WARNING ) ,
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
# endif
2021-01-27 11:03:20 +00:00
WebColor ( COL_TITLE ) ,
2022-05-29 14:49:57 +01:00
( Web . initial_config ) ? " " : ( Settings - > flag5 . gui_module_name ) ? " " : ModuleName ( ) . c_str ( ) , SettingsText ( SET_DEVICENAME ) ) ;
2021-04-12 17:36:43 +01:00
// SetOption53 - Show hostname and IP address in GUI main menu
# if (RESTART_AFTER_INITIAL_WIFI_CONFIG)
2022-01-16 15:19:28 +00:00
if ( Settings - > flag3 . gui_hostname_ip ) { // SetOption53 - (GUI) Show hostname and IP address in GUI main menu
2021-04-12 17:36:43 +01:00
# else
2021-06-11 17:14:12 +01:00
if ( Settings - > flag3 . gui_hostname_ip | | ( ( WiFi . getMode ( ) = = WIFI_AP_STA ) & & ( ! Web . initial_config ) ) ) {
2021-04-12 17:36:43 +01:00
# endif
2022-12-27 20:59:34 +00:00
bool lip = WifiHasIP ( ) ;
2019-03-14 15:50:56 +00:00
bool sip = ( static_cast < uint32_t > ( WiFi . softAPIP ( ) ) ! = 0 ) ;
2022-02-22 14:13:26 +00:00
bool eip = false ;
if ( lip | | sip ) {
WSContentSend_P ( PSTR ( " <h4>%s%s (%s%s%s) " ) , // tasmota.local (192.168.2.12, 192.168.4.1)
TasmotaGlobal . hostname ,
( Mdns . begun ) ? PSTR ( " .local " ) : " " ,
( lip ) ? WiFi . localIP ( ) . toString ( ) . c_str ( ) : " " ,
( lip & & sip ) ? " , " : " " ,
( sip ) ? WiFi . softAPIP ( ) . toString ( ) . c_str ( ) : " " ) ;
}
# if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET)
2022-12-27 20:59:34 +00:00
eip = EthernetHasIP ( ) ;
2022-02-22 14:13:26 +00:00
if ( eip ) {
WSContentSend_P ( PSTR ( " %s%s%s (%s) " ) , // tasmota-eth.local (192.168.2.13)
( lip | | sip ) ? PSTR ( " </br> " ) : PSTR ( " <h4> " ) ,
EthernetHostname ( ) ,
( Mdns . begun ) ? PSTR ( " .local " ) : " " ,
( eip ) ? EthernetLocalIP ( ) . toString ( ) . c_str ( ) : " " ) ;
}
# endif
if ( lip | | sip | | eip ) {
WSContentSend_P ( PSTR ( " </h4> " ) ) ;
}
2019-03-14 15:50:56 +00:00
}
WSContentSend_P ( PSTR ( " </div> " ) ) ;
2019-03-04 17:16:07 +00:00
}
2018-10-10 21:21:44 +01:00
2021-06-19 14:22:17 +01:00
void WSContentSendStyle ( void ) {
2019-03-26 17:26:50 +00:00
WSContentSendStyle_P ( nullptr ) ;
2018-10-10 21:21:44 +01:00
}
2021-04-14 11:39:07 +01:00
void WSContentTextCenterStart ( uint32_t color ) {
WSContentSend_P ( PSTR ( " <div style='text-align:center;color:#%06x;'> " ) , color ) ;
}
2021-06-19 14:22:17 +01:00
void WSContentButton ( uint32_t title_index , bool show = true ) {
2019-03-11 09:38:41 +00:00
char action [ 4 ] ;
2019-07-06 11:53:07 +01:00
char title [ 100 ] ; // Large to accomodate UTF-16 as used by Russian
2019-03-11 09:38:41 +00:00
2021-04-13 11:41:13 +01:00
WSContentSend_P ( PSTR ( " <p><form id=but%d style= \" display: %s; \" action='%s' method='get' " ) ,
title_index ,
show ? " block " : " none " ,
GetTextIndexed ( action , sizeof ( action ) , title_index , kButtonAction ) ) ;
2019-03-11 09:38:41 +00:00
if ( title_index < = BUTTON_RESET_CONFIGURATION ) {
2019-07-06 11:53:07 +01:00
char confirm [ 100 ] ;
2021-04-13 11:41:13 +01:00
WSContentSend_P ( PSTR ( " onsubmit='return confirm( \" %s \" );'><button name='%s' class='button bred'>%s</button></form></p> " ) ,
2019-03-11 09:38:41 +00:00
GetTextIndexed ( confirm , sizeof ( confirm ) , title_index , kButtonConfirm ) ,
2021-01-18 20:48:04 +00:00
( ! title_index ) ? PSTR ( " rst " ) : PSTR ( " non " ) ,
2019-03-11 09:38:41 +00:00
GetTextIndexed ( title , sizeof ( title ) , title_index , kButtonTitle ) ) ;
} else {
2021-04-13 11:41:13 +01:00
WSContentSend_P ( PSTR ( " ><button>%s</button></form></p> " ) ,
2019-03-11 09:38:41 +00:00
GetTextIndexed ( title , sizeof ( title ) , title_index , kButtonTitle ) ) ;
}
}
2021-06-19 14:22:17 +01:00
void WSContentSpaceButton ( uint32_t title_index , bool show = true ) {
2021-04-12 17:36:43 +01:00
WSContentSend_P ( PSTR ( " <div id=but%dd style= \" display: %s; \" ></div> " ) , title_index , show ? " block " : " none " ) ; // 5px padding
WSContentButton ( title_index , show ) ;
2019-03-11 09:38:41 +00:00
}
2021-01-26 15:26:00 +00:00
void WSContentSend_Temp ( const char * types , float f_temperature ) {
2021-06-11 17:14:12 +01:00
WSContentSend_PD ( HTTP_SNS_F_TEMP , types , Settings - > flag2 . temperature_resolution , & f_temperature , TempUnit ( ) ) ;
2021-01-26 15:26:00 +00:00
}
2021-04-15 16:21:18 +01:00
void WSContentSend_Voltage ( const char * types , float f_voltage ) {
2021-06-11 17:14:12 +01:00
WSContentSend_PD ( HTTP_SNS_F_VOLTAGE , types , Settings - > flag2 . voltage_resolution , & f_voltage ) ;
2021-04-15 16:21:18 +01:00
}
void WSContentSend_CurrentMA ( const char * types , float f_current ) {
2021-06-11 17:14:12 +01:00
WSContentSend_PD ( HTTP_SNS_F_CURRENT_MA , types , Settings - > flag2 . current_resolution , & f_current ) ;
2021-04-15 16:21:18 +01:00
}
2021-06-19 14:22:17 +01:00
void WSContentSend_THD ( const char * types , float f_temperature , float f_humidity ) {
2021-01-26 15:26:00 +00:00
WSContentSend_Temp ( types , f_temperature ) ;
2020-03-17 15:29:59 +00:00
char parameter [ FLOATSZ ] ;
2021-06-11 17:14:12 +01:00
dtostrfd ( f_humidity , Settings - > flag2 . humidity_resolution , parameter ) ;
2020-03-17 15:29:59 +00:00
WSContentSend_PD ( HTTP_SNS_HUM , types , parameter ) ;
2021-06-11 17:14:12 +01:00
dtostrfd ( CalcTempHumToDew ( f_temperature , f_humidity ) , Settings - > flag2 . temperature_resolution , parameter ) ;
2020-03-17 15:29:59 +00:00
WSContentSend_PD ( HTTP_SNS_DEW , types , parameter , TempUnit ( ) ) ;
}
2021-06-19 14:22:17 +01:00
void WSContentEnd ( void ) {
WSContentFlush ( ) ; // Flush chunk buffer
_WSContentSend ( " " ) ; // Signal end of chunked content
2020-04-15 08:58:38 +01:00
Webserver - > client ( ) . stop ( ) ;
2019-03-16 15:23:41 +00:00
}
2021-06-19 14:22:17 +01:00
void WSContentStop ( void ) {
2021-04-12 17:36:43 +01:00
if ( WifiIsInManagerMode ( ) & & ( ! Web . initial_config ) ) {
2019-03-04 17:16:07 +00:00
if ( WifiConfigCounter ( ) ) {
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_COUNTER ) ;
2019-03-04 17:16:07 +00:00
}
}
2020-10-30 11:29:48 +00:00
WSContentSend_P ( HTTP_END , TasmotaGlobal . version ) ;
2019-03-16 15:23:41 +00:00
WSContentEnd ( ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-04 17:16:07 +00:00
/*********************************************************************************************/
2018-10-12 10:42:52 +01:00
2022-05-15 13:59:39 +01:00
void WebRestart ( uint32_t type ) {
2018-10-12 10:42:52 +01:00
// type 0 = restart
// type 1 = restart after config change
2021-04-12 17:36:43 +01:00
// type 2 = Checking WiFi Connection - no restart, only refresh page.
// type 3 = restart after WiFi Connection Test Successful
2022-05-15 13:59:39 +01:00
// type 4 = type 0 without auto switch to production
bool prep_switch_partition = false ;
if ( 0 = = type ) { prep_switch_partition = true ; }
if ( 4 = = type ) { type = 0 ; }
2019-08-15 12:50:28 +01:00
bool reset_only = ( HTTP_MANAGER_RESET_ONLY = = Web . state ) ;
2018-10-12 10:42:52 +01:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( ( type ) ? PSTR ( D_SAVE_CONFIGURATION ) : PSTR ( D_RESTART ) , ! reset_only ) ;
2021-04-12 17:36:43 +01:00
# if ((RESTART_AFTER_INITIAL_WIFI_CONFIG) && (AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP))
// In case of type 3 (New network has been configured) go to the new device's IP in the new Network
if ( 3 = = type ) {
2022-12-27 20:59:34 +00:00
WSContentSend_P ( " setTimeout(function(){location.href='http://%s';},%d); " ,
IPForUrl ( WiFi . localIP ( ) ) . c_str ( ) ,
2021-04-12 17:36:43 +01:00
HTTP_RESTART_RECONNECT_TIME
) ;
} else {
WSContentSend_P ( HTTP_SCRIPT_RELOAD_TIME , HTTP_RESTART_RECONNECT_TIME ) ;
}
# else
// In case of type 3 (New network has been configured) do not refresh the page. Just halt.
// The IP of the device while was in AP mode, won't be the new IP of the newly configured Network.
if ( ! ( 3 = = type ) ) { WSContentSend_P ( HTTP_SCRIPT_RELOAD_TIME , HTTP_RESTART_RECONNECT_TIME ) ; }
# endif
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2018-10-12 10:42:52 +01:00
if ( type ) {
2021-04-12 17:36:43 +01:00
if ( ! ( 3 = = type ) ) {
WSContentSend_P ( PSTR ( " <div style='text-align:center;'><b>%s</b><br><br></div> " ) , ( type = = 2 ) ? PSTR ( D_TRYING_TO_CONNECT ) : PSTR ( D_CONFIGURATION_SAVED ) ) ;
} else {
# if (AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP)
2021-04-14 11:39:07 +01:00
WSContentTextCenterStart ( WebColor ( COL_TEXT_SUCCESS ) ) ;
2021-05-12 19:27:47 +01:00
WSContentSend_P ( PSTR ( D_SUCCESSFUL_WIFI_CONNECTION " <br><br></div><div style='text-align:center;'> " D_REDIRECTING_TO_NEW_IP " <br><br><a href='http://%_I'>%_I</a><br></div> " ) , ( uint32_t ) WiFi . localIP ( ) , ( uint32_t ) WiFi . localIP ( ) ) ;
2021-04-12 17:36:43 +01:00
# else
2021-04-14 11:39:07 +01:00
WSContentTextCenterStart ( WebColor ( COL_TEXT_SUCCESS ) ) ;
WSContentSend_P ( PSTR ( D_SUCCESSFUL_WIFI_CONNECTION " <br><br></div><div style='text-align:center;'> " D_NOW_YOU_CAN_CLOSE_THIS_WINDOW " <br><br></div> " ) ) ;
2021-04-12 17:36:43 +01:00
# endif
2018-10-12 10:42:52 +01:00
}
}
2022-05-15 13:59:39 +01:00
if ( type < 2 ) {
2021-04-12 17:36:43 +01:00
WSContentSend_P ( HTTP_MSG_RSTRT ) ;
if ( HTTP_MANAGER = = Web . state | | reset_only ) {
Web . state = HTTP_ADMIN ;
} else {
WSContentSpaceButton ( BUTTON_MAIN ) ;
}
2018-10-12 10:42:52 +01:00
}
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-12 10:42:52 +01:00
2021-04-12 17:36:43 +01:00
if ( ! ( 2 = = type ) ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_RESTART ) ) ;
ShowWebSource ( SRC_WEBGUI ) ;
2022-05-15 13:59:39 +01:00
# ifdef ESP32
if ( prep_switch_partition ) { EspPrepSwitchPartition ( 1 ) ; } // Switch to production partition if on safeboot
# endif // ESP32
2021-04-12 17:36:43 +01:00
TasmotaGlobal . restart_flag = 2 ;
}
2018-10-12 10:42:52 +01:00
}
2018-10-10 21:21:44 +01:00
/*********************************************************************************************/
2018-11-14 13:32:09 +00:00
void HandleWifiLogin ( void )
2018-10-10 21:21:44 +01:00
{
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONFIGURE_WIFI ) , false ) ; // false means show page no matter if the client has or has not credentials
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_LOGIN ) ;
2019-03-07 17:18:30 +00:00
2019-08-15 12:50:28 +01:00
if ( HTTP_MANAGER_RESET_ONLY = = Web . state ) {
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_RESTART ) ;
2019-03-07 17:18:30 +00:00
# ifndef FIRMWARE_MINIMAL
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_RESET_CONFIGURATION ) ;
2019-03-07 17:18:30 +00:00
# endif // FIRMWARE_MINIMAL
}
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2021-04-16 10:40:38 +01:00
uint32_t WebUseManagementSubmenu ( void ) {
static uint32_t management_count = 0 ;
if ( ! management_count ) {
XdrvMailbox . index = 1 ;
2022-11-11 08:57:00 +00:00
XdrvXsnsCall ( FUNC_WEB_ADD_CONSOLE_BUTTON ) ;
2021-04-16 10:40:38 +01:00
XdrvCall ( FUNC_WEB_ADD_MANAGEMENT_BUTTON ) ;
management_count = XdrvMailbox . index ;
}
return management_count - 1 ;
}
2021-04-02 14:33:05 +01:00
uint32_t WebDeviceColumns ( void ) {
const uint32_t max_columns = 8 ;
uint32_t rows = TasmotaGlobal . devices_present / max_columns ;
if ( TasmotaGlobal . devices_present % max_columns ) { rows + + ; }
uint32_t cols = TasmotaGlobal . devices_present / rows ;
if ( TasmotaGlobal . devices_present % rows ) { cols + + ; }
return cols ;
}
2020-03-02 16:48:19 +00:00
# ifdef USE_LIGHT
2020-01-16 13:22:39 +00:00
void WebSliderColdWarm ( void )
{
WSContentSend_P ( HTTP_MSG_SLIDER_GRADIENT , // Cold Warm
2021-01-18 20:48:04 +00:00
PSTR ( " a " ) , // a - Unique HTML id
PSTR ( " #eff " ) , PSTR ( " #f81 " ) , // 6500k in RGB (White) to 2500k in RGB (Warm Yellow)
2020-01-16 13:22:39 +00:00
1 , // sl1
153 , 500 , // Range color temperature
LightGetColorTemp ( ) ,
' t ' , 0 ) ; // t0 - Value id releated to lc("t0", value) and WebGetArg("t0", tmp, sizeof(tmp));
}
2020-03-02 16:48:19 +00:00
# endif // USE_LIGHT
2020-01-16 13:22:39 +00:00
2018-11-14 13:32:09 +00:00
void HandleRoot ( void )
2018-10-10 21:21:44 +01:00
{
2021-06-16 00:39:49 +01:00
# ifndef NO_CAPTIVE_PORTAL
2018-10-10 21:21:44 +01:00
if ( CaptivePortal ( ) ) { return ; } // If captive portal redirect instead of displaying the page.
2021-06-16 00:39:49 +01:00
# endif // NO_CAPTIVE_PORTAL
2018-10-10 21:21:44 +01:00
2021-01-18 20:48:04 +00:00
if ( Webserver - > hasArg ( F ( " rst " ) ) ) {
2018-10-12 10:42:52 +01:00
WebRestart ( 0 ) ;
return ;
}
2019-02-21 16:49:11 +00:00
if ( WifiIsInManagerMode ( ) ) {
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2021-01-18 20:48:04 +00:00
if ( strlen ( SettingsText ( SET_WEBPWD ) ) & & ! ( Webserver - > hasArg ( F ( " USER1 " ) ) ) & & ! ( Webserver - > hasArg ( F ( " PASS1 " ) ) ) & & HTTP_MANAGER_RESET_ONLY ! = Web . state ) {
2018-10-10 21:21:44 +01:00
HandleWifiLogin ( ) ;
} else {
2021-01-18 20:48:04 +00:00
if ( ! strlen ( SettingsText ( SET_WEBPWD ) ) | | ( ( ( Webserver - > arg ( F ( " USER1 " ) ) = = WEB_USERNAME ) & & ( Webserver - > arg ( F ( " PASS1 " ) ) = = SettingsText ( SET_WEBPWD ) ) ) | | HTTP_MANAGER_RESET_ONLY = = Web . state ) ) {
2018-10-10 21:21:44 +01:00
HandleWifiConfiguration ( ) ;
} else {
// wrong user and pass
HandleWifiLogin ( ) ;
}
}
2019-02-08 13:55:45 +00:00
# endif // Not FIRMWARE_MINIMAL
2019-03-01 17:25:46 +00:00
return ;
}
if ( HandleRootStatusRefresh ( ) ) {
return ;
}
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_MAIN_MENU ) ) ;
2019-03-01 17:25:46 +00:00
2019-12-24 16:10:50 +00:00
char stemp [ 33 ] ;
2019-03-01 17:25:46 +00:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_MAIN_MENU ) ) ;
2019-09-24 07:25:32 +01:00
# ifdef USE_SCRIPT_WEB_DISPLAY
2021-06-11 17:14:12 +01:00
WSContentSend_P ( HTTP_SCRIPT_ROOT , Settings - > web_refresh , Settings - > web_refresh ) ;
2019-09-24 07:25:32 +01:00
# else
2021-06-11 17:14:12 +01:00
WSContentSend_P ( HTTP_SCRIPT_ROOT , Settings - > web_refresh ) ;
2019-09-24 07:25:32 +01:00
# endif
2019-11-25 16:21:31 +00:00
WSContentSend_P ( HTTP_SCRIPT_ROOT_PART2 ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-01 17:25:46 +00:00
2021-04-02 15:16:38 +01:00
WSContentSend_P ( PSTR ( " <div style='padding:0;' id='l1' name='l1'></div> " ) ) ;
2020-10-30 11:29:48 +00:00
if ( TasmotaGlobal . devices_present ) {
2019-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
2020-10-30 11:29:48 +00:00
if ( TasmotaGlobal . light_type ) {
uint8_t light_subtype = TasmotaGlobal . light_type & 7 ;
2021-06-11 17:14:12 +01:00
if ( ! Settings - > flag3 . pwm_multi_channels ) { // SetOption68 0 - Enable multi-channels PWM instead of Color PWM
2020-10-30 11:29:48 +00:00
bool split_white = ( ( LST_RGBW < = light_subtype ) & & ( TasmotaGlobal . devices_present > 1 ) ) ; // Only on RGBW or RGBCW and SetOption37 128
2020-01-16 13:22:39 +00:00
if ( ( LST_COLDWARM = = light_subtype ) | | ( ( LST_RGBCW = = light_subtype ) & & ! split_white ) ) {
WebSliderColdWarm ( ) ;
2019-11-22 16:01:11 +00:00
}
2020-01-16 13:22:39 +00:00
if ( light_subtype > 2 ) { // No W or CW
2019-11-22 16:01:11 +00:00
uint16_t hue ;
uint8_t sat ;
2019-11-25 14:20:44 +00:00
LightGetHSB ( & hue , & sat , nullptr ) ;
WSContentSend_P ( HTTP_MSG_SLIDER_GRADIENT , // Hue
2021-01-18 20:48:04 +00:00
PSTR ( " b " ) , // b - Unique HTML id
PSTR ( " #800 " ) , PSTR ( " #f00 5%,#ff0 20%,#0f0 35%,#0ff 50%,#00f 65%,#f0f 80%,#f00 95%,#800 " ) , // Hue colors
2019-11-25 14:20:44 +00:00
2 , // sl2 - Unique range HTML id - Used as source for Saturation end color
2022-04-04 15:36:27 +01:00
0 , 359 , // Range valid Hue
2019-11-25 14:20:44 +00:00
hue ,
' h ' , 0 ) ; // h0 - Value id
2021-06-11 17:14:12 +01:00
uint8_t dcolor = changeUIntScale ( Settings - > light_dimmer , 0 , 100 , 0 , 255 ) ;
2019-11-25 14:20:44 +00:00
char scolor [ 8 ] ;
snprintf_P ( scolor , sizeof ( scolor ) , PSTR ( " #%02X%02X%02X " ) , dcolor , dcolor , dcolor ) ; // Saturation start color from Black to White
uint8_t red , green , blue ;
2021-01-02 18:26:24 +00:00
HsToRgb ( hue , 255 , & red , & green , & blue ) ;
2019-11-25 14:20:44 +00:00
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " #%02X%02X%02X " ) , red , green , blue ) ; // Saturation end color
WSContentSend_P ( HTTP_MSG_SLIDER_GRADIENT , // Saturation
2021-01-18 20:48:04 +00:00
PSTR ( " s " ) , // s - Unique HTML id related to eb('s').style.background='linear-gradient(to right,rgb('+sl+'%%,'+sl+'%%,'+sl+'%%),hsl('+eb('sl2').value+',100%%,50%%))';
2019-11-25 14:20:44 +00:00
scolor , stemp , // Brightness to max current color
3 , // sl3 - Unique range HTML id - Not used
Align slider behaviour with mqtt...
commands. Via slider it was NOT possible to set ```{"POWER1":"OFF","Dimmer1":0,"POWER2":"OFF","Dimmer2":100,"Color":"000000FF","HSBColor":"0,0,0","Channel":[0,0,0,100]}```
min value was before the change
```{"POWER1":"ON","Dimmer1":1,"POWER2":"OFF","Dimmer2":100,"Color":"030303FF","HSBColor":"1,1,1","Channel":[1,1,1,100]}```
2019-11-27 17:14:12 +00:00
0 , 100 , // Range 0 to 100%
2019-11-25 14:20:44 +00:00
changeUIntScale ( sat , 0 , 255 , 0 , 100 ) ,
' n ' , 0 ) ; // n0 - Value id
2019-10-15 16:37:02 +01:00
}
2019-11-25 14:20:44 +00:00
WSContentSend_P ( HTTP_MSG_SLIDER_GRADIENT , // Brightness - Black to White
2021-01-18 20:48:04 +00:00
PSTR ( " c " ) , // c - Unique HTML id
PSTR ( " #000 " ) , PSTR ( " #fff " ) , // Black to White
2019-11-25 14:20:44 +00:00
4 , // sl4 - Unique range HTML id - Used as source for Saturation begin color
2021-06-11 17:14:12 +01:00
Settings - > flag3 . slider_dimmer_stay_on , 100 , // Range 0/1 to 100% (SetOption77 - Do not power off if slider moved to far left)
Settings - > light_dimmer ,
2019-11-25 14:20:44 +00:00
' d ' , 0 ) ; // d0 - Value id is related to lc("d0", value) and WebGetArg("d0", tmp, sizeof(tmp));
2020-01-16 13:22:39 +00:00
if ( split_white ) { // SetOption37 128
if ( LST_RGBCW = = light_subtype ) {
WebSliderColdWarm ( ) ;
}
WSContentSend_P ( HTTP_MSG_SLIDER_GRADIENT , // White brightness - Black to White
2021-01-18 20:48:04 +00:00
PSTR ( " f " ) , // f - Unique HTML id
PSTR ( " #000 " ) , PSTR ( " #fff " ) , // Black to White
2020-01-16 13:22:39 +00:00
5 , // sl5 - Unique range HTML id - Not used
2021-06-11 17:14:12 +01:00
Settings - > flag3 . slider_dimmer_stay_on , 100 , // Range 0/1 to 100% (SetOption77 - Do not power off if slider moved to far left)
2020-01-16 13:22:39 +00:00
LightGetDimmer ( 2 ) ,
' w ' , 0 ) ; // w0 - Value id is related to lc("w0", value) and WebGetArg("w0", tmp, sizeof(tmp));
}
2021-06-11 17:14:12 +01:00
} else { // Settings->flag3.pwm_multi_channels - SetOption68 1 - Enable multi-channels PWM instead of Color PWM
2019-11-22 16:24:56 +00:00
uint32_t pwm_channels = light_subtype > LST_MAX ? LST_MAX : light_subtype ;
2019-11-25 18:29:11 +00:00
stemp [ 0 ] = ' e ' ; stemp [ 1 ] = ' 0 ' ; stemp [ 2 ] = ' \0 ' ; // d0
2019-10-15 16:37:02 +01:00
for ( uint32_t i = 0 ; i < pwm_channels ; i + + ) {
2019-11-25 18:29:11 +00:00
stemp [ 1 ] + + ; // e1 to e5 - Make unique ids
2019-11-25 14:20:44 +00:00
WSContentSend_P ( HTTP_MSG_SLIDER_GRADIENT , // Channel brightness - Black to White
2019-11-25 18:29:11 +00:00
stemp , // e1 to e5 - Unique HTML id
2021-01-18 20:48:04 +00:00
PSTR ( " #000 " ) , PSTR ( " #fff " ) , // Black to White
2019-11-25 14:20:44 +00:00
i + 1 , // sl1 to sl5 - Unique range HTML id - Not used
1 , 100 , // Range 1 to 100%
2021-06-11 17:14:12 +01:00
changeUIntScale ( Settings - > light_color [ i ] , 0 , 255 , 0 , 100 ) ,
2019-11-25 18:29:11 +00:00
' e ' , i + 1 ) ; // e1 to e5 - Value id
2019-10-15 16:37:02 +01:00
}
2021-06-11 17:14:12 +01:00
} // Settings->flag3.pwm_multi_channels
2019-03-01 17:25:46 +00:00
}
2019-11-19 20:22:45 +00:00
# endif // USE_LIGHT
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_TABLE100 ) ;
WSContentSend_P ( PSTR ( " <tr> " ) ) ;
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) {
2019-12-24 16:10:50 +00:00
WSContentSend_P ( HTTP_DEVICE_CONTROL , 36 , 1 ,
2021-01-18 20:48:04 +00:00
( strlen ( SettingsText ( SET_BUTTON1 ) ) ) ? SettingsText ( SET_BUTTON1 ) : PSTR ( D_BUTTON_TOGGLE ) ,
2019-12-24 16:10:50 +00:00
" " ) ;
2019-07-14 14:23:02 +01:00
for ( uint32_t i = 0 ; i < MaxFanspeed ( ) ; i + + ) {
2019-03-01 17:25:46 +00:00
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , i ) ;
2019-12-24 16:10:50 +00:00
WSContentSend_P ( HTTP_DEVICE_CONTROL , 16 , i + 2 ,
( strlen ( SettingsText ( SET_BUTTON2 + i ) ) ) ? SettingsText ( SET_BUTTON2 + i ) : stemp ,
" " ) ;
2019-03-01 17:25:46 +00:00
}
} else {
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2021-04-02 14:33:05 +01:00
uint32_t cols = WebDeviceColumns ( ) ;
2020-10-30 11:29:48 +00:00
for ( uint32_t idx = 1 ; idx < = TasmotaGlobal . devices_present ; idx + + ) {
2023-09-29 08:56:52 +01:00
bool set_button = ( ( idx < = MAX_BUTTON_TEXT ) & & strlen ( GetWebButton ( idx - 1 ) ) ) ;
2019-12-10 11:33:45 +00:00
# ifdef USE_SHUTTER
2020-01-09 08:17:39 +00:00
int32_t ShutterWebButton ;
if ( ShutterWebButton = IsShutterWebButton ( idx ) ) {
2021-04-02 14:33:05 +01:00
WSContentSend_P ( HTTP_DEVICE_CONTROL , 100 / cols , idx ,
2023-09-29 08:56:52 +01:00
( set_button ) ? GetWebButton ( idx - 1 ) : ( ( ShutterGetOptions ( abs ( ShutterWebButton ) - 1 ) & 2 ) /* is locked */ ? " - " : ( ( ShutterGetOptions ( abs ( ShutterWebButton ) - 1 ) & 8 ) /* invert web buttons */ ? ( ( ShutterWebButton > 0 ) ? " ▼ " : " ▲ " ) : ( ( ShutterWebButton > 0 ) ? " ▲ " : " ▼ " ) ) ) ,
2020-01-09 08:17:39 +00:00
" " ) ;
2021-04-02 14:33:05 +01:00
} else {
# endif // USE_SHUTTER
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , idx ) ;
WSContentSend_P ( HTTP_DEVICE_CONTROL , 100 / cols , idx ,
2023-09-29 08:56:52 +01:00
( set_button ) ? GetWebButton ( idx - 1 ) : ( cols < 5 ) ? PSTR ( D_BUTTON_TOGGLE ) : " " ,
2021-04-02 14:33:05 +01:00
( set_button ) ? " " : ( TasmotaGlobal . devices_present > 1 ) ? stemp : " " ) ;
# ifdef USE_SHUTTER
2019-12-10 11:33:45 +00:00
}
# endif // USE_SHUTTER
2021-04-02 14:33:05 +01:00
if ( 0 = = idx % cols ) { WSContentSend_P ( PSTR ( " </tr><tr> " ) ) ; }
2018-10-10 21:21:44 +01:00
}
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2018-10-10 21:21:44 +01:00
}
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " </tr></table> " ) ) ;
2019-03-01 17:25:46 +00:00
}
2021-12-15 11:30:48 +00:00
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2022-11-11 08:57:00 +00:00
XdrvXsnsCall ( FUNC_WEB_ADD_MAIN_BUTTON ) ;
2019-02-08 13:55:45 +00:00
# endif // Not FIRMWARE_MINIMAL
2018-10-11 16:33:07 +01:00
2019-08-15 12:50:28 +01:00
if ( HTTP_ADMIN = = Web . state ) {
2019-03-11 09:38:41 +00:00
# ifdef FIRMWARE_MINIMAL
2022-05-15 11:31:27 +01:00
# ifdef ESP32
# ifndef FIRMWARE_MINIMAL_ONLY
WSContentSpaceButton ( BUTTON_INFORMATION ) ;
WSContentButton ( BUTTON_FIRMWARE_UPGRADE ) ;
# endif // FIRMWARE_MINIMAL_ONLY
# else // ESP8266
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_FIRMWARE_UPGRADE ) ;
2022-05-15 11:31:27 +01:00
# endif // ESP32
2021-04-16 10:40:38 +01:00
WSContentButton ( BUTTON_CONSOLE ) ;
2019-03-07 17:18:30 +00:00
# else
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
WSContentButton ( BUTTON_INFORMATION ) ;
WSContentButton ( BUTTON_FIRMWARE_UPGRADE ) ;
2021-04-16 10:40:38 +01:00
if ( ! WebUseManagementSubmenu ( ) ) {
WSContentButton ( BUTTON_CONSOLE ) ;
} else {
WSContentButton ( BUTTON_MANAGEMENT ) ;
}
2019-03-07 17:18:30 +00:00
# endif // Not FIRMWARE_MINIMAL
2019-03-11 09:38:41 +00:00
WSContentButton ( BUTTON_RESTART ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-01 17:25:46 +00:00
bool HandleRootStatusRefresh ( void )
2018-10-10 21:21:44 +01:00
{
2019-03-01 17:25:46 +00:00
if ( ! WebAuthenticate ( ) ) {
2020-04-15 08:58:38 +01:00
Webserver - > requestAuthentication ( ) ;
2019-03-01 17:25:46 +00:00
return true ;
}
2020-04-15 08:58:38 +01:00
if ( ! Webserver - > hasArg ( " m " ) ) { // Status refresh requested
2019-03-01 17:25:46 +00:00
return false ;
}
2018-10-10 21:21:44 +01:00
2019-09-16 18:52:53 +01:00
# ifdef USE_SCRIPT_WEB_DISPLAY
Script_Check_HTML_Setvars ( ) ;
# endif
2019-02-23 17:38:36 +00:00
char tmp [ 8 ] ; // WebGetArg numbers only
char svalue [ 32 ] ; // Command and number parameter
2019-10-15 15:41:53 +01:00
char webindex [ 5 ] ; // WebGetArg name
2018-10-10 21:21:44 +01:00
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " o " ) , tmp , sizeof ( tmp ) ) ; // 1 - 16 Device number for button Toggle or Fanspeed
2018-10-10 21:21:44 +01:00
if ( strlen ( tmp ) ) {
ShowWebSource ( SRC_WEBGUI ) ;
2019-07-27 17:37:56 +01:00
uint32_t device = atoi ( tmp ) ;
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) {
2018-10-10 21:21:44 +01:00
if ( device < 2 ) {
ExecuteCommandPower ( 1 , POWER_TOGGLE , SRC_IGNORE ) ;
} else {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_FANSPEED " %d " ) , device - 2 ) ;
ExecuteCommand ( svalue , SRC_WEBGUI ) ;
}
} else {
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2020-09-16 19:45:56 +01:00
# ifdef USE_TUYA_MCU
if ( IsModuleTuya ( ) ) {
2020-11-07 21:08:07 +00:00
if ( device < = TasmotaGlobal . devices_present ) {
ExecuteCommandPower ( device , POWER_TOGGLE , SRC_IGNORE ) ;
} else {
if ( AsModuleTuyaMS ( ) & & device = = TasmotaGlobal . devices_present + 1 ) {
uint8_t dpId = TuyaGetDpId ( TUYA_MCU_FUNC_MODESET ) ;
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " Tuyasend4 %d,%d " ) , dpId , ! TuyaModeSet ( ) ) ;
ExecuteCommand ( svalue , SRC_WEBGUI ) ;
2020-09-16 19:45:56 +01:00
}
2020-11-07 21:08:07 +00:00
}
2020-09-16 19:45:56 +01:00
} else {
# endif // USE_TUYA_MCU
2020-01-09 08:17:39 +00:00
# ifdef USE_SHUTTER
int32_t ShutterWebButton ;
if ( ShutterWebButton = IsShutterWebButton ( device ) ) {
2020-04-11 07:28:05 +01:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " ShutterPosition%d %s " ) , abs ( ShutterWebButton ) , ( ShutterWebButton > 0 ) ? PSTR ( D_CMND_SHUTTER_STOPOPEN ) : PSTR ( D_CMND_SHUTTER_STOPCLOSE ) ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2020-01-09 08:17:39 +00:00
} else {
# endif // USE_SHUTTER
ExecuteCommandPower ( device , POWER_TOGGLE , SRC_IGNORE ) ;
# ifdef USE_SHUTTER
}
# endif // USE_SHUTTER
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2018-10-10 21:21:44 +01:00
}
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2020-09-16 19:45:56 +01:00
# ifdef USE_TUYA_MCU
}
# endif // USE_TUYA_MCU
2018-10-10 21:21:44 +01:00
}
2020-03-05 17:45:43 +00:00
# ifdef USE_LIGHT
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " d0 " ) , tmp , sizeof ( tmp ) ) ; // 0 - 100 Dimmer value
2018-10-10 21:21:44 +01:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_DIMMER " %s " ) , tmp ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2018-10-10 21:21:44 +01:00
}
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " w0 " ) , tmp , sizeof ( tmp ) ) ; // 0 - 100 White value
2020-01-16 13:22:39 +00:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_WHITE " %s " ) , tmp ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2020-01-16 13:22:39 +00:00
}
2020-03-05 13:53:51 +00:00
uint32_t light_device = LightDevice ( ) ; // Channel number offset
2020-10-30 11:29:48 +00:00
uint32_t pwm_channels = ( TasmotaGlobal . light_type & 7 ) > LST_MAX ? LST_MAX : ( TasmotaGlobal . light_type & 7 ) ;
2020-03-05 13:53:51 +00:00
for ( uint32_t j = 0 ; j < pwm_channels ; j + + ) {
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " e%d " ) , j + 1 ) ;
2019-10-15 15:41:53 +01:00
WebGetArg ( webindex , tmp , sizeof ( tmp ) ) ; // 0 - 100 percent
if ( strlen ( tmp ) ) {
2020-03-05 13:53:51 +00:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_CHANNEL " %d %s " ) , j + light_device , tmp ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2019-10-15 15:41:53 +01:00
}
}
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " t0 " ) , tmp , sizeof ( tmp ) ) ; // 153 - 500 Color temperature
2018-10-10 21:21:44 +01:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_COLORTEMPERATURE " %s " ) , tmp ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2018-10-10 21:21:44 +01:00
}
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " h0 " ) , tmp , sizeof ( tmp ) ) ; // 0 - 359 Hue value
2019-11-19 20:22:45 +00:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_HSBCOLOR " 1 %s " ) , tmp ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2019-11-19 20:22:45 +00:00
}
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " n0 " ) , tmp , sizeof ( tmp ) ) ; // 0 - 99 Saturation value
2019-11-19 20:22:45 +00:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_HSBCOLOR " 2 %s " ) , tmp ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2019-11-19 20:22:45 +00:00
}
2020-03-05 17:45:43 +00:00
# endif // USE_LIGHT
2019-09-29 17:00:01 +01:00
# ifdef USE_SHUTTER
2020-10-30 11:29:48 +00:00
for ( uint32_t j = 1 ; j < = TasmotaGlobal . shutters_present ; j + + ) {
2023-05-21 11:25:11 +01:00
uint8_t percent ;
2019-09-29 17:00:01 +01:00
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " u%d " ) , j ) ;
WebGetArg ( webindex , tmp , sizeof ( tmp ) ) ; // 0 - 100 percent
2023-05-21 11:25:11 +01:00
percent = atoi ( tmp ) ;
2019-09-29 17:00:01 +01:00
if ( strlen ( tmp ) ) {
2023-05-21 11:25:11 +01:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " ShutterPosition%d %d " ) , j , ( ShutterGetOptions ( j - 1 ) & 1 ) ? 100 - percent : percent ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2019-09-29 17:00:01 +01:00
}
}
# endif // USE_SHUTTER
2020-12-12 18:05:47 +00:00
# ifdef USE_ZIGBEE
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " zbj " ) , tmp , sizeof ( tmp ) ) ;
2020-12-12 18:05:47 +00:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " ZbPermitJoin " ) ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2020-12-12 18:05:47 +00:00
}
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " zbr " ) , tmp , sizeof ( tmp ) ) ;
2020-12-12 18:05:47 +00:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " ZbMap " ) ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( svalue ) ;
2020-12-12 18:05:47 +00:00
}
# endif // USE_ZIGBEE
2021-02-02 13:57:53 +00:00
2022-11-11 08:57:00 +00:00
XsnsXdrvCall ( FUNC_WEB_GET_ARG ) ;
2021-12-15 10:15:30 +00:00
2021-02-02 13:57:53 +00:00
# ifdef USE_WEB_SSE
WSContentBegin ( 200 , CT_STREAM ) ;
WSContentSend_P ( PSTR ( " data: " ) ) ;
# else
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_HTML ) ;
2021-02-02 13:57:53 +00:00
# endif // USE_WEB_SSE
2019-03-19 16:31:43 +00:00
WSContentSend_P ( PSTR ( " {t} " ) ) ;
2022-01-16 15:19:28 +00:00
if ( Settings - > web_time_end ) {
WSContentSend_P ( PSTR ( " {s} " D_TIMER_TIME " {m}%s{e} " ) , GetDateAndTime ( DT_LOCAL ) . substring ( Settings - > web_time_start , Settings - > web_time_end ) . c_str ( ) ) ;
}
2022-11-11 08:57:00 +00:00
XsnsXdrvCall ( FUNC_WEB_SENSOR ) ;
2019-09-04 19:58:17 +01:00
2019-03-19 16:31:43 +00:00
WSContentSend_P ( PSTR ( " </table> " ) ) ;
2020-10-30 11:29:48 +00:00
if ( TasmotaGlobal . devices_present ) {
2019-03-16 15:23:41 +00:00
WSContentSend_P ( PSTR ( " {t}<tr> " ) ) ;
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) {
2021-01-12 18:31:15 +00:00
WSContentSend_P ( HTTP_DEVICE_STATE , 36 , ( bitRead ( TasmotaGlobal . power , 0 ) ) ? PSTR ( " bold " ) : PSTR ( " normal " ) , 54 , GetStateText ( bitRead ( TasmotaGlobal . power , 0 ) ) ) ;
2019-07-27 17:37:56 +01:00
uint32_t fanspeed = GetFanspeed ( ) ;
2018-10-10 21:21:44 +01:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %d " ) , fanspeed ) ;
2021-01-12 18:31:15 +00:00
WSContentSend_P ( HTTP_DEVICE_STATE , 64 , ( fanspeed ) ? PSTR ( " bold " ) : PSTR ( " normal " ) , 54 , ( fanspeed ) ? svalue : GetStateText ( 0 ) ) ;
2018-10-10 21:21:44 +01:00
} else {
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2021-04-02 14:33:05 +01:00
uint32_t cols = WebDeviceColumns ( ) ;
uint32_t fontsize = ( cols < 5 ) ? 70 - ( cols * 8 ) : 32 ;
2020-10-30 11:29:48 +00:00
for ( uint32_t idx = 1 ; idx < = TasmotaGlobal . devices_present ; idx + + ) {
2020-10-28 18:03:39 +00:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %d " ) , bitRead ( TasmotaGlobal . power , idx - 1 ) ) ;
2021-04-02 14:33:05 +01:00
WSContentSend_P ( HTTP_DEVICE_STATE , 100 / cols , ( bitRead ( TasmotaGlobal . power , idx - 1 ) ) ? PSTR ( " bold " ) : PSTR ( " normal " ) , fontsize ,
( cols < 5 ) ? GetStateText ( bitRead ( TasmotaGlobal . power , idx - 1 ) ) : svalue ) ;
if ( 0 = = idx % cols ) { WSContentSend_P ( PSTR ( " </tr><tr> " ) ) ; }
2018-10-10 21:21:44 +01:00
}
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2018-10-10 21:21:44 +01:00
}
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2020-09-16 19:45:56 +01:00
2019-03-16 15:23:41 +00:00
WSContentSend_P ( PSTR ( " </tr></table> " ) ) ;
2018-10-10 21:21:44 +01:00
}
2021-02-02 14:48:29 +00:00
WSContentSend_P ( PSTR ( " \n \n " ) ) ; // Prep for SSE
2019-03-16 15:23:41 +00:00
WSContentEnd ( ) ;
2019-03-01 17:25:46 +00:00
return true ;
2018-10-10 21:21:44 +01:00
}
2020-01-09 08:17:39 +00:00
# ifdef USE_SHUTTER
int32_t IsShutterWebButton ( uint32_t idx ) {
/* 0: Not a shutter, 1..4: shutter up idx, -1..-4: shutter down idx */
int32_t ShutterWebButton = 0 ;
2021-06-11 17:14:12 +01:00
if ( Settings - > flag3 . shutter_mode ) { // SetOption80 - Enable shutter support
2023-04-01 13:53:01 +01:00
for ( uint32_t i = 0 ; i < TasmotaGlobal . shutters_present ; i + + ) {
if ( ShutterGetStartRelay ( i ) & & ( ( ShutterGetStartRelay ( i ) = = idx ) | | ( ShutterGetStartRelay ( i ) = = ( idx - 1 ) ) ) ) {
ShutterWebButton = ( ShutterGetStartRelay ( i ) = = idx ) ? ( i + 1 ) : ( - 1 - i ) ;
2020-01-09 08:17:39 +00:00
break ;
}
}
}
return ShutterWebButton ;
}
# endif // USE_SHUTTER
2018-10-10 21:21:44 +01:00
/*-------------------------------------------------------------------------------------------*/
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2018-10-11 07:32:09 +01:00
2018-11-14 13:32:09 +00:00
void HandleConfiguration ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_CONFIGURATION ) ) ;
2018-10-10 21:21:44 +01:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONFIGURATION ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-11 09:38:41 +00:00
WSContentButton ( BUTTON_MODULE ) ;
WSContentButton ( BUTTON_WIFI ) ;
2018-10-10 21:21:44 +01:00
2022-11-11 08:57:00 +00:00
XdrvXsnsCall ( FUNC_WEB_ADD_BUTTON ) ;
2018-10-10 21:21:44 +01:00
2019-03-11 09:38:41 +00:00
WSContentButton ( BUTTON_LOGGING ) ;
WSContentButton ( BUTTON_OTHER ) ;
WSContentButton ( BUTTON_TEMPLATE ) ;
WSContentSpaceButton ( BUTTON_RESET_CONFIGURATION ) ;
WSContentButton ( BUTTON_BACKUP ) ;
WSContentButton ( BUTTON_RESTORE ) ;
WSContentSpaceButton ( BUTTON_MAIN ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2020-10-09 16:59:42 +01:00
void WSContentSendNiceLists ( uint32_t option ) {
char stemp [ 30 ] ; // Template number and Sensor name
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( kGpioNiceList ) ; i + + ) { // GPIO: }2'0'>None (0)}3}2'17'>Button1 (17)}3...
2020-10-09 16:59:42 +01:00
if ( option & & ( 1 = = i ) ) {
2021-01-18 20:48:04 +00:00
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX , AGPIO ( GPIO_USER ) , PSTR ( D_SENSOR_USER ) ) ; // }2'255'>User}3
2020-10-09 16:59:42 +01:00
}
uint32_t ridx = pgm_read_word ( kGpioNiceList + i ) & 0xFFE0 ;
uint32_t midx = BGPIO ( ridx ) ;
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX , ridx , GetTextIndexed ( stemp , sizeof ( stemp ) , midx , kSensorNames ) ) ;
}
WSContentSend_P ( PSTR ( " \" ; " ) ) ;
WSContentSend_P ( PSTR ( " hs=[ " ) ) ;
uint32_t midx ;
bool first_done = false ;
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( kGpioNiceList ) ; i + + ) { // hs=[36,68,100,132,168,200,232,264,292,324,356,388,421,453];
2020-10-09 16:59:42 +01:00
midx = pgm_read_word ( kGpioNiceList + i ) ;
if ( midx & 0x001F ) {
if ( first_done ) { WSContentSend_P ( PSTR ( " , " ) ) ; }
WSContentSend_P ( PSTR ( " %d " ) , midx ) ;
first_done = true ;
}
}
# ifdef ESP8266
# ifdef USE_ADC
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( kAdcNiceList ) ; i + + ) { // hs=[36,68,100,132,168,200,232,264,292,324,356,388,421,453];
2020-10-09 16:59:42 +01:00
midx = pgm_read_word ( kAdcNiceList + i ) ;
if ( midx & 0x001F ) {
if ( first_done ) { WSContentSend_P ( PSTR ( " , " ) ) ; }
WSContentSend_P ( PSTR ( " %d " ) , midx ) ;
first_done = true ;
}
}
# endif // USE_ADC
# endif // ESP8266
WSContentSend_P ( PSTR ( " ]; " ) ) ;
}
# ifdef ESP8266
# ifdef USE_ADC
void WSContentSendAdcNiceList ( uint32_t option ) {
char stemp [ 30 ] ; // Template number and Sensor name
WSContentSend_P ( PSTR ( " os= \" " ) ) ;
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( kAdcNiceList ) ; i + + ) { // GPIO: }2'0'>None}3}2'17'>Analog}3...
2020-10-09 16:59:42 +01:00
if ( option & & ( 1 = = i ) ) {
2021-01-18 20:48:04 +00:00
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX , AGPIO ( GPIO_USER ) , PSTR ( D_SENSOR_USER ) ) ; // }2'15'>User}3
2020-10-09 16:59:42 +01:00
}
uint32_t ridx = pgm_read_word ( kAdcNiceList + i ) & 0xFFE0 ;
uint32_t midx = BGPIO ( ridx ) ;
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE_NO_INDEX , ridx , GetTextIndexed ( stemp , sizeof ( stemp ) , midx , kSensorNames ) ) ;
}
}
# endif // USE_ADC
# endif // ESP8266
/*-------------------------------------------------------------------------------------------*/
2021-04-08 16:57:37 +01:00
void HandleTemplateConfiguration ( void ) {
2019-02-17 10:32:53 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-18 20:48:04 +00:00
if ( Webserver - > hasArg ( F ( " save " ) ) ) {
2019-02-17 10:32:53 +00:00
TemplateSaveSettings ( ) ;
2019-02-18 14:13:37 +00:00
WebRestart ( 1 ) ;
2019-02-17 10:32:53 +00:00
return ;
}
2019-07-23 21:59:23 +01:00
char stemp [ 30 ] ; // Template number and Sensor name
2019-02-17 10:32:53 +00:00
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " t " ) , stemp , sizeof ( stemp ) ) ; // 0 - 69 Template number
2019-02-17 10:32:53 +00:00
if ( strlen ( stemp ) ) {
2019-07-27 17:37:56 +01:00
uint32_t module = atoi ( stemp ) ;
2021-06-11 17:14:12 +01:00
uint32_t module_save = Settings - > module ;
Settings - > module = module ;
2020-11-24 14:14:22 +00:00
myio template_gp ;
TemplateGpios ( & template_gp ) ;
2019-02-17 10:32:53 +00:00
gpio_flag flag = ModuleFlag ( ) ;
2021-06-11 17:14:12 +01:00
Settings - > module = module_save ;
2019-02-17 10:32:53 +00:00
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_PLAIN ) ;
WSContentSend_P ( PSTR ( " %s}1 " ) , AnyModuleName ( module ) . c_str ( ) ) ; // NAME: Generic
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( template_gp . io ) ; i + + ) { // 17,148,29,149,7,255,255,255,138,255,139,255,255
2023-08-21 15:18:21 +01:00
# if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
// ESP32C2/C3/C6 we always send all GPIOs, Flash are just hidden
2021-06-14 20:32:07 +01:00
WSContentSend_P ( PSTR ( " %s%d " ) , ( i > 0 ) ? " , " : " " , template_gp . io [ i ] ) ;
# else
2020-04-12 17:17:35 +01:00
if ( ! FlashPin ( i ) ) {
2020-11-24 14:14:22 +00:00
WSContentSend_P ( PSTR ( " %s%d " ) , ( i > 0 ) ? " , " : " " , template_gp . io [ i ] ) ;
2019-02-17 10:32:53 +00:00
}
2021-06-14 20:32:07 +01:00
# endif
2019-02-17 10:32:53 +00:00
}
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1%d}1%d " ) , flag , Settings - > user_template_base ) ; // FLAG: 1 BASE: 17
2019-03-16 15:23:41 +00:00
WSContentEnd ( ) ;
2019-02-17 10:32:53 +00:00
return ;
}
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_CONFIGURE_TEMPLATE ) ) ;
2019-02-17 10:32:53 +00:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONFIGURE_TEMPLATE ) ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_SCRIPT_MODULE_TEMPLATE ) ;
2020-04-25 14:34:18 +01:00
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_SCRIPT_TEMPLATE ) ;
2020-05-01 15:47:41 +01:00
2020-10-09 16:59:42 +01:00
WSContentSendNiceLists ( 1 ) ;
2020-05-01 15:47:41 +01:00
2020-04-25 14:34:18 +01:00
WSContentSend_P ( HTTP_SCRIPT_TEMPLATE2 ) ;
2020-05-01 15:47:41 +01:00
2020-09-29 13:08:48 +01:00
# ifdef ESP8266
2020-10-09 16:59:42 +01:00
# ifdef USE_ADC
WSContentSendAdcNiceList ( 1 ) ;
2020-09-29 13:08:48 +01:00
WSContentSend_P ( HTTP_SCRIPT_TEMPLATE3 ) ;
2020-10-09 16:59:42 +01:00
# endif // USE_ADC
2020-09-29 13:08:48 +01:00
# endif // ESP8266
2020-05-01 15:47:41 +01:00
WSContentSend_P ( HTTP_SCRIPT_TEMPLATE4 ) ;
2020-04-25 14:34:18 +01:00
for ( uint32_t i = 0 ; i < sizeof ( kModuleNiceList ) ; i + + ) { // "}2'%d'>%s (%d)}3" - "}2'0'>Sonoff Basic (1)}3"
uint32_t midx = pgm_read_byte ( kModuleNiceList + i ) ;
2020-05-07 17:10:54 +01:00
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE_INDEX , midx , AnyModuleName ( midx ) . c_str ( ) , midx + 1 ) ;
2020-04-25 14:34:18 +01:00
}
2020-05-01 15:47:41 +01:00
WSContentSend_P ( HTTP_SCRIPT_TEMPLATE5 ) ;
2020-04-25 14:34:18 +01:00
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_TEMPLATE ) ;
2019-03-15 13:10:42 +00:00
WSContentSend_P ( HTTP_TABLE100 ) ;
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <tr><td><b> " D_TEMPLATE_NAME " </b></td><td style='width:200px'><input id='s1' placeholder=' " D_TEMPLATE_NAME " '></td></tr> "
" <tr><td><b> " D_BASE_TYPE " </b></td><td><select id='g99' onchange='st(this.value)'></select></td></tr> "
2019-03-15 13:10:42 +00:00
" </table> "
" <hr/> " ) ) ;
WSContentSend_P ( HTTP_TABLE100 ) ;
2020-04-12 17:17:35 +01:00
for ( uint32_t i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
2023-08-21 15:18:21 +01:00
# if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
// ESP32C2/C3/C6 all gpios are in the template, flash are hidden
2021-06-14 20:32:07 +01:00
bool hidden = FlashPin ( i ) ;
WSContentSend_P ( PSTR ( " <tr%s><td><b><font color='#%06x'> " D_GPIO " %d</font></b></td><td%s><select id='g%d' onchange='ot(%d,this.value)'></select></td> " ) ,
hidden ? PSTR ( " hidden " ) : " " ,
RedPin ( i ) ? WebColor ( COL_TEXT_WARNING ) : WebColor ( COL_TEXT ) , i , ( 0 = = i ) ? PSTR ( " style='width:146px' " ) : " " , i , i ) ;
WSContentSend_P ( PSTR ( " <td style='width:54px'><select id='h%d'></select></td></tr> " ) , i ) ;
2021-09-04 13:20:09 +01:00
# else // also works for ESP32S2
2020-04-12 17:17:35 +01:00
if ( ! FlashPin ( i ) ) {
2020-05-01 15:47:41 +01:00
WSContentSend_P ( PSTR ( " <tr><td><b><font color='#%06x'> " D_GPIO " %d</font></b></td><td%s><select id='g%d' onchange='ot(%d,this.value)'></select></td> " ) ,
2021-06-08 19:31:01 +01:00
RedPin ( i ) ? WebColor ( COL_TEXT_WARNING ) : WebColor ( COL_TEXT ) , i , ( 0 = = i ) ? PSTR ( " style='width:146px' " ) : " " , i , i ) ;
2021-02-04 16:06:45 +00:00
WSContentSend_P ( PSTR ( " <td style='width:54px'><select id='h%d'></select></td></tr> " ) , i ) ;
2019-02-17 10:32:53 +00:00
}
2021-06-14 20:32:07 +01:00
# endif
2019-02-17 10:32:53 +00:00
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " </table> " ) ) ;
2020-05-01 15:47:41 +01:00
2019-05-13 14:56:01 +01:00
gpio_flag flag = ModuleFlag ( ) ;
2020-05-01 15:47:41 +01:00
if ( flag . data ) {
2019-05-13 14:56:01 +01:00
WSContentSend_P ( HTTP_FORM_TEMPLATE_FLAG ) ;
}
2020-05-01 15:47:41 +01:00
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_END ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2019-02-17 10:32:53 +00:00
}
2020-10-09 16:59:42 +01:00
uint16_t WebGetGpioArg ( uint32_t i ) {
char webindex [ 5 ] ; // WebGetArg name
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " g%d " ) , i ) ;
char tmp [ 8 ] ; // WebGetArg numbers only
WebGetArg ( webindex , tmp , sizeof ( tmp ) ) ; // GPIO
uint32_t gpio = ( ! strlen ( tmp ) ) ? 0 : atoi ( tmp ) ;
char webindex2 [ 5 ] ; // WebGetArg name
snprintf_P ( webindex2 , sizeof ( webindex2 ) , PSTR ( " h%d " ) , i ) ;
char tmp2 [ 8 ] ; // WebGetArg numbers only
WebGetArg ( webindex2 , tmp2 , sizeof ( tmp2 ) ) ;
uint32_t value2 = ( ! strlen ( tmp2 ) ) ? 0 : atoi ( tmp2 ) - 1 ;
gpio + = value2 ;
return gpio ;
}
2021-04-08 16:57:37 +01:00
void TemplateSaveSettings ( void ) {
char tmp [ TOPSZ ] ; // WebGetArg NAME and GPIO/BASE/FLAG byte value
2021-04-13 09:15:35 +01:00
char command [ 300 ] ; // Template command string
2019-02-17 10:32:53 +00:00
2021-04-08 16:57:37 +01:00
WebGetArg ( PSTR ( " s1 " ) , tmp , sizeof ( tmp ) ) ; // NAME
2021-04-09 11:18:26 +01:00
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_TEMPLATE " { \" " D_JSON_NAME " \" : \" %s \" , \" " D_JSON_GPIO " \" :[ " ) , tmp ) ;
2019-02-17 10:32:53 +00:00
2019-07-27 17:37:56 +01:00
uint32_t j = 0 ;
2021-06-11 17:14:12 +01:00
for ( uint32_t i = 0 ; i < nitems ( Settings - > user_template . gp . io ) ; i + + ) {
2023-08-21 15:18:21 +01:00
/*
2021-06-14 20:32:07 +01:00
# if defined(ESP32) && CONFIG_IDF_TARGET_ESP32C3
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( i ) ) ;
2022-02-01 11:05:56 +00:00
# elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
2021-09-04 13:20:09 +01:00
if ( 22 = = i ) { j = 33 ; } // skip 22-32
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( j ) ) ;
j + + ;
2021-09-05 18:43:53 +01:00
# elif defined(CONFIG_IDF_TARGET_ESP32)
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( Esp32TemplateToPhy [ i ] ) ) ;
# else // ESP8266
2019-02-17 10:32:53 +00:00
if ( 6 = = i ) { j = 9 ; }
if ( 8 = = i ) { j = 12 ; }
2021-04-09 11:18:26 +01:00
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( j ) ) ;
2019-02-17 10:32:53 +00:00
j + + ;
2021-06-14 20:32:07 +01:00
# endif
2023-08-21 15:18:21 +01:00
*/
# ifdef ESP8266
if ( 6 = = i ) { j = 9 ; }
if ( 8 = = i ) { j = 12 ; }
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( j ) ) ;
j + + ;
# endif // ESP8266
# ifdef ESP32
# if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( i ) ) ;
# elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
if ( 22 = = i ) { j = 33 ; } // skip 22-32
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( j ) ) ;
j + + ;
# else // ESP32
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s%s%d " ) , command , ( i > 0 ) ? " , " : " " , WebGetGpioArg ( Esp32TemplateToPhy [ i ] ) ) ;
# endif // ESP32C2/C3/C6 and S2/S3
# endif // ESP32
2019-02-17 10:32:53 +00:00
}
2020-05-01 15:47:41 +01:00
uint32_t flag = 0 ;
2021-04-08 16:57:37 +01:00
char webindex [ 5 ] ; // WebGetArg name
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < GPIO_FLAG_USED ; i + + ) {
2019-02-23 17:38:36 +00:00
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " c%d " ) , i ) ;
2021-04-08 16:57:37 +01:00
uint32_t state = Webserver - > hasArg ( webindex ) < < i ; // FLAG
2019-02-17 10:32:53 +00:00
flag + = state ;
}
2021-04-08 16:57:37 +01:00
WebGetArg ( PSTR ( " g99 " ) , tmp , sizeof ( tmp ) ) ; // BASE
2019-07-27 17:37:56 +01:00
uint32_t base = atoi ( tmp ) + 1 ;
2019-02-17 10:32:53 +00:00
2021-04-09 11:18:26 +01:00
snprintf_P ( command , sizeof ( command ) , PSTR ( " %s], \" " D_JSON_FLAG " \" :%d, \" " D_JSON_BASE " \" :%d} " ) , command , flag , base ) ;
ExecuteWebCommand ( command ) ;
2019-02-17 10:32:53 +00:00
}
/*-------------------------------------------------------------------------------------------*/
2021-04-08 16:57:37 +01:00
void HandleModuleConfiguration ( void ) {
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2018-10-10 21:21:44 +01:00
2021-01-18 20:48:04 +00:00
if ( Webserver - > hasArg ( F ( " save " ) ) ) {
2018-10-10 21:21:44 +01:00
ModuleSaveSettings ( ) ;
2018-10-12 10:42:52 +01:00
WebRestart ( 1 ) ;
2018-10-10 21:21:44 +01:00
return ;
}
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_CONFIGURE_MODULE ) ) ;
2020-04-25 12:30:00 +01:00
2019-07-23 22:19:27 +01:00
char stemp [ 30 ] ; // Sensor name
2019-07-27 17:37:56 +01:00
uint32_t midx ;
2020-11-24 14:14:22 +00:00
myio template_gp ;
TemplateGpios ( & template_gp ) ;
2018-11-10 14:10:58 +00:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONFIGURE_MODULE ) ) ;
2020-04-25 12:30:00 +01:00
WSContentSend_P ( HTTP_SCRIPT_MODULE_TEMPLATE ) ;
2019-02-02 14:16:35 +00:00
2020-04-25 12:30:00 +01:00
WSContentSend_P ( PSTR ( " function sl(){os= \" " ) ) ;
uint32_t vidx = 0 ;
for ( uint32_t i = 0 ; i < = sizeof ( kModuleNiceList ) ; 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 ;
} else {
midx = pgm_read_byte ( kModuleNiceList + i - 1 ) ;
vidx = midx + 1 ;
2018-11-10 14:10:58 +00:00
}
2020-05-07 17:10:54 +01:00
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE_INDEX , midx , AnyModuleName ( midx ) . c_str ( ) , vidx ) ;
2018-10-10 21:21:44 +01:00
}
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " \" ;sk(%d,99);os= \" " ) , Settings - > module ) ;
2020-04-30 17:47:34 +01:00
2020-10-09 16:59:42 +01:00
WSContentSendNiceLists ( 0 ) ;
2020-04-30 17:47:34 +01:00
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( template_gp . io ) ; i + + ) {
2020-11-24 14:14:22 +00:00
if ( ValidGPIO ( i , template_gp . io [ i ] ) ) {
2020-10-30 11:29:48 +00:00
WSContentSend_P ( PSTR ( " sk(%d,%d); " ) , TasmotaGlobal . my_module . io [ i ] , i ) ; // g0 - g17
2018-10-10 21:21:44 +01:00
}
}
2020-05-01 10:48:12 +01:00
2020-09-29 13:08:48 +01:00
# ifdef ESP8266
2020-10-09 16:59:42 +01:00
# ifdef USE_ADC
WSContentSendAdcNiceList ( 0 ) ;
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " \" ;sk(%d, " STR ( ADC0_PIN ) " ); " ) , Settings - > my_gp . io [ ( sizeof ( myio ) / 2 ) - 1 ] ) ;
2020-10-09 16:59:42 +01:00
# endif // USE_ADC
2020-09-29 13:08:48 +01:00
# endif // ESP8266
2020-05-01 10:48:12 +01:00
2020-04-25 12:30:00 +01:00
WSContentSend_P ( PSTR ( " }wl(sl); " ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
WSContentSend_P ( HTTP_FORM_MODULE , AnyModuleName ( MODULE ) . c_str ( ) ) ;
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( template_gp . io ) ; i + + ) {
2020-11-24 14:14:22 +00:00
if ( ValidGPIO ( i , template_gp . io [ i ] ) ) {
2020-04-18 17:10:41 +01:00
snprintf_P ( stemp , 3 , PINS_WEMOS + i * 2 ) ;
2021-02-04 16:06:45 +00:00
WSContentSend_P ( PSTR ( " <tr><td style='width:116px'>%s <b> " D_GPIO " %d</b></td><td style='width:146px'><select id='g%d' onchange='ot(%d,this.value)'></select></td> " ) ,
2020-10-30 11:29:48 +00:00
( WEMOS = = TasmotaGlobal . module_type ) ? stemp : " " , i , i , i ) ;
2021-02-04 16:06:45 +00:00
WSContentSend_P ( PSTR ( " <td style='width:54px'><select id='h%d'></select></td></tr> " ) , i ) ;
2018-10-10 21:21:44 +01:00
}
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " </table> " ) ) ;
WSContentSend_P ( HTTP_FORM_END ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2021-04-08 16:57:37 +01:00
void ModuleSaveSettings ( void ) {
2019-02-23 17:38:36 +00:00
char tmp [ 8 ] ; // WebGetArg numbers only
2021-04-08 16:57:37 +01:00
WebGetArg ( PSTR ( " g99 " ) , tmp , sizeof ( tmp ) ) ; // Module
2019-07-27 17:37:56 +01:00
uint32_t new_module = ( ! strlen ( tmp ) ) ? MODULE : atoi ( tmp ) ;
2021-06-11 17:14:12 +01:00
Settings - > last_module = Settings - > module ;
Settings - > module = new_module ;
2019-02-11 18:21:49 +00:00
SetModuleType ( ) ;
2020-11-24 14:14:22 +00:00
myio template_gp ;
TemplateGpios ( & template_gp ) ;
2021-02-28 11:50:02 +00:00
for ( uint32_t i = 0 ; i < nitems ( template_gp . io ) ; i + + ) {
2021-06-11 17:14:12 +01:00
if ( Settings - > last_module ! = new_module ) {
Settings - > my_gp . io [ i ] = GPIO_NONE ;
2018-10-10 21:21:44 +01:00
} else {
2020-11-24 14:14:22 +00:00
if ( ValidGPIO ( i , template_gp . io [ i ] ) ) {
2021-06-11 17:14:12 +01:00
Settings - > my_gp . io [ i ] = WebGetGpioArg ( i ) ; // Gpio
2018-10-10 21:21:44 +01:00
}
}
}
2021-04-08 16:57:37 +01:00
char command [ 32 ] ;
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_BACKLOG " 0 " D_CMND_MODULE " ; " D_CMND_GPIO ) ) ;
ExecuteWebCommand ( command ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2021-04-08 16:57:37 +01:00
void HandleWifiConfiguration ( void ) {
2021-04-12 17:36:43 +01:00
char tmp [ TOPSZ ] ; // Max length is currently 150
2019-03-07 17:18:30 +00:00
if ( ! HttpCheckPriviledgedAccess ( ! WifiIsInManagerMode ( ) ) ) { return ; }
2018-10-10 21:21:44 +01:00
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_CONFIGURE_WIFI ) ) ;
2018-10-10 21:21:44 +01:00
2021-01-18 20:48:04 +00:00
if ( Webserver - > hasArg ( F ( " save " ) ) & & HTTP_MANAGER_RESET_ONLY ! = Web . state ) {
2021-04-12 17:36:43 +01:00
if ( WifiIsInManagerMode ( ) ) {
// Test WIFI Connection to Router
// As Tasmota is in this case in AP mode, a STA connection can be established too at the same time
2021-07-09 17:27:47 +01:00
2022-08-03 06:35:16 +01:00
if ( WIFI_NOT_TESTING = = Wifi . wifiTest ) {
if ( MAX_WIFI_OPTION = = Wifi . old_wificonfig ) { Wifi . old_wificonfig = Settings - > sta_config ; }
2021-07-09 17:27:47 +01:00
TasmotaGlobal . wifi_state_flag = Settings - > sta_config = WIFI_MANAGER ;
2022-08-03 06:35:16 +01:00
Wifi . save_data_counter = TasmotaGlobal . save_data_counter ;
2021-07-09 17:27:47 +01:00
}
2022-08-03 06:35:16 +01:00
Wifi . wifi_test_counter = 9 ; // seconds to test user's proposed AP
Wifi . wifiTest = WIFI_TESTING ;
2021-04-12 17:36:43 +01:00
TasmotaGlobal . save_data_counter = 0 ; // Stop auto saving data - Updating Settings
2021-06-11 17:14:12 +01:00
Settings - > save_data = 0 ;
2021-04-12 17:36:43 +01:00
TasmotaGlobal . sleep = 0 ; // Disable sleep
TasmotaGlobal . restart_flag = 0 ; // No restart
TasmotaGlobal . ota_state_flag = 0 ; // No OTA
// TasmotaGlobal.blinks = 0; // Disable blinks initiated by WifiManager
WebGetArg ( PSTR ( " s1 " ) , tmp , sizeof ( tmp ) ) ; // SSID1
SettingsUpdateText ( SET_STASSID1 , tmp ) ;
WebGetArg ( PSTR ( " p1 " ) , tmp , sizeof ( tmp ) ) ; // PASSWORD1
SettingsUpdateText ( SET_STAPWD1 , tmp ) ;
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CONNECTING_TO_AP " %s " D_AS " %s ... " ) ,
SettingsText ( SET_STASSID1 ) , TasmotaGlobal . hostname ) ;
WiFi . begin ( SettingsText ( SET_STASSID1 ) , SettingsText ( SET_STAPWD1 ) ) ;
WebRestart ( 2 ) ;
} else {
// STATION MODE or MIXED
// Save the config and restart
2021-04-13 11:00:42 +01:00
WifiSaveSettings ( ) ;
2021-04-12 17:36:43 +01:00
WebRestart ( 1 ) ;
}
2018-10-10 21:21:44 +01:00
return ;
}
2022-08-03 06:35:16 +01:00
if ( WIFI_TEST_FINISHED = = Wifi . wifiTest ) {
Wifi . wifiTest = WIFI_NOT_TESTING ;
if ( Wifi . wifi_test_AP_TIMEOUT ) {
2021-07-22 14:14:58 +01:00
WebRestart ( 1 ) ; // Save credentials and Force Restart in STA only mode (11n-only routers)
2021-07-05 14:00:10 +01:00
} else {
2021-04-12 17:36:43 +01:00
# if (RESTART_AFTER_INITIAL_WIFI_CONFIG)
2021-07-05 14:00:10 +01:00
WebRestart ( 3 ) ;
2021-04-12 17:36:43 +01:00
# else
2021-07-05 14:00:10 +01:00
HandleRoot ( ) ;
2021-04-12 17:36:43 +01:00
# endif
2021-07-05 14:00:10 +01:00
}
2021-04-12 17:36:43 +01:00
}
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONFIGURE_WIFI ) , ! WifiIsInManagerMode ( ) ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_SCRIPT_WIFI ) ;
2021-04-12 17:36:43 +01:00
if ( WifiIsInManagerMode ( ) ) { WSContentSend_P ( HTTP_SCRIPT_HIDE ) ; }
2022-08-03 06:35:16 +01:00
if ( WIFI_TESTING = = Wifi . wifiTest ) { WSContentSend_P ( HTTP_SCRIPT_RELOAD_TIME , HTTP_RESTART_RECONNECT_TIME ) ; }
2020-12-27 15:25:34 +00:00
# ifdef USE_ENHANCED_GUI_WIFI_SCAN
WSContentSendStyle_P ( HTTP_HEAD_STYLE_SSI , WebColor ( COL_TEXT ) ) ;
# else
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2020-12-27 15:25:34 +00:00
# endif // USE_ENHANCED_GUI_WIFI_SCAN
2018-10-10 21:21:44 +01:00
2021-04-12 17:36:43 +01:00
bool limitScannedNetworks = true ;
2019-08-15 12:50:28 +01:00
if ( HTTP_MANAGER_RESET_ONLY ! = Web . state ) {
2022-08-03 06:35:16 +01:00
if ( WIFI_TESTING = = Wifi . wifiTest ) {
2021-04-12 17:36:43 +01:00
limitScannedNetworks = false ;
} else {
if ( Webserver - > hasArg ( F ( " scan " ) ) ) { limitScannedNetworks = false ; }
2021-04-13 16:00:54 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI " Scanning... " ) ) ;
2019-02-23 17:38:36 +00:00
# ifdef USE_EMULATION
2019-02-21 16:49:11 +00:00
UdpDisconnect ( ) ;
2019-02-23 17:38:36 +00:00
# endif // USE_EMULATION
2019-02-21 16:49:11 +00:00
int n = WiFi . scanNetworks ( ) ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_SCAN_DONE ) ) ;
2019-02-21 16:49:11 +00:00
if ( 0 = = n ) {
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_NO_NETWORKS_FOUND ) ) ;
2020-11-06 16:09:13 +00:00
WSContentSend_P ( PSTR ( D_NO_NETWORKS_FOUND ) ) ;
2021-04-12 17:36:43 +01:00
limitScannedNetworks = false ; // in order to show D_SCAN_FOR_WIFI_NETWORKS
2019-02-21 16:49:11 +00:00
} else {
//sort networks
int indices [ n ] ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < n ; i + + ) {
2019-02-21 16:49:11 +00:00
indices [ i ] = i ;
2018-10-10 21:21:44 +01:00
}
2019-02-21 16:49:11 +00:00
// RSSI SORT
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < n ; i + + ) {
for ( uint32_t j = i + 1 ; j < n ; j + + ) {
2019-02-21 16:49:11 +00:00
if ( WiFi . RSSI ( indices [ j ] ) > WiFi . RSSI ( indices [ i ] ) ) {
std : : swap ( indices [ i ] , indices [ j ] ) ;
2018-10-10 21:21:44 +01:00
}
}
}
2021-04-12 17:36:43 +01:00
uint32_t networksToShow = n ;
if ( ( limitScannedNetworks ) & & ( networksToShow > MAX_WIFI_NETWORKS_TO_SHOW ) ) { networksToShow = MAX_WIFI_NETWORKS_TO_SHOW ; }
2021-04-14 11:39:07 +01:00
if ( WifiIsInManagerMode ( ) ) {
WSContentTextCenterStart ( WebColor ( COL_TEXT ) ) ;
WSContentSend_P ( PSTR ( D_SELECT_YOUR_WIFI_NETWORK " </div><br> " ) ) ;
}
2021-04-12 17:36:43 +01:00
2020-12-27 15:25:34 +00:00
# ifdef USE_ENHANCED_GUI_WIFI_SCAN
//display networks in page
2021-04-12 17:36:43 +01:00
bool skipduplicated ;
int ssid_showed = 0 ;
for ( uint32_t i = 0 ; i < networksToShow ; i + + ) {
2020-12-27 15:25:34 +00:00
if ( indices [ i ] < n ) {
int32_t rssi = WiFi . RSSI ( indices [ i ] ) ;
String ssid = WiFi . SSID ( indices [ i ] ) ;
DEBUG_CORE_LOG ( PSTR ( D_LOG_WIFI D_SSID " %s, " D_BSSID " %s, " D_CHANNEL " %d, " D_RSSI " %d " ) ,
ssid . c_str ( ) , WiFi . BSSIDstr ( indices [ i ] ) . c_str ( ) , WiFi . channel ( indices [ i ] ) , rssi ) ;
2021-04-13 15:04:22 +01:00
String ssid_copy = ssid ;
if ( ! ssid_copy . length ( ) ) { ssid_copy = F ( " no_name " ) ; }
2020-12-27 15:25:34 +00:00
// Print SSID
2021-04-12 17:36:43 +01:00
if ( ! limitScannedNetworks ) {
2021-04-13 15:04:22 +01:00
WSContentSend_P ( PSTR ( " <div><a href='#p' onclick='c(this)'>%s</a><br> " ) , HtmlEscape ( ssid_copy ) . c_str ( ) ) ;
2021-04-12 17:36:43 +01:00
}
skipduplicated = false ;
2020-12-27 15:25:34 +00:00
String nextSSID = " " ;
// Handle all APs with the same SSID
for ( uint32_t j = 0 ; j < n ; j + + ) {
if ( ( indices [ j ] < n ) & & ( ( nextSSID = WiFi . SSID ( indices [ j ] ) ) = = ssid ) ) {
2021-04-12 17:36:43 +01:00
if ( ! skipduplicated ) {
// Update RSSI / quality
rssi = WiFi . RSSI ( indices [ j ] ) ;
uint32_t rssi_as_quality = WifiGetRssiAsQuality ( rssi ) ;
uint32_t num_bars = changeUIntScale ( rssi_as_quality , 0 , 100 , 0 , 4 ) ;
2021-04-13 15:04:22 +01:00
WSContentSend_P ( PSTR ( " <div title='%d dBm (%d%%)'> " ) , rssi , rssi_as_quality ) ;
2021-04-12 17:36:43 +01:00
if ( limitScannedNetworks ) {
// Print SSID and item
2021-04-13 15:04:22 +01:00
WSContentSend_P ( PSTR ( " <a href='#p' onclick='c(this)'>%s</a><span class='q'><div class='si'> " ) , HtmlEscape ( ssid_copy ) . c_str ( ) ) ;
2021-04-12 17:36:43 +01:00
ssid_showed + + ;
skipduplicated = true ; // For the simplified page, just show 1 SSID if there are many Networks with the same
} else {
// Print item
2021-04-13 15:04:22 +01:00
WSContentSend_P ( PSTR ( " %s<span class='q'>(%d) <div class='si'> " ) , WiFi . BSSIDstr ( indices [ j ] ) . c_str ( ) , WiFi . channel ( indices [ j ] )
2021-04-12 17:36:43 +01:00
) ;
2021-04-13 11:00:42 +01:00
}
2021-04-13 15:04:22 +01:00
// Print signal strength indicator
for ( uint32_t k = 0 ; k < 4 ; + + k ) {
WSContentSend_P ( PSTR ( " <i class='b%d%s'></i> " ) , k , ( num_bars < k ) ? PSTR ( " o30 " ) : PSTR ( " " ) ) ;
}
WSContentSend_P ( PSTR ( " </span></div></div> " ) ) ;
2021-04-12 17:36:43 +01:00
} else {
if ( ssid_showed < = networksToShow ) { networksToShow + + ; }
2020-12-27 15:25:34 +00:00
}
indices [ j ] = n ;
}
delay ( 0 ) ;
}
2021-04-13 15:04:22 +01:00
if ( ! limitScannedNetworks ) {
WSContentSend_P ( PSTR ( " </div> " ) ) ;
}
2020-12-27 15:25:34 +00:00
}
}
# else // No USE_ENHANCED_GUI_WIFI_SCAN
2019-02-21 16:49:11 +00:00
// remove duplicates ( must be RSSI sorted )
2019-08-15 12:50:28 +01:00
for ( uint32_t i = 0 ; i < n ; i + + ) {
if ( - 1 = = indices [ i ] ) { continue ; }
2021-01-24 15:35:36 +00:00
String cssid = WiFi . SSID ( indices [ i ] ) ;
2020-01-09 13:19:19 +00:00
uint32_t cschn = WiFi . channel ( indices [ i ] ) ;
2019-08-15 12:50:28 +01:00
for ( uint32_t j = i + 1 ; j < n ; j + + ) {
2020-01-09 13:19:19 +00:00
if ( ( cssid = = WiFi . SSID ( indices [ j ] ) ) & & ( cschn = = WiFi . channel ( indices [ j ] ) ) ) {
2019-08-15 12:50:28 +01:00
DEBUG_CORE_LOG ( PSTR ( D_LOG_WIFI D_DUPLICATE_ACCESSPOINT " %s " ) , WiFi . SSID ( indices [ j ] ) . c_str ( ) ) ;
indices [ j ] = - 1 ; // set dup aps to index -1
2019-02-21 16:49:11 +00:00
}
}
2018-10-10 21:21:44 +01:00
}
2019-02-21 16:49:11 +00:00
//display networks in page
2021-04-12 17:36:43 +01:00
for ( uint32_t i = 0 ; i < networksToShow ; i + + ) {
2019-02-21 16:49:11 +00:00
if ( - 1 = = indices [ i ] ) { continue ; } // skip dups
2020-03-29 14:17:54 +01:00
int32_t rssi = WiFi . RSSI ( indices [ i ] ) ;
2019-08-09 13:05:12 +01:00
DEBUG_CORE_LOG ( PSTR ( D_LOG_WIFI D_SSID " %s, " D_BSSID " %s, " D_CHANNEL " %d, " D_RSSI " %d " ) ,
2020-02-20 09:07:00 +00:00
WiFi . SSID ( indices [ i ] ) . c_str ( ) , WiFi . BSSIDstr ( indices [ i ] ) . c_str ( ) , WiFi . channel ( indices [ i ] ) , rssi ) ;
int quality = WifiGetRssiAsQuality ( rssi ) ;
2021-04-13 15:04:22 +01:00
String ssid_copy = WiFi . SSID ( indices [ i ] ) ;
if ( ! ssid_copy . length ( ) ) { ssid_copy = F ( " no_name " ) ; }
2020-12-27 15:25:34 +00:00
WSContentSend_P ( PSTR ( " <div><a href='#p' onclick='c(this)'>%s</a> (%d) <span class='q'>%d%% (%d dBm)</span></div> " ) ,
2021-04-13 15:04:22 +01:00
HtmlEscape ( ssid_copy ) . c_str ( ) ,
2020-12-27 15:25:34 +00:00
WiFi . channel ( indices [ i ] ) ,
quality , rssi
) ;
2019-02-21 16:49:11 +00:00
2020-12-27 15:25:34 +00:00
delay ( 0 ) ;
2019-02-21 16:49:11 +00:00
}
2020-12-27 15:25:34 +00:00
# endif // USE_ENHANCED_GUI_WIFI_SCAN
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <br> " ) ) ;
2018-10-10 21:21:44 +01:00
}
2021-04-12 17:36:43 +01:00
}
2021-04-13 11:41:13 +01:00
WSContentSend_P ( PSTR ( " <div><a href='/wi?scan='>%s</a></div><br> " ) , ( limitScannedNetworks ) ? PSTR ( D_SHOW_MORE_WIFI_NETWORKS ) : PSTR ( D_SCAN_FOR_WIFI_NETWORKS ) ) ;
2021-04-13 11:00:42 +01:00
WSContentSend_P ( HTTP_FORM_WIFI_PART1 , ( WifiIsInManagerMode ( ) ) ? " " : PSTR ( " ( " STA_SSID1 " ) " ) , SettingsText ( SET_STASSID1 ) ) ;
2021-04-12 17:36:43 +01:00
if ( WifiIsInManagerMode ( ) ) {
2021-04-13 11:00:42 +01:00
// As WIFI_HOSTNAME may contain %s-%04d it cannot be part of HTTP_FORM_WIFI where it will exception
WSContentSend_P ( PSTR ( " ></p> " ) ) ;
2021-04-12 17:36:43 +01:00
} else {
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
2021-04-13 11:00:42 +01:00
WSContentSend_P ( HTTP_FORM_WIFI_PART2 , SettingsText ( SET_STASSID2 ) , WIFI_HOSTNAME , WIFI_HOSTNAME , SettingsText ( SET_HOSTNAME ) , SettingsText ( SET_CORS ) ) ;
2021-08-05 16:55:07 +01:00
# else
WSContentSend_P ( HTTP_FORM_WIFI_PART2 , SettingsText ( SET_STASSID2 ) , WIFI_HOSTNAME , WIFI_HOSTNAME , SettingsText ( SET_HOSTNAME ) ) ;
# endif
2021-04-12 17:36:43 +01:00
}
2021-04-13 11:00:42 +01:00
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_END ) ;
2019-02-21 16:49:11 +00:00
}
2019-03-04 17:16:07 +00:00
2019-02-21 16:49:11 +00:00
if ( WifiIsInManagerMode ( ) ) {
2019-02-23 17:38:36 +00:00
# ifndef FIRMWARE_MINIMAL
2021-04-14 11:39:07 +01:00
WSContentTextCenterStart ( WebColor ( COL_TEXT_WARNING ) ) ;
WSContentSend_P ( PSTR ( " <h3> " ) ) ;
2022-08-03 06:35:16 +01:00
if ( WIFI_TESTING = = Wifi . wifiTest ) {
2021-04-13 11:41:13 +01:00
WSContentSend_P ( PSTR ( D_TRYING_TO_CONNECT " <br>%s</h3></div> " ) , SettingsText ( SET_STASSID1 ) ) ;
2022-08-03 06:35:16 +01:00
} else if ( WIFI_TEST_FINISHED_BAD = = Wifi . wifiTest ) {
2021-04-13 11:41:13 +01:00
WSContentSend_P ( PSTR ( D_CONNECT_FAILED_TO " %s<br> " D_CHECK_CREDENTIALS " </h3></div> " ) , SettingsText ( SET_STASSID1 ) ) ;
2021-04-12 17:36:43 +01:00
}
// More Options Button
2021-04-13 11:41:13 +01:00
WSContentSend_P ( PSTR ( " <div id=butmod style= \" display:%s; \" ></div><p><form id=butmo style= \" display:%s; \" ><button type='button' onclick='hidBtns()'> " D_SHOW_MORE_OPTIONS " </button></form></p> " ) ,
2022-08-03 06:35:16 +01:00
( WIFI_TEST_FINISHED_BAD = = Wifi . wifiTest ) ? " none " : Web . initial_config ? " block " : " none " , Web . initial_config ? " block " : " none "
2021-04-12 17:36:43 +01:00
) ;
WSContentSpaceButton ( BUTTON_RESTORE , ! Web . initial_config ) ;
WSContentButton ( BUTTON_RESET_CONFIGURATION , ! Web . initial_config ) ;
2019-03-04 17:16:07 +00:00
# endif // FIRMWARE_MINIMAL
2021-04-12 17:36:43 +01:00
WSContentSpaceButton ( BUTTON_RESTART , ! Web . initial_config ) ;
2018-10-10 21:21:44 +01:00
} else {
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2021-05-02 14:28:47 +01:00
void WifiSaveSettings ( void ) {
String cmnd = F ( D_CMND_BACKLOG " 0 " ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_HOSTNAME ) , PSTR ( " h " ) , PSTR ( " 1 " ) ) ;
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
2021-05-02 14:28:47 +01:00
cmnd + = AddWebCommand ( PSTR ( D_CMND_CORS ) , PSTR ( " c " ) , PSTR ( " 1 " ) ) ;
2021-08-05 16:55:07 +01:00
# endif
2021-05-02 14:28:47 +01:00
cmnd + = AddWebCommand ( PSTR ( D_CMND_SSID " 1 " ) , PSTR ( " s1 " ) , PSTR ( " 1 " ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_SSID " 2 " ) , PSTR ( " s2 " ) , PSTR ( " 1 " ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_PASSWORD " 3 " ) , PSTR ( " p1 " ) , PSTR ( " \" " ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_PASSWORD " 4 " ) , PSTR ( " p2 " ) , PSTR ( " \" " ) ) ;
2021-05-01 17:35:20 +01:00
ExecuteWebCommand ( ( char * ) cmnd . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2021-04-08 16:57:37 +01:00
void HandleLoggingConfiguration ( void ) {
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_CONFIGURE_LOGGING ) ) ;
2018-10-10 21:21:44 +01:00
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " save " ) ) {
2018-10-10 21:21:44 +01:00
LoggingSaveSettings ( ) ;
HandleConfiguration ( ) ;
return ;
}
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONFIGURE_LOGGING ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_LOG1 ) ;
2019-06-03 09:51:21 +01:00
char stemp1 [ 45 ] ;
2019-03-04 17:16:07 +00:00
char stemp2 [ 32 ] ;
2019-10-03 13:45:24 +01:00
uint8_t dlevel [ 4 ] = { LOG_LEVEL_INFO , LOG_LEVEL_INFO , LOG_LEVEL_NONE , LOG_LEVEL_NONE } ;
for ( uint32_t idx = 0 ; idx < 4 ; idx + + ) {
2021-06-11 17:14:12 +01:00
if ( ( 2 = = idx ) & & ! Settings - > flag . mqtt_enabled ) { continue ; } // SetOption3 - Enable MQTT
uint32_t llevel = ( 0 = = idx ) ? Settings - > seriallog_level : ( 1 = = idx ) ? Settings - > weblog_level : ( 2 = = idx ) ? Settings - > mqttlog_level : Settings - > syslog_level ;
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <p><b>%s</b> (%s)<br><select id='l%d'> " ) ,
2019-03-04 17:16:07 +00:00
GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , idx , kLoggingOptions ) ,
GetTextIndexed ( stemp2 , sizeof ( stemp2 ) , dlevel [ idx ] , kLoggingLevels ) ,
2019-06-02 15:44:02 +01:00
idx ) ;
2019-10-24 07:55:00 +01:00
for ( uint32_t i = LOG_LEVEL_NONE ; i < = LOG_LEVEL_DEBUG_MORE ; i + + ) {
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " <option%s value='%d'>%d %s</option> " ) ,
2021-01-12 18:31:15 +00:00
( i = = llevel ) ? PSTR ( " selected " ) : " " , i , i ,
2019-03-04 17:16:07 +00:00
GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , i , kLoggingLevels ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " </select></p> " ) ) ;
2018-10-10 21:21:44 +01:00
}
2021-06-11 17:14:12 +01:00
WSContentSend_P ( HTTP_FORM_LOG2 , SettingsText ( SET_SYSLOG_HOST ) , Settings - > syslog_port , Settings - > tele_period ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_END ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2021-04-08 16:57:37 +01:00
void LoggingSaveSettings ( void ) {
2021-05-02 14:28:47 +01:00
String cmnd = F ( D_CMND_BACKLOG " 0 " ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_SERIALLOG ) , PSTR ( " l0 " ) , STR ( SERIAL_LOG_LEVEL ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_WEBLOG ) , PSTR ( " l1 " ) , STR ( WEB_LOG_LEVEL ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_MQTTLOG ) , PSTR ( " l2 " ) , STR ( MQTT_LOG_LEVEL ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_SYSLOG ) , PSTR ( " l3 " ) , STR ( SYS_LOG_LEVEL ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_LOGHOST ) , PSTR ( " lh " ) , PSTR ( " 1 " ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_LOGPORT ) , PSTR ( " lp " ) , PSTR ( " 1 " ) ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_TELEPERIOD ) , PSTR ( " lt " ) , PSTR ( " 1 " ) ) ;
2021-05-01 17:35:20 +01:00
ExecuteWebCommand ( ( char * ) cmnd . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2021-04-08 16:57:37 +01:00
void HandleOtherConfiguration ( void ) {
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_CONFIGURE_OTHER ) ) ;
2018-10-10 21:21:44 +01:00
2021-01-18 20:48:04 +00:00
if ( Webserver - > hasArg ( F ( " save " ) ) ) {
2018-10-10 21:21:44 +01:00
OtherSaveSettings ( ) ;
2018-10-12 10:42:52 +01:00
WebRestart ( 1 ) ;
2018-10-10 21:21:44 +01:00
return ;
}
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONFIGURE_OTHER ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2018-10-10 21:21:44 +01:00
2019-02-12 10:55:47 +00:00
TemplateJson ( ) ;
2021-08-15 16:08:31 +01:00
WSContentSend_P ( HTTP_FORM_OTHER , ResponseData ( ) , ( USER_MODULE = = Settings - > module ) ? PSTR ( " checked disabled " ) : " " ,
2021-08-16 22:45:24 +01:00
( Settings - > flag5 . disable_referer_chk ) ? PSTR ( " checked " ) : " " , // SetOption128 - Enable HTTP API
2021-06-11 17:14:12 +01:00
( Settings - > flag . mqtt_enabled ) ? PSTR ( " checked " ) : " " , // SetOption3 - Enable MQTT
2020-05-17 16:55:36 +01:00
SettingsText ( SET_FRIENDLYNAME1 ) , SettingsText ( SET_DEVICENAME ) ) ;
2019-01-07 15:33:18 +00:00
2021-06-04 10:04:52 +01:00
char stemp [ 32 ] ;
2020-10-30 11:29:48 +00:00
uint32_t maxfn = ( TasmotaGlobal . devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : ( ! TasmotaGlobal . devices_present ) ? 1 : TasmotaGlobal . devices_present ;
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) { maxfn = 1 ; }
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < maxfn ; i + + ) {
2019-03-04 17:16:07 +00:00
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , i + 1 ) ;
2020-05-21 16:49:59 +01:00
WSContentSend_P ( PSTR ( " <b> " D_FRIENDLY_NAME " %d</b> ( " FRIENDLY_NAME " %s)<br><input id='a%d' placeholder= \" " FRIENDLY_NAME " %s \" value= \" %s \" ><p></p> " ) ,
2019-03-04 17:16:07 +00:00
i + 1 ,
( i ) ? stemp : " " ,
2019-06-02 15:44:02 +01:00
i ,
2019-03-04 17:16:07 +00:00
( i ) ? stemp : " " ,
2019-12-16 14:13:57 +00:00
SettingsText ( SET_FRIENDLYNAME1 + i ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-02-13 15:05:25 +00:00
2018-10-10 21:21:44 +01:00
# ifdef USE_EMULATION
2020-02-26 12:45:46 +00:00
# if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE)
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <p></p><fieldset><legend><b> " D_EMULATION " </b></legend><p> " ) ) ; // Keep close to Friendlynames so do not use <br>
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < EMUL_MAX ; i + + ) {
2019-05-20 14:09:42 +01:00
# ifndef USE_EMULATION_WEMO
if ( i = = EMUL_WEMO ) { i + + ; }
# endif
# ifndef USE_EMULATION_HUE
if ( i = = EMUL_HUE ) { i + + ; }
# endif
if ( i < EMUL_MAX ) {
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <input id='r%d' name='b2' type='radio' value='%d'%s><b>%s</b> %s<br> " ) , // Different id only used for labels
2019-05-20 14:09:42 +01:00
i , i ,
2021-06-11 17:14:12 +01:00
( i = = Settings - > flag2 . emulation ) ? PSTR ( " checked " ) : " " ,
2019-05-20 14:09:42 +01:00
GetTextIndexed ( stemp , sizeof ( stemp ) , i , kEmulationOptions ) ,
2021-01-12 18:31:15 +00:00
( i = = EMUL_NONE ) ? " " : ( i = = EMUL_WEMO ) ? PSTR ( D_SINGLE_DEVICE ) : PSTR ( D_MULTI_DEVICE ) ) ;
2019-05-20 14:09:42 +01:00
}
2018-10-10 21:21:44 +01:00
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " </p></fieldset> " ) ) ;
2020-02-26 12:45:46 +00:00
# endif // USE_EMULATION_WEMO || USE_EMULATION_HUE
2018-10-10 21:21:44 +01:00
# endif // USE_EMULATION
2019-02-13 15:05:25 +00:00
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_END ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2021-04-08 16:57:37 +01:00
void OtherSaveSettings ( void ) {
2021-05-02 14:28:47 +01:00
String cmnd = F ( D_CMND_BACKLOG " 0 " ) ;
cmnd + = AddWebCommand ( PSTR ( D_CMND_WEBPASSWORD " 2 " ) , PSTR ( " wp " ) , PSTR ( " \" " ) ) ;
2021-05-01 17:04:43 +01:00
cmnd + = F ( " ; " D_CMND_SO " 3 " ) ;
cmnd + = Webserver - > hasArg ( F ( " b1 " ) ) ;
2021-08-16 22:45:24 +01:00
cmnd + = F ( " ; " D_CMND_SO " 128 " ) ;
2021-08-20 14:54:26 +01:00
cmnd + = Webserver - > hasArg ( F ( " b3 " ) ) ;
2021-05-02 14:28:47 +01:00
cmnd + = AddWebCommand ( PSTR ( D_CMND_DEVICENAME ) , PSTR ( " dn " ) , PSTR ( " \" " ) ) ;
2019-02-23 17:38:36 +00:00
char webindex [ 5 ] ;
2021-05-02 14:28:47 +01:00
char cmnd2 [ 24 ] ; // ";Module 0;Template "
2021-04-08 16:57:37 +01:00
for ( uint32_t i = 0 ; i < MAX_FRIENDLYNAMES ; i + + ) {
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " a%d " ) , i ) ;
2021-05-02 14:28:47 +01:00
snprintf_P ( cmnd2 , sizeof ( cmnd2 ) , PSTR ( D_CMND_FN " %d " ) , i + 1 ) ;
cmnd + = AddWebCommand ( cmnd2 , webindex , PSTR ( " \" " ) ) ;
2021-04-08 16:57:37 +01:00
}
2018-10-10 21:21:44 +01:00
# ifdef USE_EMULATION
2020-02-26 12:45:46 +00:00
# if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE)
2021-05-02 14:28:47 +01:00
cmnd + = AddWebCommand ( PSTR ( D_CMND_EMULATION ) , PSTR ( " b2 " ) , PSTR ( " 0 " ) ) ;
2020-02-26 12:45:46 +00:00
# endif // USE_EMULATION_WEMO || USE_EMULATION_HUE
2018-10-10 21:21:44 +01:00
# endif // USE_EMULATION
2019-12-24 14:06:19 +00:00
2021-05-01 17:04:43 +01:00
String tmpl = Webserver - > arg ( F ( " t1 " ) ) ; // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255,"CMND":"SO123 1;SO99 0"}
if ( tmpl . length ( ) & & ( tmpl . length ( ) < MQTT_MAX_PACKET_SIZE ) ) {
2021-05-02 14:28:47 +01:00
snprintf_P ( cmnd2 , sizeof ( cmnd2 ) , PSTR ( " ;%s " D_CMND_TEMPLATE " " ) , ( Webserver - > hasArg ( F ( " t2 " ) ) ) ? PSTR ( D_CMND_MODULE " 0; " ) : " " ) ;
cmnd + = cmnd2 + tmpl ;
2019-02-12 10:55:47 +00:00
}
2021-05-01 17:04:43 +01:00
ExecuteWebCommand ( ( char * ) cmnd . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandleBackupConfiguration ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_BACKUP_CONFIGURATION ) ) ;
2018-10-10 21:21:44 +01:00
2021-05-06 14:23:41 +01:00
uint32_t config_len = SettingsConfigBackup ( ) ;
2023-07-10 17:14:23 +01:00
if ( ! config_len ) { return ; } // Unable to allocate buffer
2018-10-10 21:21:44 +01:00
2020-04-15 08:58:38 +01:00
WiFiClient myClient = Webserver - > client ( ) ;
2021-05-06 14:23:41 +01:00
Webserver - > setContentLength ( config_len ) ;
2018-10-10 21:21:44 +01:00
2019-12-22 14:23:52 +00:00
char attachment [ TOPSZ ] ;
2021-05-06 14:23:41 +01:00
snprintf_P ( attachment , sizeof ( attachment ) , PSTR ( " attachment; filename=%s " ) , SettingsConfigFilename ( ) . c_str ( ) ) ;
2020-04-15 08:58:38 +01:00
Webserver - > sendHeader ( F ( " Content-Disposition " ) , attachment ) ;
2018-10-10 21:21:44 +01:00
2021-02-02 13:57:53 +00:00
WSSend ( 200 , CT_APP_STREAM , " " ) ;
2021-05-06 14:23:41 +01:00
myClient . write ( ( const char * ) settings_buffer , config_len ) ;
2018-10-10 21:21:44 +01:00
SettingsBufferFree ( ) ;
}
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandleResetConfiguration ( void )
2018-10-10 21:21:44 +01:00
{
2019-03-07 17:18:30 +00:00
if ( ! HttpCheckPriviledgedAccess ( ! WifiIsInManagerMode ( ) ) ) { return ; }
2018-10-10 21:21:44 +01:00
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_RESET_CONFIGURATION ) ) ;
2018-10-10 21:21:44 +01:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_RESET_CONFIGURATION ) , ! WifiIsInManagerMode ( ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " <div style='text-align:center;'> " D_CONFIGURATION_RESET " </div> " ) ) ;
WSContentSend_P ( HTTP_MSG_RSTRT ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_MAIN ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
2019-02-23 17:38:36 +00:00
char command [ CMDSZ ] ;
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_RESET " 1 " ) ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( command ) ;
2018-10-10 21:21:44 +01:00
}
2018-11-14 13:32:09 +00:00
void HandleRestoreConfiguration ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_RESTORE_CONFIGURATION ) ) ;
2018-10-10 21:21:44 +01:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_RESTORE_CONFIGURATION ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_RST ) ;
2022-11-24 13:47:26 +00:00
WSContentSend_P ( HTTP_FORM_RST_UPG , PSTR ( D_RESTORE ) ) ;
2019-12-26 00:59:42 +00:00
if ( WifiIsInManagerMode ( ) ) {
WSContentSpaceButton ( BUTTON_MAIN ) ;
} else {
WSContentSpaceButton ( BUTTON_CONFIGURATION ) ;
}
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
2019-08-15 12:50:28 +01:00
Web . upload_file_type = UPL_SETTINGS ;
2018-10-10 21:21:44 +01:00
}
2022-05-15 11:31:27 +01:00
# endif // Not FIRMWARE_MINIMAL
2018-10-10 21:21:44 +01:00
/*-------------------------------------------------------------------------------------------*/
2022-05-15 11:31:27 +01:00
# ifndef FIRMWARE_MINIMAL_ONLY
2018-11-14 13:32:09 +00:00
void HandleInformation ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-02-15 11:24:23 +00:00
float freemem = ( ( float ) ESP_getFreeHeap ( ) ) / 1024 ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_INFORMATION ) ) ;
2018-10-10 21:21:44 +01:00
char stopic [ TOPSZ ] ;
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_INFORMATION ) ) ;
2018-10-10 21:21:44 +01:00
// Save 1k of code space replacing table html with javascript replace codes
// }1 = </td></tr><tr><th>
// }2 = </th><td>
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_SCRIPT_INFO_BEGIN ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " <table style='width:100%%'><tr><th> " ) ) ;
2022-10-04 16:52:15 +01:00
WSContentSend_P ( PSTR ( D_PROGRAM_VERSION " }2%s%s%s " ) , TasmotaGlobal . version , TasmotaGlobal . image_name , GetCodeCores ( ) . c_str ( ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_BUILD_DATE_AND_TIME " }2%s " ) , GetBuildDateAndTime ( ) . c_str ( ) ) ;
2020-04-13 16:45:06 +01:00
WSContentSend_P ( PSTR ( " }1 " D_CORE_AND_SDK_VERSION " }2 " ARDUINO_CORE_RELEASE " /%s " ) , ESP . getSdkVersion ( ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_UPTIME " }2%s " ) , GetUptime ( ) . c_str ( ) ) ;
2020-04-19 15:58:13 +01:00
# ifdef ESP8266
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_FLASH_WRITE_COUNT " }2%d at 0x%X " ) , Settings - > save_flag , GetSettingsAddress ( ) ) ;
2020-11-28 15:39:15 +00:00
# endif // ESP8266
# ifdef ESP32
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_FLASH_WRITE_COUNT " }2%d " ) , Settings - > save_flag ) ;
2020-11-28 15:39:15 +00:00
# endif // ESP32
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_BOOT_COUNT " }2%d " ) , Settings - > bootcount ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_RESTART_REASON " }2%s " ) , GetResetReason ( ) . c_str ( ) ) ;
2020-10-30 11:29:48 +00:00
uint32_t maxfn = ( TasmotaGlobal . devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : TasmotaGlobal . devices_present ;
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) { maxfn = 1 ; }
2019-07-14 21:08:19 +01:00
# endif // USE_SONOFF_IFAN
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < maxfn ; i + + ) {
2019-12-16 14:13:57 +00:00
WSContentSend_P ( PSTR ( " }1 " D_FRIENDLY_NAME " %d}2%s " ) , i + 1 , SettingsText ( SET_FRIENDLYNAME1 + i ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2022-01-13 14:57:33 +00:00
bool show_hr = false ;
2022-01-13 14:27:24 +00:00
if ( ( WiFi . getMode ( ) > = WIFI_AP ) & & ( static_cast < uint32_t > ( WiFi . softAPIP ( ) ) ! = 0 ) ) {
WSContentSend_P ( PSTR ( " }1 " D_MAC_ADDRESS " }2%s " ) , WiFi . softAPmacAddress ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_IP_ADDRESS " (AP)}2%_I " ) , ( uint32_t ) WiFi . softAPIP ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_GATEWAY " }2%_I " ) , ( uint32_t ) WiFi . softAPIP ( ) ) ;
2020-06-16 13:57:00 +01:00
WSContentSend_P ( PSTR ( " }1<hr/>}2<hr/> " ) ) ;
2020-06-15 17:27:04 +01:00
}
2021-06-11 17:14:12 +01:00
if ( Settings - > flag4 . network_wifi ) {
2020-06-15 17:27:04 +01:00
int32_t rssi = WiFi . RSSI ( ) ;
2023-10-09 10:33:24 +01:00
WSContentSend_P ( PSTR ( " }1 " D_AP " %d " D_INFORMATION " }2 " D_SSID " %s<br> " D_RSSI " %d%%, %d dBm<br> " D_MODE " 11%c<br> " D_CHANNEL " %d<br> " D_BSSID " %s " ) ,
Settings - > sta_active + 1 ,
HtmlEscape ( SettingsText ( SET_STASSID1 + Settings - > sta_active ) ) . c_str ( ) ,
WifiGetRssiAsQuality ( rssi ) , rssi ,
pgm_read_byte ( & kWifiPhyMode [ WiFi . getPhyMode ( ) & 0x3 ] ) ,
WiFi . channel ( ) ,
WiFi . BSSIDstr ( ) . c_str ( ) ) ;
2023-10-09 07:39:12 +01:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2021-01-12 18:31:15 +00:00
WSContentSend_P ( PSTR ( " }1 " D_HOSTNAME " }2%s%s " ) , TasmotaGlobal . hostname , ( Mdns . begun ) ? PSTR ( " .local " ) : " " ) ;
2022-12-10 12:44:16 +00:00
# ifdef USE_IPV6
2022-12-27 20:59:34 +00:00
String ipv6_addr = WifiGetIPv6Str ( ) ;
2020-06-15 17:27:04 +01:00
if ( ipv6_addr ! = " " ) {
2023-10-09 07:39:12 +01:00
WSContentSend_P ( PSTR ( " }1 IPv6 Global (WiFi)}2%s " ) , ipv6_addr . c_str ( ) ) ;
2022-11-30 18:40:58 +00:00
}
2022-12-27 20:59:34 +00:00
ipv6_addr = WifiGetIPv6LinkLocalStr ( ) ;
2022-11-30 18:40:58 +00:00
if ( ipv6_addr ! = " " ) {
2023-10-09 07:39:12 +01:00
WSContentSend_P ( PSTR ( " }1 IPv6 Local (WiFi)}2%s " ) , ipv6_addr . c_str ( ) ) ;
2019-12-11 14:53:19 +00:00
}
2022-12-10 12:44:16 +00:00
# endif // USE_IPV6
2020-06-15 17:27:04 +01:00
if ( static_cast < uint32_t > ( WiFi . localIP ( ) ) ! = 0 ) {
WSContentSend_P ( PSTR ( " }1 " D_MAC_ADDRESS " }2%s " ) , WiFi . macAddress ( ) . c_str ( ) ) ;
2023-10-09 07:39:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_IP_ADDRESS " (WiFi)}2%_I " ) , ( uint32_t ) WiFi . localIP ( ) ) ;
2020-06-15 17:27:04 +01:00
}
2022-01-13 14:57:33 +00:00
show_hr = true ;
2020-06-15 17:27:04 +01:00
}
2022-01-13 14:57:33 +00:00
if ( ! TasmotaGlobal . global_state . wifi_down ) {
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_GATEWAY " }2%_I " ) , Settings - > ipv4_address [ 1 ] ) ;
WSContentSend_P ( PSTR ( " }1 " D_SUBNET_MASK " }2%_I " ) , Settings - > ipv4_address [ 2 ] ) ;
2022-12-27 20:59:34 +00:00
# ifdef USE_IPV6
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 1}2%s " ) , DNSGetIPStr ( 0 ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 2}2%s " ) , DNSGetIPStr ( 1 ) . c_str ( ) ) ;
# else // USE_IPV6
2021-07-29 15:57:04 +01:00
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 1}2%_I " ) , Settings - > ipv4_address [ 3 ] ) ;
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 2}2%_I " ) , Settings - > ipv4_address [ 4 ] ) ;
2022-12-27 20:59:34 +00:00
# endif // USE_IPV6
2018-10-10 21:21:44 +01:00
}
2022-01-13 14:27:24 +00:00
# if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET)
2022-12-27 20:59:34 +00:00
if ( EthernetHasIP ( ) ) {
2022-01-13 14:57:33 +00:00
if ( show_hr ) {
WSContentSend_P ( PSTR ( " }1<hr/>}2<hr/> " ) ) ;
}
2022-01-13 14:27:24 +00:00
WSContentSend_P ( PSTR ( " }1 " D_HOSTNAME " }2%s%s " ) , EthernetHostname ( ) , ( Mdns . begun ) ? PSTR ( " .local " ) : " " ) ;
2022-12-10 12:44:16 +00:00
# ifdef USE_IPV6
2022-12-27 20:59:34 +00:00
String ipv6_eth_addr = EthernetGetIPv6Str ( ) ;
2022-12-08 18:06:51 +00:00
if ( ipv6_eth_addr ! = " " ) {
WSContentSend_P ( PSTR ( " }1 IPv6 Global (eth)}2%s " ) , ipv6_eth_addr . c_str ( ) ) ;
}
2022-12-27 20:59:34 +00:00
ipv6_eth_addr = EthernetGetIPv6LinkLocalStr ( ) ;
2022-12-08 18:06:51 +00:00
if ( ipv6_eth_addr ! = " " ) {
WSContentSend_P ( PSTR ( " }1 IPv6 Local (eth)}2%s " ) , ipv6_eth_addr . c_str ( ) ) ;
}
2022-12-10 12:44:16 +00:00
# endif // USE_IPV6
2022-01-13 14:27:24 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MAC_ADDRESS " }2%s " ) , EthernetMacAddress ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_IP_ADDRESS " (eth)}2%_I " ) , ( uint32_t ) EthernetLocalIP ( ) ) ;
}
2022-01-13 14:57:33 +00:00
if ( ! TasmotaGlobal . global_state . eth_down ) {
2022-01-13 14:27:24 +00:00
WSContentSend_P ( PSTR ( " }1 " D_GATEWAY " }2%_I " ) , Settings - > eth_ipv4_address [ 1 ] ) ;
WSContentSend_P ( PSTR ( " }1 " D_SUBNET_MASK " }2%_I " ) , Settings - > eth_ipv4_address [ 2 ] ) ;
2022-12-27 20:59:34 +00:00
# ifdef USE_IPV6
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 1}2%s " ) , DNSGetIPStr ( 0 ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 2}2%s " ) , DNSGetIPStr ( 1 ) . c_str ( ) ) ;
# else // USE_IPV6
2022-01-13 14:27:24 +00:00
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 1}2%_I " ) , Settings - > eth_ipv4_address [ 3 ] ) ;
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " 2}2%_I " ) , Settings - > eth_ipv4_address [ 4 ] ) ;
2022-12-27 20:59:34 +00:00
# endif // USE_IPV6
2018-10-10 21:21:44 +01:00
}
2022-01-13 14:27:24 +00:00
# endif // USE_ETHERNET
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2021-08-16 22:45:24 +01:00
WSContentSend_P ( PSTR ( " }1 " D_HTTP_API " }2%s " ) , Settings - > flag5 . disable_referer_chk ? PSTR ( D_ENABLED ) : PSTR ( D_DISABLED ) ) ; // SetOption 128
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . mqtt_enabled ) { // SetOption3 - Enable MQTT
2019-12-16 14:13:57 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_HOST " }2%s " ) , SettingsText ( SET_MQTT_HOST ) ) ;
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_PORT " }2%d " ) , Settings - > mqtt_port ) ;
2020-08-12 16:20:37 +01:00
# ifdef USE_MQTT_TLS
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_TLS_ENABLE " }2%s " ) , Settings - > flag4 . mqtt_tls ? PSTR ( D_ENABLED ) : PSTR ( D_DISABLED ) ) ;
2021-01-19 11:26:52 +00:00
# endif // USE_MQTT_TLS
2019-12-16 14:13:57 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_USER " }2%s " ) , SettingsText ( SET_MQTT_USER ) ) ;
2020-10-30 11:29:48 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_CLIENT " }2%s " ) , TasmotaGlobal . mqtt_client ) ;
2019-12-16 14:13:57 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_TOPIC " }2%s " ) , SettingsText ( SET_MQTT_TOPIC ) ) ;
2020-03-28 15:48:36 +00:00
uint32_t real_index = SET_MQTT_GRP_TOPIC ;
for ( uint32_t i = 0 ; i < MAX_GROUP_TOPICS ; i + + ) {
if ( 1 = = i ) { real_index = SET_MQTT_GRP_TOPIC2 - 1 ; }
if ( strlen ( SettingsText ( real_index + i ) ) ) {
WSContentSend_P ( PSTR ( " }1 " D_MQTT_GROUP_TOPIC " %d}2%s " ) , 1 + i , GetGroupTopic_P ( stopic , " " , real_index + i ) ) ;
2020-03-28 10:13:01 +00:00
}
}
2020-10-30 11:29:48 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_FULL_TOPIC " }2%s " ) , GetTopic_P ( stopic , CMND , TasmotaGlobal . mqtt_topic , " " ) ) ;
2019-10-31 16:24:06 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT " " D_FALLBACK_TOPIC " }2%s " ) , GetFallbackTopic_P ( stopic , " " ) ) ;
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_NO_RETAIN " }2%s " ) , Settings - > flag4 . mqtt_no_retain ? PSTR ( D_ENABLED ) : PSTR ( D_DISABLED ) ) ;
2018-10-10 21:21:44 +01:00
} else {
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT " }2 " D_DISABLED ) ) ;
2018-10-10 21:21:44 +01:00
}
2021-01-19 11:26:52 +00:00
# if defined(USE_EMULATION) || defined(USE_DISCOVERY)
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
# endif // USE_EMULATION or USE_DISCOVERY
2018-10-10 21:21:44 +01:00
# ifdef USE_EMULATION
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_EMULATION " }2%s " ) , GetTextIndexed ( stopic , sizeof ( stopic ) , Settings - > flag2 . emulation , kEmulationOptions ) ) ;
2021-01-19 11:26:52 +00:00
# endif // USE_EMULATION
2018-10-10 21:21:44 +01:00
# ifdef USE_DISCOVERY
2021-06-11 17:14:12 +01:00
WSContentSend_P ( PSTR ( " }1 " D_MDNS_DISCOVERY " }2%s " ) , ( Settings - > flag3 . mdns_enabled ) ? D_ENABLED : D_DISABLED ) ; // SetOption55 - Control mDNS service
if ( Settings - > flag3 . mdns_enabled ) { // SetOption55 - Control mDNS service
2018-10-10 21:21:44 +01:00
# ifdef WEBSERVER_ADVERTISE
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MDNS_ADVERTISE " }2 " D_WEB_SERVER ) ) ;
2018-10-10 21:21:44 +01:00
# else
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MDNS_ADVERTISE " }2 " D_DISABLED ) ) ;
2021-01-19 11:26:52 +00:00
# endif // WEBSERVER_ADVERTISE
2019-01-03 17:07:03 +00:00
}
2021-01-19 11:26:52 +00:00
# endif // USE_DISCOVERY
2018-10-10 21:21:44 +01:00
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2022-04-24 10:24:01 +01:00
WSContentSend_P ( PSTR ( " }1 " D_ESP_CHIP_ID " }2%d (%s) " ) , ESP_getChipId ( ) , GetDeviceHardwareRevision ( ) . c_str ( ) ) ;
2023-08-12 10:31:06 +01:00
WSContentSend_P ( PSTR ( " }1 " D_FLASH_CHIP_ID " }20x%06X ( " D_TASMOTA_FLASHMODE " ) " ) , ESP_getFlashChipId ( ) ) ;
2022-09-17 14:53:58 +01:00
# ifdef ESP32
WSContentSend_P ( PSTR ( " }1 " D_FLASH_CHIP_SIZE " }2%d KB " ) , ESP . getFlashChipSize ( ) / 1024 ) ;
WSContentSend_P ( PSTR ( " }1 " D_PROGRAM_FLASH_SIZE " }2%d KB " ) , ESP_getFlashChipMagicSize ( ) / 1024 ) ;
# endif // ESP32
# ifdef ESP8266
WSContentSend_P ( PSTR ( " }1 " D_FLASH_CHIP_SIZE " }2%d KB " ) , ESP . getFlashChipRealSize ( ) / 1024 ) ;
WSContentSend_P ( PSTR ( " }1 " D_PROGRAM_FLASH_SIZE " }2%d KB " ) , ESP_getFlashChipSize ( ) / 1024 ) ;
# endif // ESP8266
2022-05-15 16:35:45 +01:00
WSContentSend_P ( PSTR ( " }1 " D_PROGRAM_SIZE " }2%d KB " ) , ESP_getSketchSize ( ) / 1024 ) ;
WSContentSend_P ( PSTR ( " }1 " D_FREE_PROGRAM_SPACE " }2%d KB " ) , ESP_getFreeSketchSpace ( ) / 1024 ) ;
2020-05-12 13:19:10 +01:00
# ifdef ESP32
2023-05-10 13:02:51 +01:00
# ifdef USE_GT911
WSContentSend_PD ( PSTR ( " }1 " D_FREE_MEMORY " }2%1_f KB " ) , & freemem ) ;
# else
2022-05-15 16:35:45 +01:00
WSContentSend_PD ( PSTR ( " }1 " D_FREE_MEMORY " }2%1_f KB ( " D_FRAGMENTATION " %d%%) " ) , & freemem , ESP_getHeapFragmentation ( ) ) ;
2023-05-10 13:02:51 +01:00
# endif // USE_GT911
2021-07-18 18:43:33 +01:00
if ( UsePSRAM ( ) ) {
2022-05-15 16:35:45 +01:00
WSContentSend_P ( PSTR ( " }1 " D_PSR_MAX_MEMORY " }2%d KB " ) , ESP . getPsramSize ( ) / 1024 ) ;
WSContentSend_P ( PSTR ( " }1 " D_PSR_FREE_MEMORY " }2%d KB " ) , ESP . getFreePsram ( ) / 1024 ) ;
2020-05-12 13:19:10 +01:00
}
2022-05-14 16:41:52 +01:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2022-05-15 11:31:27 +01:00
uint32_t cur_part = ESP_PARTITION_SUBTYPE_APP_FACTORY ; // 0
const esp_partition_t * running_ota = esp_ota_get_running_partition ( ) ;
if ( running_ota ) { cur_part = running_ota - > subtype ; } // 16 - 32
2022-05-14 16:41:52 +01:00
esp_partition_iterator_t it = esp_partition_find ( ESP_PARTITION_TYPE_ANY , ESP_PARTITION_SUBTYPE_ANY , NULL ) ;
for ( ; it ! = NULL ; it = esp_partition_next ( it ) ) {
const esp_partition_t * part = esp_partition_get ( it ) ;
2022-05-15 10:40:24 +01:00
2022-05-15 11:31:27 +01:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("PRT: Type %d, Subtype %d, Name %s, Size %d"), part->type, part->subtype, part->label, part->size);
2022-05-15 10:40:24 +01:00
2022-05-14 16:41:52 +01:00
uint32_t part_size = part - > size / 1024 ;
2022-05-15 10:40:24 +01:00
if ( ESP_PARTITION_TYPE_APP = = part - > type ) {
2022-05-15 11:31:27 +01:00
uint32_t prog_size = 0 ; // No active ota partition
2022-05-15 10:40:24 +01:00
if ( part - > subtype = = ESP_PARTITION_SUBTYPE_APP_FACTORY ) {
2022-05-15 13:59:39 +01:00
prog_size = EspProgramSize ( part - > label ) ; // safeboot partition (slow response)
2022-05-15 10:40:24 +01:00
}
else if ( ( part - > subtype > = ESP_PARTITION_SUBTYPE_APP_OTA_MIN ) & & ( part - > subtype < = ESP_PARTITION_SUBTYPE_APP_OTA_MAX ) ) {
2022-05-15 11:31:27 +01:00
if ( cur_part = = part - > subtype ) {
2022-05-15 13:59:39 +01:00
prog_size = ESP_getSketchSize ( ) ; // Active running ota partition (fast response)
2022-05-15 11:31:27 +01:00
}
else if ( cur_part = = ESP_PARTITION_SUBTYPE_APP_FACTORY ) {
2022-05-15 13:59:39 +01:00
prog_size = EspProgramSize ( part - > label ) ; // One app partition when safeboot partitions (slow response)
2022-05-15 10:40:24 +01:00
}
}
char running [ 2 ] = { 0 } ;
2022-05-15 11:31:27 +01:00
if ( part - > subtype = = cur_part ) { running [ 0 ] = ' * ' ; }
2022-05-20 16:51:14 +01:00
WSContentSend_PD ( PSTR ( " }1 " D_PARTITION " %s%s}2%d KB " ) , part - > label , running , part_size ) ;
if ( prog_size ) {
uint32_t part_used = ( ( prog_size / 1024 ) * 100 ) / part_size ;
WSContentSend_PD ( PSTR ( " ( " D_USED " %d%%) " ) , part_used ) ;
}
2022-05-14 16:41:52 +01:00
}
2022-05-15 10:40:24 +01:00
if ( ( ESP_PARTITION_TYPE_DATA = = part - > type ) & & ( ESP_PARTITION_SUBTYPE_DATA_SPIFFS = = part - > subtype ) ) {
2022-05-15 16:35:45 +01:00
WSContentSend_PD ( PSTR ( " }1 " D_PARTITION " fs}2%d KB " ) , part_size ) ;
2022-05-14 16:41:52 +01:00
}
}
esp_partition_iterator_release ( it ) ;
2023-05-07 16:25:18 +01:00
# else // not ESP32
2022-05-15 16:35:45 +01:00
WSContentSend_PD ( PSTR ( " }1 " D_FREE_MEMORY " }2%1_f KB " ) , & freemem ) ;
2023-05-07 16:25:18 +01:00
# ifdef USE_UFILESYS
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
WSContentSend_P ( PSTR ( " }1 " D_FILE_SYSTEM_SIZE " }2%d KB " ) , UfsSize ( ) ) ;
# endif // USE_UFILESYS
# endif // ESP32
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " </td></tr></table> " ) ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_SCRIPT_INFO_END ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
// WSContentSend_P(PSTR("<fieldset><legend><b> Information </b></legend>"));
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " <style>td{padding:0px 5px;}</style> "
" <div id='i' name='i'></div> " ) ) ;
2019-03-10 14:36:34 +00:00
// WSContentSend_P(PSTR("</fieldset>"));
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_MAIN ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2022-05-15 11:31:27 +01:00
# endif // Not FIRMWARE_MINIMAL_ONLY
2018-10-10 21:21:44 +01:00
/*-------------------------------------------------------------------------------------------*/
2020-11-24 19:29:28 +00:00
# if defined(USE_ZIGBEE_EZSP) || defined(USE_TASMOTA_CLIENT) || defined(SHELLY_FW_UPGRADE) || defined(USE_RF_FLASH) || defined(USE_CCLOADER)
2020-11-20 16:51:16 +00:00
# define USE_WEB_FW_UPGRADE
# endif
# ifdef USE_WEB_FW_UPGRADE
2020-11-16 16:39:16 +00:00
struct {
size_t spi_hex_size ;
size_t spi_sector_counter ;
size_t spi_sector_cursor ;
2020-11-20 16:51:16 +00:00
bool active ;
2020-11-16 16:39:16 +00:00
bool ready ;
} BUpload ;
2020-11-20 16:51:16 +00:00
void BUploadInit ( uint32_t file_type ) {
Web . upload_file_type = file_type ;
2020-11-16 16:39:16 +00:00
BUpload . spi_hex_size = 0 ;
2020-11-22 16:35:04 +00:00
BUpload . spi_sector_counter = FlashWriteStartSector ( ) ;
2020-11-16 16:39:16 +00:00
BUpload . spi_sector_cursor = 0 ;
2020-11-20 16:51:16 +00:00
BUpload . active = true ;
2020-11-16 16:39:16 +00:00
BUpload . ready = false ;
}
2020-11-17 16:15:29 +00:00
uint32_t BUploadWriteBuffer ( uint8_t * buf , size_t size ) {
2020-11-16 16:39:16 +00:00
if ( 0 = = BUpload . spi_sector_cursor ) { // Starting a new sector write so we need to erase it first
2020-11-22 16:35:04 +00:00
if ( ! ESP . flashEraseSector ( BUpload . spi_sector_counter ) ) {
return 7 ; // Upload aborted - flash failed
}
2020-11-16 16:39:16 +00:00
}
BUpload . spi_sector_cursor + + ;
2020-11-25 12:07:04 +00:00
if ( ! ESP . flashWrite ( ( BUpload . spi_sector_counter * SPI_FLASH_SEC_SIZE ) + ( ( BUpload . spi_sector_cursor - 1 ) * HTTP_UPLOAD_BUFLEN ) , ( uint32_t * ) buf , size ) ) {
2020-11-22 16:35:04 +00:00
return 7 ; // Upload aborted - flash failed
}
2020-11-16 16:39:16 +00:00
BUpload . spi_hex_size + = size ;
if ( 2 = = BUpload . spi_sector_cursor ) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase
BUpload . spi_sector_cursor = 0 ;
BUpload . spi_sector_counter + + ;
2020-11-22 16:35:04 +00:00
if ( BUpload . spi_sector_counter > FlashWriteMaxSector ( ) ) {
2020-11-17 16:15:29 +00:00
return 9 ; // File too large - Not enough free space
}
2020-11-16 16:39:16 +00:00
}
2020-11-17 16:15:29 +00:00
return 0 ;
2020-11-16 16:39:16 +00:00
}
2020-11-20 16:51:16 +00:00
# endif // USE_WEB_FW_UPGRADE
2020-11-16 16:39:16 +00:00
2021-01-09 14:28:47 +00:00
void HandleUpgradeFirmware ( void ) {
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_FIRMWARE_UPGRADE ) ) ;
2018-10-10 21:21:44 +01:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_FIRMWARE_UPGRADE ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-12-16 14:13:57 +00:00
WSContentSend_P ( HTTP_FORM_UPG , SettingsText ( SET_OTAURL ) ) ;
2022-05-02 16:25:31 +01:00
# ifdef ESP32
if ( EspSingleOtaPartition ( ) & & ! EspRunningFactoryPartition ( ) ) {
2022-11-24 13:47:26 +00:00
WSContentSend_P ( HTTP_FORM_RST_UPG_FCT , PSTR ( D_UPGRADE ) ) ;
2022-05-02 16:25:31 +01:00
} else {
2022-11-24 13:47:26 +00:00
WSContentSend_P ( HTTP_FORM_RST_UPG , PSTR ( D_UPGRADE ) ) ;
2022-05-02 16:25:31 +01:00
}
# else
2022-11-24 13:47:26 +00:00
WSContentSend_P ( HTTP_FORM_RST_UPG , PSTR ( D_UPGRADE ) ) ;
2022-05-02 16:25:31 +01:00
# endif
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_MAIN ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
2019-08-15 12:50:28 +01:00
Web . upload_file_type = UPL_TASMOTA ;
2018-10-10 21:21:44 +01:00
}
2021-01-09 14:28:47 +00:00
void HandleUpgradeFirmwareStart ( void ) {
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2019-12-22 14:23:52 +00:00
char command [ TOPSZ + 10 ] ; // OtaUrl
2018-10-10 21:21:44 +01:00
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_UPGRADE_STARTED ) ) ;
2018-10-10 21:21:44 +01:00
WifiConfigCounter ( ) ;
2019-12-22 14:23:52 +00:00
char otaurl [ TOPSZ ] ;
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " o " ) , otaurl , sizeof ( otaurl ) ) ;
2019-02-23 17:38:36 +00:00
if ( strlen ( otaurl ) ) {
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_OTAURL " %s " ) , otaurl ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( command ) ;
2018-10-10 21:21:44 +01:00
}
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_INFORMATION ) ) ;
2020-06-05 10:53:53 +01:00
WSContentSend_P ( HTTP_SCRIPT_RELOAD_TIME , HTTP_OTA_RESTART_RECONNECT_TIME ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " <div style='text-align:center;'><b> " D_UPGRADE_STARTED " ...</b></div> " ) ) ;
WSContentSend_P ( HTTP_MSG_RSTRT ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_MAIN ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
2019-02-23 17:38:36 +00:00
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_UPGRADE " 1 " ) ) ;
2021-04-07 17:10:34 +01:00
ExecuteWebCommand ( command ) ;
2018-10-10 21:21:44 +01:00
}
2021-01-09 14:28:47 +00:00
void HandleUploadDone ( void ) {
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2020-11-19 14:43:47 +00:00
# if defined(USE_ZIGBEE_EZSP)
if ( ( UPL_EFR32 = = Web . upload_file_type ) & & ! Web . upload_error & & BUpload . ready ) {
2020-11-21 16:12:17 +00:00
BUpload . ready = false ; // Make sure not to follow thru again
2020-09-01 12:05:46 +01:00
// GUI xmodem
2020-11-22 16:35:04 +00:00
ZigbeeUploadStep1Done ( FlashWriteStartSector ( ) , BUpload . spi_hex_size ) ;
2020-11-19 14:43:47 +00:00
HandleZigbeeXfer ( ) ;
return ;
2020-09-01 12:05:46 +01:00
}
2020-11-19 14:43:47 +00:00
# endif // USE_ZIGBEE_EZSP
2020-09-01 12:05:46 +01:00
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_UPLOAD_DONE ) ) ;
2018-10-10 21:21:44 +01:00
WifiConfigCounter ( ) ;
2021-01-10 16:46:30 +00:00
UploadServices ( 1 ) ;
2018-10-10 21:21:44 +01:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_INFORMATION ) ) ;
2019-08-15 12:50:28 +01:00
if ( ! Web . upload_error ) {
2020-11-21 16:12:17 +00:00
WSContentSend_P ( HTTP_SCRIPT_RELOAD_TIME , ( UPL_TASMOTA = = Web . upload_file_type ) ? HTTP_OTA_RESTART_RECONNECT_TIME : HTTP_RESTART_RECONNECT_TIME ) ; // Refesh main web ui after OTA upgrade
2019-03-04 11:36:44 +00:00
}
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
WSContentSend_P ( PSTR ( " <div style='text-align:center;'><b> " D_UPLOAD " <font color='# " ) ) ;
2019-08-15 12:50:28 +01:00
if ( Web . upload_error ) {
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " %06x'> " D_FAILED " </font></b><br><br> " ) , WebColor ( COL_TEXT_WARNING ) ) ;
2021-01-10 16:46:30 +00:00
char error [ 100 ] ;
2020-11-07 14:43:52 +00:00
if ( Web . upload_error < 10 ) {
2019-08-15 12:50:28 +01:00
GetTextIndexed ( error , sizeof ( error ) , Web . upload_error - 1 , kUploadErrors ) ;
2019-02-23 12:17:02 +00:00
} else {
2019-08-15 12:50:28 +01:00
snprintf_P ( error , sizeof ( error ) , PSTR ( D_UPLOAD_ERROR_CODE " %d " ) , Web . upload_error ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( error ) ;
2019-08-09 16:34:22 +01:00
DEBUG_CORE_LOG ( PSTR ( " UPL: %s " ) , error ) ;
2021-06-11 17:14:12 +01:00
TasmotaGlobal . stop_flash_rotate = Settings - > flag . stop_flash_rotate ; // SetOption12 - Switch between dynamic or fixed slot flash save location
2021-01-10 16:46:30 +00:00
Web . upload_error = 0 ;
2018-10-10 21:21:44 +01:00
} else {
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " %06x'> " D_SUCCESSFUL " </font></b><br> " ) , WebColor ( COL_TEXT_SUCCESS ) ) ;
2020-10-29 11:21:24 +00:00
TasmotaGlobal . restart_flag = 2 ; // Always restart to re-enable disabled features during update
2020-11-21 16:12:17 +00:00
WSContentSend_P ( HTTP_MSG_RSTRT ) ;
ShowWebSource ( SRC_WEBGUI ) ;
2018-10-10 21:21:44 +01:00
}
SettingsBufferFree ( ) ;
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " </div><br> " ) ) ;
2019-03-11 09:38:41 +00:00
WSContentSpaceButton ( BUTTON_MAIN ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2021-01-10 16:46:30 +00:00
void UploadServices ( uint32_t start_service ) {
2021-01-11 08:50:31 +00:00
if ( Web . upload_services_stopped ! = start_service ) { return ; }
Web . upload_services_stopped = ! start_service ;
2021-01-10 16:46:30 +00:00
if ( start_service ) {
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("UPL: Services enabled"));
2021-01-10 16:46:30 +00:00
/*
MqttRetryCounter ( 0 ) ;
*/
2023-01-07 14:37:52 +00:00
AllowInterrupts ( 1 ) ;
2021-01-10 16:46:30 +00:00
} else {
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("UPL: Services disabled"));
2021-01-10 16:46:30 +00:00
2023-01-07 14:37:52 +00:00
AllowInterrupts ( 0 ) ;
2021-01-10 16:46:30 +00:00
/*
MqttRetryCounter ( 60 ) ;
2021-06-11 17:14:12 +01:00
if ( Settings - > flag . mqtt_enabled ) { // SetOption3 - Enable MQTT
2021-01-10 16:46:30 +00:00
MqttDisconnect ( ) ;
}
*/
}
}
2021-01-09 14:28:47 +00:00
void HandleUploadLoop ( void ) {
2018-10-10 21:21:44 +01:00
// Based on ESP8266HTTPUpdateServer.cpp uses ESP8266WebServer Parsing.cpp and Cores Updater.cpp (Update)
2021-01-09 17:19:15 +00:00
static uint32_t upload_size ;
2021-01-10 16:46:30 +00:00
static bool upload_error_signalled ;
2018-10-10 21:21:44 +01:00
2019-08-15 12:50:28 +01:00
if ( HTTP_USER = = Web . state ) { return ; }
2021-01-10 16:46:30 +00:00
2019-08-15 12:50:28 +01:00
if ( Web . upload_error ) {
2021-01-10 16:46:30 +00:00
if ( ! upload_error_signalled ) {
if ( UPL_TASMOTA = = Web . upload_file_type ) { Update . end ( ) ; }
UploadServices ( 1 ) ;
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Upload error %d"), Web.upload_error);
2021-01-10 16:46:30 +00:00
upload_error_signalled = true ;
}
2018-10-10 21:21:44 +01:00
return ;
}
2020-04-15 08:58:38 +01:00
HTTPUpload & upload = Webserver - > upload ( ) ;
2018-10-10 21:21:44 +01:00
2020-09-04 11:49:57 +01:00
// ***** Step1: Start upload file
2018-10-10 21:21:44 +01:00
if ( UPLOAD_FILE_START = = upload . status ) {
2021-01-09 14:28:47 +00:00
Web . upload_error = 0 ;
2021-01-10 16:46:30 +00:00
upload_error_signalled = false ;
2021-01-09 17:19:15 +00:00
upload_size = 0 ;
2021-01-10 16:46:30 +00:00
UploadServices ( 0 ) ;
2018-10-10 21:21:44 +01:00
if ( 0 = = upload . filename . c_str ( ) [ 0 ] ) {
2019-08-15 12:50:28 +01:00
Web . upload_error = 1 ; // No file selected
2018-10-10 21:21:44 +01:00
return ;
}
SettingsSave ( 1 ) ; // Free flash for upload
2021-01-09 14:28:47 +00:00
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD D_FILE " %s " ) , upload . filename . c_str ( ) ) ;
2021-01-09 14:28:47 +00:00
2021-01-09 17:19:15 +00:00
# ifdef USE_UFILESYS
2023-07-10 15:03:32 +01:00
if ( UPL_UFSFILE = = Web . upload_file_type ) {
2021-01-09 17:19:15 +00:00
if ( ! UfsUploadFileOpen ( upload . filename . c_str ( ) ) ) {
Web . upload_error = 2 ;
return ;
}
}
# endif // USE_UFILESYS
2020-09-04 11:49:57 +01:00
}
// ***** Step2: Write upload file
2020-11-20 16:51:16 +00:00
else if ( UPLOAD_FILE_WRITE = = upload . status ) {
if ( 0 = = upload . totalSize ) { // First block received
2019-08-15 12:50:28 +01:00
if ( UPL_SETTINGS = = Web . upload_file_type ) {
2023-07-10 15:03:32 +01:00
uint32_t set_size = sizeof ( TSettings ) ;
# ifdef USE_UFILESYS
if ( ( ' s ' = = upload . buf [ 2 ] ) & & ( ' e ' = = upload . buf [ 3 ] ) ) { // /.settings
set_size = upload . buf [ 14 ] + ( upload . buf [ 15 ] < < 8 ) ;
}
# endif // USE_UFILESYS
if ( ! SettingsBufferAlloc ( set_size ) ) {
Web . upload_error = 2 ; // Not enough space
return ;
}
2019-08-15 12:50:28 +01:00
Web . config_block_count = 0 ;
2018-10-10 21:21:44 +01:00
}
2020-11-20 16:51:16 +00:00
# ifdef USE_WEB_FW_UPGRADE
2019-10-15 14:37:22 +01:00
# ifdef USE_RF_FLASH
2020-11-20 16:51:16 +00:00
else if ( ( SONOFF_BRIDGE = = TasmotaGlobal . module_type ) & & ( ' : ' = = upload . buf [ 0 ] ) ) { // Check if this is a RF bridge FW file
BUploadInit ( UPL_EFM8BB1 ) ;
}
2018-10-10 21:21:44 +01:00
# endif // USE_RF_FLASH
2020-11-21 16:12:17 +00:00
# ifdef USE_TASMOTA_CLIENT
else if ( TasmotaClient_Available ( ) & & ( ' : ' = = upload . buf [ 0 ] ) ) { // Check if this is a ARDUINO CLIENT hex file
BUploadInit ( UPL_TASMOTACLIENT ) ;
}
# endif // USE_TASMOTA_CLIENT
# ifdef SHELLY_FW_UPGRADE
2021-04-05 15:57:48 +01:00
else if ( ShdPresent ( ) & & ( 0x00 = = upload . buf [ 0 ] ) & & ( ( 0x10 = = upload . buf [ 1 ] ) | | ( 0x20 = = upload . buf [ 1 ] ) ) ) {
2020-11-21 16:12:17 +00:00
BUploadInit ( UPL_SHD ) ;
}
# endif // SHELLY_FW_UPGRADE
2020-11-24 19:29:28 +00:00
# ifdef USE_CCLOADER
else if ( CCLChipFound ( ) & & 0x02 = = upload . buf [ 0 ] ) { // the 0x02 is only an assumption!!
BUploadInit ( UPL_CCL ) ;
}
# endif // USE_CCLOADER
2020-11-20 16:51:16 +00:00
# ifdef USE_ZIGBEE_EZSP
2020-11-19 14:43:47 +00:00
# ifdef ESP8266
2020-11-20 16:51:16 +00:00
else if ( ( SONOFF_ZB_BRIDGE = = TasmotaGlobal . module_type ) & & ( 0xEB = = upload . buf [ 0 ] ) ) { // Check if this is a Zigbee bridge FW file
2020-11-28 15:39:15 +00:00
# endif // ESP8266
# ifdef ESP32
2020-11-20 16:51:16 +00:00
else if ( PinUsed ( GPIO_ZIGBEE_RX ) & & PinUsed ( GPIO_ZIGBEE_TX ) & & ( 0xEB = = upload . buf [ 0 ] ) ) { // Check if this is a Zigbee bridge FW file
2020-11-28 15:39:15 +00:00
# endif // ESP32
2020-11-20 16:51:16 +00:00
// Read complete file into ESP8266 flash
// Current files are about 200k
Web . upload_error = ZigbeeUploadStep1Init ( ) ; // 1
if ( Web . upload_error ! = 0 ) { return ; }
BUploadInit ( UPL_EFR32 ) ;
}
2020-11-21 16:12:17 +00:00
# endif // USE_ZIGBEE_EZSP
2020-11-20 16:51:16 +00:00
# endif // USE_WEB_FW_UPGRADE
2021-01-09 17:19:15 +00:00
else if ( UPL_TASMOTA = = Web . upload_file_type ) {
if ( ( upload . buf [ 0 ] ! = 0xE9 ) & & ( upload . buf [ 0 ] ! = 0x1F ) ) { // 0x1F is gzipped 0xE9
Web . upload_error = 3 ; // Invalid file signature - Magic byte is not 0xE9
return ;
}
2020-11-20 16:51:16 +00:00
if ( 0xE9 = = upload . buf [ 0 ] ) {
2022-05-09 21:43:27 +01:00
# ifdef ESP8266
2022-05-13 08:30:31 +01:00
uint32_t bin_flash_size = ESP . magicFlashChipSize ( ( upload . buf [ 3 ] & 0xf0 ) > > 4 ) ;
2020-11-20 16:51:16 +00:00
if ( bin_flash_size > ESP . getFlashChipRealSize ( ) ) {
2022-05-09 21:43:27 +01:00
# else
2022-05-13 08:30:31 +01:00
char tmp [ 16 ] ;
WebGetArg ( " fsz " , tmp , sizeof ( tmp ) ) ; // filesize
uint32_t upload_size = ( ! strlen ( tmp ) ) ? 0 : atoi ( tmp ) ;
AddLog ( LOG_LEVEL_DEBUG , D_LOG_UPLOAD " freespace=%i filesize=%i " , ESP . getFreeSketchSpace ( ) , upload_size ) ;
if ( upload_size > ESP . getFreeSketchSpace ( ) ) { // TODO revisit this test
2022-05-09 21:43:27 +01:00
# endif
2020-11-20 16:51:16 +00:00
Web . upload_error = 4 ; // Program flash size is larger than real flash size
2018-10-10 21:21:44 +01:00
return ;
}
2020-11-20 16:51:16 +00:00
// upload.buf[2] = 3; // Force DOUT - ESP8285
2018-10-10 21:21:44 +01:00
}
2022-05-09 10:34:52 +01:00
uint32_t maxSketchSpace = ( ESP . getFreeSketchSpace ( ) - 0x1000 ) & 0xFFFFF000 ;
2020-11-20 16:51:16 +00:00
if ( ! Update . begin ( maxSketchSpace ) ) { //start with max available size
Web . upload_error = 2 ; // Not enough space
2018-10-10 21:21:44 +01:00
return ;
}
}
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_UPLOAD " File type %d " ) , Web . upload_file_type ) ;
2020-11-20 16:51:16 +00:00
} // First block received
if ( UPL_SETTINGS = = Web . upload_file_type ) {
2023-07-10 15:03:32 +01:00
if ( upload . currentSize > ( settings_size - ( Web . config_block_count * HTTP_UPLOAD_BUFLEN ) ) ) {
2020-11-20 16:51:16 +00:00
Web . upload_error = 9 ; // File too large
2018-10-10 21:21:44 +01:00
return ;
}
2020-11-20 16:51:16 +00:00
memcpy ( settings_buffer + ( Web . config_block_count * HTTP_UPLOAD_BUFLEN ) , upload . buf , upload . currentSize ) ;
Web . config_block_count + + ;
2018-10-10 21:21:44 +01:00
}
2021-01-09 17:19:15 +00:00
# ifdef USE_UFILESYS
else if ( UPL_UFSFILE = = Web . upload_file_type ) {
if ( ! UfsUploadFileWrite ( upload . buf , upload . currentSize ) ) {
Web . upload_error = 9 ; // File too large
return ;
}
}
# endif // USE_UFILESYS
2020-11-20 16:51:16 +00:00
# ifdef USE_WEB_FW_UPGRADE
else if ( BUpload . active ) {
2020-11-16 16:39:16 +00:00
// Write a block
2022-11-11 10:47:11 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Size %d, Data '%32_H'"), upload.currentSize, upload.buf);
2020-11-17 16:15:29 +00:00
Web . upload_error = BUploadWriteBuffer ( upload . buf , upload . currentSize ) ;
if ( Web . upload_error ! = 0 ) { return ; }
2020-11-16 16:39:16 +00:00
}
2020-11-20 16:51:16 +00:00
# endif // USE_WEB_FW_UPGRADE
else if ( Update . write ( upload . buf , upload . currentSize ) ! = upload . currentSize ) {
2021-07-22 14:14:58 +01:00
// Web.upload_error = 5; // Upload buffer miscompare
Web . upload_error = 2 ; // Not enough space
2020-11-20 16:51:16 +00:00
return ;
}
2021-01-10 16:46:30 +00:00
if ( upload . totalSize & & ! ( upload . totalSize % 102400 ) ) {
2022-05-15 16:35:45 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_UPLOAD " Progress %d KB " ) , upload . totalSize / 1024 ) ;
2018-10-10 21:21:44 +01:00
}
2020-09-04 11:49:57 +01:00
}
// ***** Step3: Finish upload file
2020-11-20 16:51:16 +00:00
else if ( UPLOAD_FILE_END = = upload . status ) {
2021-01-10 16:46:30 +00:00
UploadServices ( 1 ) ;
2019-08-15 12:50:28 +01:00
if ( UPL_SETTINGS = = Web . upload_file_type ) {
2021-05-06 14:23:41 +01:00
if ( ! SettingsConfigRestore ( ) ) {
2019-08-15 12:50:28 +01:00
Web . upload_error = 8 ; // File invalid
2018-10-10 21:21:44 +01:00
return ;
}
}
2021-01-09 17:19:15 +00:00
# ifdef USE_UFILESYS
else if ( UPL_UFSFILE = = Web . upload_file_type ) {
UfsUploadFileClose ( ) ;
}
# endif // USE_UFILESYS
2020-11-20 16:51:16 +00:00
# ifdef USE_WEB_FW_UPGRADE
else if ( BUpload . active ) {
2020-11-21 16:12:17 +00:00
// Done writing the data to SPI flash
BUpload . active = false ;
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD " Transfer %u bytes " ) , upload . totalSize ) ;
2020-11-21 13:45:58 +00:00
2020-11-25 13:58:18 +00:00
uint8_t * data = FlashDirectAccess ( ) ;
2020-11-21 13:45:58 +00:00
// uint32_t* values = (uint32_t*)(data); // Only 4-byte access allowed
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Head 0x%08X"), values[0]);
2020-11-21 13:45:58 +00:00
uint32_t error = 0 ;
# ifdef USE_RF_FLASH
if ( UPL_EFM8BB1 = = Web . upload_file_type ) {
error = SnfBrUpdateFirmware ( data , BUpload . spi_hex_size ) ;
}
# endif // USE_RF_FLASH
2020-11-21 16:12:17 +00:00
# ifdef USE_TASMOTA_CLIENT
2020-11-21 16:21:20 +00:00
if ( UPL_TASMOTACLIENT = = Web . upload_file_type ) {
2020-11-25 12:07:04 +00:00
error = TasmotaClient_Flash ( data , BUpload . spi_hex_size ) ;
2020-11-21 16:12:17 +00:00
}
# endif // USE_TASMOTA_CLIENT
2020-11-21 13:45:58 +00:00
# ifdef SHELLY_FW_UPGRADE
2020-11-21 16:21:20 +00:00
if ( UPL_SHD = = Web . upload_file_type ) {
2020-11-21 13:45:58 +00:00
error = ShdFlash ( data , BUpload . spi_hex_size ) ;
}
2020-11-21 16:12:17 +00:00
# endif // SHELLY_FW_UPGRADE
2020-11-24 19:29:28 +00:00
# ifdef USE_CCLOADER
if ( UPL_CCL = = Web . upload_file_type ) {
error = CLLFlashFirmware ( data , BUpload . spi_hex_size ) ;
}
# endif // SHELLY_FW_UPGRADE
2020-11-21 16:12:17 +00:00
# ifdef USE_ZIGBEE_EZSP
2020-11-21 16:21:20 +00:00
if ( UPL_EFR32 = = Web . upload_file_type ) {
2020-11-21 16:12:17 +00:00
BUpload . ready = true ; // So we know on upload success page if it needs to flash hex or do a normal restart
}
# endif // USE_ZIGBEE_EZSP
2020-11-21 13:45:58 +00:00
if ( error ! = 0 ) {
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "Transfer error %d"), error);
2021-05-08 14:26:23 +01:00
Web . upload_error = error + ( 100 * ( Web . upload_file_type - 1 ) ) ; // Add offset to discriminate transfer errors
2020-11-21 13:45:58 +00:00
return ;
}
2020-11-16 16:39:16 +00:00
}
2020-11-20 16:51:16 +00:00
# endif // USE_WEB_FW_UPGRADE
else if ( ! Update . end ( true ) ) { // true to set the size to the current progress
Web . upload_error = 6 ; // Upload failed. Enable logging 3
return ;
2018-10-10 21:21:44 +01:00
}
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD D_SUCCESSFUL " %u bytes " ) , upload . totalSize ) ;
2020-09-04 11:49:57 +01:00
}
// ***** Step4: Abort upload file
2021-01-09 14:28:47 +00:00
else {
2021-01-10 16:46:30 +00:00
UploadServices ( 1 ) ;
2019-08-15 12:50:28 +01:00
Web . upload_error = 7 ; // Upload aborted
if ( UPL_TASMOTA = = Web . upload_file_type ) { Update . end ( ) ; }
2018-10-10 21:21:44 +01:00
}
2021-01-17 17:08:54 +00:00
// do actually wait a little to allow ESP32 tasks to tick
// fixes task timeout in ESP32Solo1 style unicore code.
delay ( 10 ) ;
2021-01-11 08:50:31 +00:00
OsWatchLoop ( ) ;
// Scheduler(); // Feed OsWatch timer to prevent restart on long uploads
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandlePreflightRequest ( void )
2018-10-10 21:21:44 +01:00
{
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
2019-10-28 12:36:04 +00:00
HttpHeaderCors ( ) ;
2021-08-05 16:55:07 +01:00
# endif
2020-04-15 08:58:38 +01:00
Webserver - > sendHeader ( F ( " Access-Control-Allow-Methods " ) , F ( " GET, POST " ) ) ;
Webserver - > sendHeader ( F ( " Access-Control-Allow-Headers " ) , F ( " authorization " ) ) ;
2019-02-23 14:29:42 +00:00
WSSend ( 200 , CT_HTML , " " ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2022-05-01 22:16:21 +01:00
# ifdef ESP32
2022-05-05 18:13:58 +01:00
// Switch boot partition
2022-05-01 22:16:21 +01:00
//
// Parameter `u4` is either `fct` or `ota` to switch to factory or ota
2022-05-05 18:13:58 +01:00
// If not in single-OTA mode
2022-05-01 22:16:21 +01:00
//
// The page can return the followinf (code 200)
// `false`: the current partition is not the target, but a restart to factory is triggered (polling required)
// `true`: the current partition is the one required
// `none`: there is no factory partition
2022-05-02 09:00:00 +01:00
// return a simple status page as text/plain code 200
static void WSReturnSimpleString ( const char * msg ) {
if ( nullptr = = msg ) { msg = " " ; }
Webserver - > client ( ) . flush ( ) ;
WSHeaderSend ( ) ;
Webserver - > send ( 200 , " text/plain " , msg ) ;
}
2022-05-05 18:13:58 +01:00
void HandleSwitchBootPartition ( void )
2022-05-01 22:16:21 +01:00
{
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
char tmp1 [ 8 ] ;
WebGetArg ( PSTR ( " u4 " ) , tmp1 , sizeof ( tmp1 ) ) ;
bool switch_factory = false ; // trigger a restart to factory partition?
bool switch_ota = false ; // switch back to OTA partition
2022-05-05 18:13:58 +01:00
bool single_ota = EspSingleOtaPartition ( ) ;
2022-05-02 09:00:00 +01:00
bool api_mode = Webserver - > hasArg ( " api " ) ; // api-mode, returns `true`, `false` or `none`
2022-05-01 22:16:21 +01:00
2022-05-05 18:13:58 +01:00
// switch to next OTA?
if ( strcmp ( " ota " , tmp1 ) = = 0 ) {
switch_ota = true ;
if ( single_ota & & ! EspRunningFactoryPartition ( ) ) {
switch_ota = false ; // if in single-OTA and already running OTA, nothing to do
2022-05-01 22:16:21 +01:00
}
}
2022-05-05 18:13:58 +01:00
// switch to factory ?
if ( strcmp ( " fct " , tmp1 ) = = 0 & & single_ota & & ! EspRunningFactoryPartition ( ) ) {
switch_factory = true ;
}
2022-05-01 22:16:21 +01:00
2022-05-02 09:00:00 +01:00
// apply the change in flash and return result
2022-05-01 22:16:21 +01:00
if ( switch_factory | | switch_ota ) {
SettingsSaveAll ( ) ;
if ( switch_factory ) {
2022-05-05 10:19:39 +01:00
EspPrepRestartToSafeBoot ( ) ;
2022-05-01 22:16:21 +01:00
} else {
const esp_partition_t * partition = esp_ota_get_next_update_partition ( nullptr ) ;
esp_ota_set_boot_partition ( partition ) ;
}
2022-05-03 10:19:02 +01:00
2022-05-02 09:00:00 +01:00
if ( api_mode ) {
WSReturnSimpleString ( " false " ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_RESTART ) ) ;
EspRestart ( ) ;
} else {
2022-05-15 13:59:39 +01:00
WebRestart ( 4 ) ;
2022-05-02 09:00:00 +01:00
}
2022-05-01 22:16:21 +01:00
} else {
2022-05-02 09:00:00 +01:00
if ( api_mode ) {
// return `none` or `true`
WSReturnSimpleString ( EspSingleOtaPartition ( ) ? " true " : " none " ) ;
} else {
Webserver - > sendHeader ( " Location " , " / " , true ) ;
Webserver - > send ( 302 , " text/plain " , " " ) ;
}
2022-05-01 22:16:21 +01:00
}
2022-05-02 16:25:31 +01:00
Web . upload_file_type = UPL_TASMOTA ;
2022-05-01 22:16:21 +01:00
}
2022-05-02 16:25:31 +01:00
# endif // ESP32
2022-05-01 22:16:21 +01:00
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandleHttpCommand ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( false ) ) { return ; }
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_COMMAND ) ) ;
2018-10-10 21:21:44 +01:00
2021-01-08 13:10:34 +00:00
if ( ! WebAuthenticate ( ) ) {
// Prefer authorization via HTTP header (Basic auth), if it fails, use legacy method via GET parameters
char tmp1 [ 33 ] ;
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " user " ) , tmp1 , sizeof ( tmp1 ) ) ;
2021-02-21 13:17:51 +00:00
char tmp2 [ strlen ( SettingsText ( SET_WEBPWD ) ) + 2 ] ; // Need space for an entered password longer than set password
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " password " ) , tmp2 , sizeof ( tmp2 ) ) ;
2021-01-08 13:10:34 +00:00
if ( ! ( ! strcmp ( tmp1 , WEB_USERNAME ) & & ! strcmp ( tmp2 , SettingsText ( SET_WEBPWD ) ) ) ) {
2021-02-02 13:57:53 +00:00
WSContentBegin ( 401 , CT_APP_JSON ) ;
2021-01-08 13:10:34 +00:00
WSContentSend_P ( PSTR ( " { \" " D_RSLT_WARNING " \" : \" " D_NEED_USER_AND_PASSWORD " \" } " ) ) ;
WSContentEnd ( ) ;
2022-04-22 16:52:53 +01:00
// https://github.com/arendst/Tasmota/discussions/15420
2022-04-23 10:18:22 +01:00
ShowWebSource ( SRC_WEBCOMMAND ) ;
2022-04-22 16:52:53 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP " Bad userid and/or password " ) ) ;
2021-01-08 13:10:34 +00:00
return ;
}
2018-10-10 21:21:44 +01:00
}
2021-02-02 13:57:53 +00:00
WSContentBegin ( 200 , CT_APP_JSON ) ;
2021-01-18 20:48:04 +00:00
String svalue = Webserver - > arg ( F ( " cmnd " ) ) ;
2020-04-15 09:14:16 +01:00
if ( svalue . length ( ) & & ( svalue . length ( ) < MQTT_MAX_PACKET_SIZE ) ) {
2020-12-22 14:26:07 +00:00
uint32_t curridx = TasmotaGlobal . log_buffer_pointer ;
TasmotaGlobal . templog_level = LOG_LEVEL_INFO ;
2020-04-15 09:14:16 +01:00
ExecuteWebCommand ( ( char * ) svalue . c_str ( ) , SRC_WEBCOMMAND ) ;
2020-12-22 14:26:07 +00:00
WSContentSend_P ( PSTR ( " { " ) ) ;
bool cflg = false ;
uint32_t index = curridx ;
char * line ;
size_t len ;
while ( GetLog ( TasmotaGlobal . templog_level , & index , & line , & len ) ) {
// [14:49:36.123 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char * JSON = ( char * ) memchr ( line , ' { ' , len ) ;
if ( JSON ) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
2021-05-31 15:17:45 +01:00
if ( cflg ) { WSContentSend_P ( PSTR ( " , " ) ) ; }
uint32_t JSONlen = len - ( JSON - line ) - 3 ;
2023-06-09 08:59:24 +01:00
for ( + + JSON ; JSONlen & & JSON [ JSONlen ] ! = ' } ' ; JSONlen - - ) ;
WSContentSend ( JSON , JSONlen ) ;
2020-12-22 14:26:07 +00:00
cflg = true ;
2020-12-19 16:29:14 +00:00
}
2018-10-10 21:21:44 +01:00
}
2020-12-22 14:26:07 +00:00
WSContentSend_P ( PSTR ( " } " ) ) ;
TasmotaGlobal . templog_level = 0 ;
2018-10-10 21:21:44 +01:00
} else {
2020-04-15 09:14:16 +01:00
WSContentSend_P ( PSTR ( " { \" " D_RSLT_WARNING " \" : \" " D_ENTER_COMMAND " cmnd= \" } " ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-16 15:23:41 +00:00
WSContentEnd ( ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2021-04-16 10:40:38 +01:00
void HandleManagement ( void )
{
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_MANAGEMENT ) ) ;
WSContentStart_P ( PSTR ( D_MANAGEMENT ) ) ;
WSContentSendStyle ( ) ;
WSContentButton ( BUTTON_CONSOLE ) ;
XdrvMailbox . index = 0 ;
2022-11-11 08:57:00 +00:00
XdrvXsnsCall ( FUNC_WEB_ADD_CONSOLE_BUTTON ) ;
2021-04-16 10:40:38 +01:00
WSContentSend_P ( PSTR ( " <div></div> " ) ) ; // 5px padding
XdrvCall ( FUNC_WEB_ADD_MANAGEMENT_BUTTON ) ;
WSContentSpaceButton ( BUTTON_MAIN ) ;
WSContentStop ( ) ;
}
2018-11-14 13:32:09 +00:00
void HandleConsole ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2021-01-18 20:48:04 +00:00
if ( Webserver - > hasArg ( F ( " c2 " ) ) ) { // Console refresh requested
2019-03-01 17:25:46 +00:00
HandleConsoleRefresh ( ) ;
return ;
}
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_CONSOLE ) ) ;
2018-10-10 21:21:44 +01:00
2020-11-06 16:09:13 +00:00
WSContentStart_P ( PSTR ( D_CONSOLE ) ) ;
2021-06-11 17:14:12 +01:00
WSContentSend_P ( HTTP_SCRIPT_CONSOL , Settings - > web_refresh ) ;
2023-08-04 15:11:58 +01:00
# ifdef USE_CONSOLE_CSS_FLEX
WSContentSendStyle_P ( HTTP_CMND_STYLE ) ;
# else
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2023-08-04 15:11:58 +01:00
# endif // USE_CONSOLE_CSS_FLEX
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_CMND ) ;
2021-04-16 10:40:38 +01:00
WSContentSpaceButton ( ( WebUseManagementSubmenu ( ) ) ? BUTTON_MANAGEMENT : BUTTON_MAIN ) ;
2019-03-16 15:23:41 +00:00
WSContentStop ( ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-01 17:25:46 +00:00
void HandleConsoleRefresh ( void )
2018-10-10 21:21:44 +01:00
{
2021-01-18 20:48:04 +00:00
String svalue = Webserver - > arg ( F ( " c1 " ) ) ;
2019-08-01 21:59:12 +01:00
if ( svalue . length ( ) & & ( svalue . length ( ) < MQTT_MAX_PACKET_SIZE ) ) {
2021-06-05 10:47:09 +01:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_COMMAND " %s " ) , svalue . c_str ( ) ) ;
2019-02-22 11:04:05 +00:00
ExecuteWebCommand ( ( char * ) svalue . c_str ( ) , SRC_WEBCONSOLE ) ;
2018-10-10 21:21:44 +01:00
}
2019-02-23 17:38:36 +00:00
char stmp [ 8 ] ;
2021-01-18 20:48:04 +00:00
WebGetArg ( PSTR ( " c2 " ) , stmp , sizeof ( stmp ) ) ;
2020-12-19 16:29:14 +00:00
uint32_t index = 0 ; // Initial start, dump all
if ( strlen ( stmp ) ) { index = atoi ( stmp ) ; }
2018-10-10 21:21:44 +01:00
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_PLAIN ) ;
2020-12-18 15:30:37 +00:00
WSContentSend_P ( PSTR ( " %d}1%d}1 " ) , TasmotaGlobal . log_buffer_pointer , Web . reset_web_log_flag ) ;
2019-08-15 12:50:28 +01:00
if ( ! Web . reset_web_log_flag ) {
2020-12-19 16:29:14 +00:00
index = 0 ;
2019-08-15 12:50:28 +01:00
Web . reset_web_log_flag = true ;
2018-10-10 21:21:44 +01:00
}
2020-12-19 16:29:14 +00:00
bool cflg = ( index ) ;
char * line ;
size_t len ;
2021-06-11 17:14:12 +01:00
while ( GetLog ( Settings - > weblog_level , & index , & line , & len ) ) {
2021-05-31 15:17:45 +01:00
if ( cflg ) { WSContentSend_P ( PSTR ( " \n " ) ) ; }
2021-05-31 15:58:32 +01:00
WSContentSend ( line , len - 1 ) ;
2020-12-19 16:29:14 +00:00
cflg = true ;
2018-10-10 21:21:44 +01:00
}
2019-03-16 15:23:41 +00:00
WSContentSend_P ( PSTR ( " }1 " ) ) ;
WSContentEnd ( ) ;
2018-10-10 21:21:44 +01:00
}
/********************************************************************************************/
2018-11-14 13:32:09 +00:00
void HandleNotFound ( void )
2018-10-10 21:21:44 +01:00
{
2021-01-23 15:26:23 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Not found (%s)"), Webserver->uri().c_str());
2021-06-16 00:39:49 +01:00
# ifndef NO_CAPTIVE_PORTAL
2018-10-10 21:21:44 +01:00
if ( CaptivePortal ( ) ) { return ; } // If captive portal redirect instead of displaying the error page.
2021-06-16 00:39:49 +01:00
# endif // NO_CAPTIVE_PORTAL
2018-10-10 21:21:44 +01:00
# ifdef USE_EMULATION
2019-05-20 14:09:42 +01:00
# ifdef USE_EMULATION_HUE
2020-04-15 08:58:38 +01:00
String path = Webserver - > uri ( ) ;
2021-06-11 17:14:12 +01:00
if ( ( EMUL_HUE = = Settings - > flag2 . emulation ) & & ( path . startsWith ( F ( " /api " ) ) ) ) {
2018-10-10 21:21:44 +01:00
HandleHueApi ( & path ) ;
} else
2019-05-20 14:09:42 +01:00
# endif // USE_EMULATION_HUE
# endif // USE_EMULATION
2018-10-10 21:21:44 +01:00
{
2019-03-23 16:00:59 +00:00
WSContentBegin ( 404 , CT_PLAIN ) ;
2021-01-18 20:48:04 +00:00
WSContentSend_P ( PSTR ( D_FILE_NOT_FOUND " \n \n URI: %s \n Method: %s \n Arguments: %d \n " ) , Webserver - > uri ( ) . c_str ( ) , ( Webserver - > method ( ) = = HTTP_GET ) ? PSTR ( " GET " ) : PSTR ( " POST " ) , Webserver - > args ( ) ) ;
2020-04-15 08:58:38 +01:00
for ( uint32_t i = 0 ; i < Webserver - > args ( ) ; i + + ) {
WSContentSend_P ( PSTR ( " %s: %s \n " ) , Webserver - > argName ( i ) . c_str ( ) , Webserver - > arg ( i ) . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-23 16:00:59 +00:00
WSContentEnd ( ) ;
2018-10-10 21:21:44 +01:00
}
}
2021-06-16 00:39:49 +01:00
# ifndef NO_CAPTIVE_PORTAL
2018-10-10 21:21:44 +01:00
/* Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
2019-01-28 13:08:33 +00:00
bool CaptivePortal ( void )
2018-10-10 21:21:44 +01:00
{
2019-04-02 19:26:30 +01:00
// Possible hostHeader: connectivitycheck.gstatic.com or 192.168.4.1
2020-04-15 08:58:38 +01:00
if ( ( WifiIsInManagerMode ( ) ) & & ! ValidIpAddress ( Webserver - > hostHeader ( ) . c_str ( ) ) ) {
2021-01-23 15:26:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_REDIRECTED ) ) ;
2018-10-10 21:21:44 +01:00
2023-01-06 13:03:16 +00:00
Webserver - > sendHeader ( F ( " Location " ) , String ( F ( " http:// " ) ) + IPGetListeningAddressStr ( ) , true ) ;
2019-02-23 14:29:42 +00:00
WSSend ( 302 , CT_PLAIN , " " ) ; // Empty content inhibits Content-length header so we have to close the socket ourselves.
2020-04-15 08:58:38 +01:00
Webserver - > client ( ) . stop ( ) ; // Stop is needed because we sent no content length
2018-10-10 21:21:44 +01:00
return true ;
}
return false ;
}
2021-06-16 00:39:49 +01:00
# endif // NO_CAPTIVE_PORTAL
2018-10-10 21:21:44 +01:00
/*********************************************************************************************/
int WebSend ( char * buffer )
{
2019-11-03 14:37:33 +00:00
// [tasmota] POWER1 ON --> Sends http://tasmota/cm?cmnd=POWER1 ON
2019-02-19 11:51:38 +00:00
// [192.168.178.86:80,admin:joker] POWER1 ON --> Sends http://hostname:80/cm?user=admin&password=joker&cmnd=POWER1 ON
2019-11-03 14:37:33 +00:00
// [tasmota] /any/link/starting/with/a/slash.php?log=123 --> Sends http://tasmota/any/link/starting/with/a/slash.php?log=123
// [tasmota,admin:joker] /any/link/starting/with/a/slash.php?log=123 --> Sends http://tasmota/any/link/starting/with/a/slash.php?log=123
2018-10-10 21:21:44 +01:00
char * host ;
char * user ;
char * password ;
char * command ;
2021-09-01 20:30:54 +01:00
int status = WEBCMND_WRONG_PARAMETERS ;
2018-10-10 21:21:44 +01:00
2018-11-12 11:33:49 +00:00
// buffer = | [ 192.168.178.86 : 80 , admin : joker ] POWER1 ON |
host = strtok_r ( buffer , " ] " , & command ) ; // host = | [ 192.168.178.86 : 80 , admin : joker |, command = | POWER1 ON |
2018-10-10 21:21:44 +01:00
if ( host & & command ) {
2019-02-23 11:48:39 +00:00
RemoveSpace ( host ) ; // host = |[192.168.178.86:80,admin:joker|
host + + ; // host = |192.168.178.86:80,admin:joker| - Skip [
host = strtok_r ( host , " , " , & user ) ; // host = |192.168.178.86:80|, user = |admin:joker|
2019-02-22 14:19:59 +00:00
String url = F ( " http:// " ) ; // url = |http://|
2019-02-23 11:48:39 +00:00
url + = host ; // url = |http://192.168.178.86:80|
2019-02-22 11:04:05 +00:00
2018-11-12 11:33:49 +00:00
command = Trim ( command ) ; // command = |POWER1 ON| or |/any/link/starting/with/a/slash.php?log=123|
2018-11-12 10:13:05 +00:00
if ( command [ 0 ] ! = ' / ' ) {
2019-02-19 11:51:38 +00:00
url + = F ( " /cm? " ) ; // url = |http://192.168.178.86/cm?|
2019-02-23 11:48:39 +00:00
if ( user ) {
user = strtok_r ( user , " : " , & password ) ; // user = |admin|, password = |joker|
if ( user & & password ) {
2019-12-22 14:23:52 +00:00
char userpass [ 200 ] ;
2019-02-23 11:48:39 +00:00
snprintf_P ( userpass , sizeof ( userpass ) , PSTR ( " user=%s&password=%s& " ) , user , password ) ;
url + = userpass ; // url = |http://192.168.178.86/cm?user=admin&password=joker&|
}
2018-11-12 10:13:05 +00:00
}
2019-02-19 11:51:38 +00:00
url + = F ( " cmnd= " ) ; // url = |http://192.168.178.86/cm?cmnd=| or |http://192.168.178.86/cm?user=admin&password=joker&cmnd=|
2018-10-10 21:21:44 +01:00
}
2021-09-24 10:34:44 +01:00
url + = UrlEncode ( command ) ; // url = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
url + = F ( " GET " ) ; // url = |http://192.168.178.86/cm?cmnd=POWER1%20ON GET|
2018-10-10 21:21:44 +01:00
2021-09-24 10:34:44 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Uri '%s' " ) , url . c_str ( ) ) ;
status = WebQuery ( const_cast < char * > ( url . c_str ( ) ) ) ;
}
return status ;
}
2023-04-03 13:55:47 +01:00
int WebQuery ( char * buffer ) {
2021-09-24 10:34:44 +01:00
// http://192.168.1.1/path GET -> Sends HTTP GET http://192.168.1.1/path
// http://192.168.1.1/path POST {"some":"message"} -> Sends HTTP POST to http://192.168.1.1/path with body {"some":"message"}
// http://192.168.1.1/path PUT [Autorization: Bearer abcdxyz] potato -> Sends HTTP PUT to http://192.168.1.1/path with authorization header and body "potato"
// http://192.168.1.1/path PATCH patchInfo -> Sends HTTP PATCH to http://192.168.1.1/path with body "potato"
// Valid HTTP Commands: GET, POST, PUT, and PATCH
// An unlimited number of headers can be sent per request, and a body can be sent for all command types
// The body will be ignored if sending a GET command
2021-11-26 17:58:35 +00:00
# if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS)
HTTPClientLight http ;
# else // HTTP only
2021-09-24 10:34:44 +01:00
WiFiClient http_client ;
HTTPClient http ;
2021-11-26 17:58:35 +00:00
# endif
2021-09-24 10:34:44 +01:00
int status = WEBCMND_WRONG_PARAMETERS ;
char * temp ;
char * url = strtok_r ( buffer , " " , & temp ) ;
char * method = strtok_r ( temp , " " , & temp ) ;
if ( url & & method ) {
2021-11-26 17:58:35 +00:00
# if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS)
if ( http . begin ( UrlEncode ( url ) ) ) {
# else // HTTP only
2021-09-24 10:34:44 +01:00
if ( http . begin ( http_client , UrlEncode ( url ) ) ) {
2021-11-26 17:58:35 +00:00
# endif
2021-09-24 10:34:44 +01:00
char empty_body [ 1 ] = { 0 } ;
char * body = empty_body ;
if ( temp ) { // There is a body and/or header
if ( temp [ 0 ] = = ' [ ' ) { // Header information was sent; decode it
temp + = 1 ;
temp = strtok_r ( temp , " ] " , & body ) ;
bool headerFound = true ;
while ( headerFound ) {
char * header = strtok_r ( temp , " : " , & temp ) ;
if ( header ) {
char * headerBody = strtok_r ( temp , " | " , & temp ) ;
if ( headerBody ) {
http . addHeader ( header , headerBody ) ;
}
else headerFound = false ;
}
else headerFound = false ;
}
} else { // No header information was sent, but there was a body
body = temp ;
}
}
int http_code ;
if ( 0 = = strcasecmp_P ( method , PSTR ( " GET " ) ) ) { http_code = http . GET ( ) ; }
else if ( 0 = = strcasecmp_P ( method , PSTR ( " POST " ) ) ) { http_code = http . POST ( body ) ; }
else if ( 0 = = strcasecmp_P ( method , PSTR ( " PUT " ) ) ) { http_code = http . PUT ( body ) ; }
else if ( 0 = = strcasecmp_P ( method , PSTR ( " PATCH " ) ) ) { http_code = http . PATCH ( body ) ; }
else return status ;
2018-10-10 21:21:44 +01:00
2019-02-19 11:51:38 +00:00
if ( http_code > 0 ) { // http_code will be negative on error
if ( http_code = = HTTP_CODE_OK | | http_code = = HTTP_CODE_MOVED_PERMANENTLY ) {
2019-08-19 07:20:51 +01:00
# ifdef USE_WEBSEND_RESPONSE
2019-02-19 11:51:38 +00:00
// Return received data to the user - Adds 900+ bytes to the code
2019-08-19 10:21:00 +01:00
const char * read = http . getString ( ) . c_str ( ) ; // File found at server - may need lot of ram or trigger out of memory!
2021-05-23 15:50:17 +01:00
ResponseClear ( ) ;
2022-04-09 07:44:00 +01:00
Response_P ( PSTR ( " { \" " D_CMND_WEBQUERY " \" : " ) ) ;
2022-04-09 09:35:17 +01:00
char text [ 2 ] = { 0 } ;
text [ 0 ] = * read + + ;
bool assume_json = ( text [ 0 ] = = ' { ' ) | | ( text [ 0 ] = = ' [ ' ) ;
if ( ! assume_json ) { ResponseAppend_P ( PSTR ( " \" " ) ) ; }
2021-05-23 15:50:17 +01:00
while ( text [ 0 ] ! = ' \0 ' ) {
if ( text [ 0 ] > 31 ) { // Remove control characters like linefeed
2022-04-09 09:35:17 +01:00
if ( assume_json ) {
if ( ResponseAppend_P ( text ) = = ResponseSize ( ) ) { break ; } ;
} else {
if ( ResponseAppend_P ( EscapeJSONString ( text ) . c_str ( ) ) = = ResponseSize ( ) ) { break ; } ;
}
2019-02-19 11:51:38 +00:00
}
2022-04-09 09:35:17 +01:00
text [ 0 ] = * read + + ;
2019-02-19 11:51:38 +00:00
}
2022-04-09 09:35:17 +01:00
if ( ! assume_json ) { ResponseAppend_P ( PSTR ( " \" " ) ) ; }
2022-04-09 07:44:00 +01:00
ResponseJsonEnd ( ) ;
2019-08-19 07:20:51 +01:00
# ifdef USE_SCRIPT
2021-04-07 14:07:05 +01:00
extern uint8_t tasm_cmd_activ ;
2019-08-19 07:20:51 +01:00
// recursive call must be possible in this case
2021-04-07 14:07:05 +01:00
tasm_cmd_activ = 0 ;
2019-08-19 10:47:59 +01:00
# endif // USE_SCRIPT
2021-09-24 10:34:44 +01:00
MqttPublishPrefixTopicRulesProcess_P ( RESULT_OR_STAT , PSTR ( D_CMND_WEBQUERY ) ) ;
2019-08-19 10:47:59 +01:00
# endif // USE_WEBSEND_RESPONSE
2019-02-19 11:51:38 +00:00
}
2021-09-01 20:30:54 +01:00
status = WEBCMND_DONE ;
2018-10-10 21:21:44 +01:00
} else {
2021-09-01 20:30:54 +01:00
status = WEBCMND_CONNECT_FAILED ;
2018-10-10 21:21:44 +01:00
}
2019-02-21 08:48:58 +00:00
http . end ( ) ; // Clean up connection data
2018-10-10 21:21:44 +01:00
} else {
2021-09-01 20:30:54 +01:00
status = WEBCMND_HOST_NOT_FOUND ;
}
}
return status ;
}
# ifdef USE_WEBGETCONFIG
2023-04-03 13:55:47 +01:00
int WebGetConfig ( char * buffer ) {
2021-09-01 20:30:54 +01:00
// http://user:password@server:port/path/%id%.dmp : %id% will be expanded to MAC address
int status = WEBCMND_WRONG_PARAMETERS ;
RemoveSpace ( buffer ) ; // host = |[192.168.178.86:80,admin:joker|
String url = ResolveToken ( buffer ) ;
2021-09-02 09:46:29 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Config Uri '%s' " ) , url . c_str ( ) ) ;
2021-09-01 20:30:54 +01:00
2021-11-26 17:58:35 +00:00
# if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS)
HTTPClientLight http ;
2023-04-03 13:55:47 +01:00
if ( http . begin ( UrlEncode ( url ) ) ) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
2021-11-26 17:58:35 +00:00
# else // HTTP only
2021-09-01 20:30:54 +01:00
WiFiClient http_client ;
HTTPClient http ;
if ( http . begin ( http_client , UrlEncode ( url ) ) ) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
2021-11-26 17:58:35 +00:00
# endif
2021-09-01 20:30:54 +01:00
int http_code = http . GET ( ) ; // Start connection and send HTTP header
if ( http_code > 0 ) { // http_code will be negative on error
status = WEBCMND_DONE ;
if ( http_code = = HTTP_CODE_OK | | http_code = = HTTP_CODE_MOVED_PERMANENTLY ) {
WiFiClient * stream = http . getStreamPtr ( ) ;
int len = http . getSize ( ) ;
2023-07-10 17:14:23 +01:00
if ( len < = sizeof ( TSettings ) ) {
len = sizeof ( TSettings ) ;
}
2023-07-10 15:03:32 +01:00
if ( SettingsBufferAlloc ( len ) ) {
2021-09-01 20:30:54 +01:00
uint8_t * buff = settings_buffer ;
while ( http . connected ( ) & & ( len > 0 ) ) {
size_t size = stream - > available ( ) ;
if ( size ) {
int read = stream - > readBytes ( buff , len ) ;
len - = read ;
}
delayMicroseconds ( 1 ) ;
}
if ( len ) {
2021-09-01 20:37:21 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Connection lost " ) ) ;
2021-09-01 20:30:54 +01:00
status = WEBCMND_CONNECTION_LOST ;
} else if ( SettingsConfigRestore ( ) ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " WEB: Settings applied, restarting " ) ) ;
TasmotaGlobal . restart_flag = 2 ; // Always restart to re-enable disabled features during update
} else {
2021-09-01 20:37:21 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Settings file invalid " ) ) ;
2021-09-01 20:30:54 +01:00
status = WEBCMND_INVALID_FILE ;
}
} else {
2021-09-01 20:37:21 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Memory error (%d) or invalid file length (%d) " ) , settings_buffer , len ) ;
2021-09-01 20:30:54 +01:00
status = WEBCMND_MEMORY_ERROR ;
}
} else {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " WEB: HTTP error %d " ) , http_code ) ;
status = ( http_code = = HTTP_CODE_NOT_FOUND ) ? WEBCMND_FILE_NOT_FOUND : WEBCMND_OTHER_HTTP_ERROR ;
}
} else {
2021-09-01 20:37:21 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Connection failed " ) ) ;
2021-09-01 20:30:54 +01:00
status = 2 ; // Connection failed
2018-10-10 21:21:44 +01:00
}
2021-09-01 20:30:54 +01:00
http . end ( ) ; // Clean up connection data
} else {
status = 3 ; // Host not found or connection error
2018-10-10 21:21:44 +01:00
}
2021-09-01 20:30:54 +01:00
2018-10-10 21:21:44 +01:00
return status ;
}
2021-09-01 20:30:54 +01:00
# endif // USE_WEBGETCONFIG
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
bool JsonWebColor ( const char * dataBuf )
{
2019-11-06 10:16:43 +00:00
// Default (Dark theme)
// {"WebColor":["#eaeaea","#252525","#4f4f4f","#000","#ddd","#65c115","#1f1f1f","#ff5661","#008000","#faffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#faffff","#999","#eaeaea"]}
// Default pre v7 (Light theme)
// {"WebColor":["#000","#fff","#f2f2f2","#000","#fff","#000","#fff","#f00","#008000","#fff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#fff","#999","#000"]} // {"WebColor":["#000000","#ffffff","#f2f2f2","#000000","#ffffff","#000000","#ffffff","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]}
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
2020-09-23 18:38:24 +01:00
JsonParser parser ( ( char * ) dataBuf ) ;
JsonParserObject root = parser . getRootObject ( ) ;
2020-09-21 20:49:32 +01:00
JsonParserArray arr = root [ PSTR ( D_CMND_WEBCOLOR ) ] . getArray ( ) ;
if ( arr ) { // if arr is valid, i.e. json is valid, the key D_CMND_WEBCOLOR was found and the token is an arra
uint32_t i = 0 ;
for ( auto color : arr ) {
if ( i < COL_LAST ) {
WebHexCode ( i , color . getStr ( ) ) ;
} else {
break ;
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
}
2020-09-21 20:49:32 +01:00
i + + ;
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
}
}
return true ;
}
2021-09-01 20:30:54 +01:00
const char kWebCmndStatus [ ] PROGMEM = D_JSON_DONE " | " D_JSON_WRONG_PARAMETERS " | " D_JSON_CONNECT_FAILED " | " D_JSON_HOST_NOT_FOUND " | " D_JSON_MEMORY_ERROR
# ifdef USE_WEBGETCONFIG
" | " D_JSON_FILE_NOT_FOUND " | " D_JSON_OTHER_HTTP_ERROR " | " D_JSON_CONNECTION_LOST " | " D_JSON_INVALID_FILE_TYPE
# endif // USE_WEBGETCONFIG
;
2018-10-10 21:21:44 +01:00
2019-08-11 17:12:18 +01:00
const char kWebCommands [ ] PROGMEM = " | " // No prefix
2022-03-18 13:39:06 +00:00
D_CMND_WEBLOG " | "
2022-05-04 09:19:49 +01:00
# ifndef FIRMWARE_MINIMAL_ONLY
2022-01-16 15:19:28 +00:00
D_CMND_WEBTIME " | "
2019-07-28 16:57:09 +01:00
# ifdef USE_EMULATION
D_CMND_EMULATION " | "
2019-09-04 19:58:17 +01:00
# endif
2022-06-21 15:53:58 +01:00
# ifdef USE_SENDMAIL
2019-09-04 19:58:17 +01:00
D_CMND_SENDMAIL " | "
2019-07-28 16:57:09 +01:00
# endif
2022-03-18 13:39:06 +00:00
D_CMND_WEBSERVER " | " D_CMND_WEBPASSWORD " | " D_CMND_WEBREFRESH " | " D_CMND_WEBSEND " | " D_CMND_WEBQUERY " | "
2021-09-24 10:34:44 +01:00
D_CMND_WEBCOLOR " | " D_CMND_WEBSENSOR " | " D_CMND_WEBBUTTON
2021-09-01 20:30:54 +01:00
# ifdef USE_WEBGETCONFIG
" | " D_CMND_WEBGETCONFIG
# endif
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
" | " D_CMND_CORS
# endif
2022-05-04 09:19:49 +01:00
# endif // FIRMWARE_MINIMAL_ONLY
2021-09-01 20:30:54 +01:00
;
2019-07-28 16:57:09 +01:00
void ( * const WebCommand [ ] ) ( void ) PROGMEM = {
2022-03-18 13:39:06 +00:00
& CmndWeblog ,
2022-05-04 09:19:49 +01:00
# ifndef FIRMWARE_MINIMAL_ONLY
2022-01-16 15:19:28 +00:00
& CmndWebTime ,
2019-07-28 16:57:09 +01:00
# ifdef USE_EMULATION
& CmndEmulation ,
2019-09-04 19:58:17 +01:00
# endif
2022-06-21 15:53:58 +01:00
# ifdef USE_SENDMAIL
2019-09-04 19:58:17 +01:00
& CmndSendmail ,
2019-07-28 16:57:09 +01:00
# endif
2022-03-18 13:39:06 +00:00
& CmndWebServer , & CmndWebPassword , & CmndWebRefresh , & CmndWebSend , & CmndWebQuery ,
2021-09-24 10:34:44 +01:00
& CmndWebColor , & CmndWebSensor , & CmndWebButton
2021-09-01 20:30:54 +01:00
# ifdef USE_WEBGETCONFIG
, & CmndWebGetConfig
# endif
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
, & CmndCors
# endif
2022-05-04 09:19:49 +01:00
# endif // FIRMWARE_MINIMAL_ONLY
2021-08-05 16:55:07 +01:00
} ;
2019-07-28 16:57:09 +01:00
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-16 15:19:28 +00:00
void CmndWebTime ( void ) {
// 2017-03-07T11:08:02-07:00
// 0123456789012345678901234
//
// WebTime 0,16 = 2017-03-07T11:08 - No seconds
// WebTime 11,19 = 11:08:02
uint32_t values [ 2 ] = { 0 } ;
String datetime = GetDateAndTime ( DT_LOCAL ) ;
if ( ParseParameters ( 2 , values ) > 1 ) {
Settings - > web_time_start = values [ 0 ] ;
Settings - > web_time_end = values [ 1 ] ;
if ( Settings - > web_time_end > datetime . length ( ) ) { Settings - > web_time_end = datetime . length ( ) ; }
if ( Settings - > web_time_start > = Settings - > web_time_end ) { Settings - > web_time_start = 0 ; }
}
Response_P ( PSTR ( " { \" %s \" :[%d,%d], \" Time \" : \" %s \" } " ) ,
XdrvMailbox . command , Settings - > web_time_start , Settings - > web_time_end ,
datetime . substring ( Settings - > web_time_start , Settings - > web_time_end ) . c_str ( ) ) ;
}
2019-07-28 16:57:09 +01:00
# ifdef USE_EMULATION
void CmndEmulation ( void )
2018-10-10 21:21:44 +01:00
{
2020-02-25 10:52:52 +00:00
# if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE)
2019-07-28 16:57:09 +01:00
# if defined(USE_EMULATION_WEMO) && defined(USE_EMULATION_HUE)
if ( ( XdrvMailbox . payload > = EMUL_NONE ) & & ( XdrvMailbox . payload < EMUL_MAX ) ) {
# else
# ifndef USE_EMULATION_WEMO
if ( ( EMUL_NONE = = XdrvMailbox . payload ) | | ( EMUL_HUE = = XdrvMailbox . payload ) ) {
# endif
# ifndef USE_EMULATION_HUE
if ( ( EMUL_NONE = = XdrvMailbox . payload ) | | ( EMUL_WEMO = = XdrvMailbox . payload ) ) {
# endif
# endif
2021-06-11 17:14:12 +01:00
Settings - > flag2 . emulation = XdrvMailbox . payload ;
2020-10-29 11:21:24 +00:00
TasmotaGlobal . restart_flag = 2 ;
2019-07-28 16:57:09 +01:00
}
2020-02-25 10:52:52 +00:00
# endif
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > flag2 . emulation ) ;
2019-07-28 16:57:09 +01:00
}
# endif // USE_EMULATION
2018-10-10 21:21:44 +01:00
2022-06-21 15:53:58 +01:00
# ifdef USE_SENDMAIL
void CmndSendmail ( void ) {
2019-09-04 19:58:17 +01:00
if ( XdrvMailbox . data_len > 0 ) {
2019-09-05 16:19:19 +01:00
uint8_t result = SendMail ( XdrvMailbox . data ) ;
char stemp1 [ 20 ] ;
2021-09-01 20:30:54 +01:00
ResponseCmndChar ( GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , result , kWebCmndStatus ) ) ;
2019-09-04 19:58:17 +01:00
}
}
# endif // USE_SENDMAIL
2019-07-28 16:57:09 +01:00
void CmndWebServer ( void )
{
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 2 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > webserver = XdrvMailbox . payload ;
2018-10-10 21:21:44 +01:00
}
2021-06-11 17:14:12 +01:00
if ( Settings - > webserver ) {
2021-01-27 11:03:20 +00:00
Response_P ( PSTR ( " { \" " D_CMND_WEBSERVER " \" : \" " D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %_I \" } " ) ,
2021-06-11 17:14:12 +01:00
( 2 = = Settings - > webserver ) ? PSTR ( D_ADMIN ) : PSTR ( D_USER ) , NetworkHostname ( ) , ( uint32_t ) NetworkAddress ( ) ) ;
2019-07-28 16:57:09 +01:00
} else {
2019-08-03 12:01:34 +01:00
ResponseCmndStateText ( 0 ) ;
2018-10-10 21:21:44 +01:00
}
2019-07-28 16:57:09 +01:00
}
void CmndWebPassword ( void )
{
2021-04-08 16:57:37 +01:00
bool show_asterisk = ( 2 = = XdrvMailbox . index ) ;
2019-12-16 14:13:57 +00:00
if ( XdrvMailbox . data_len > 0 ) {
SettingsUpdateText ( SET_WEBPWD , ( SC_CLEAR = = Shortcut ( ) ) ? " " : ( SC_DEFAULT = = Shortcut ( ) ) ? WEB_PASSWORD : XdrvMailbox . data ) ;
2021-04-08 16:57:37 +01:00
if ( ! show_asterisk ) {
ResponseCmndChar ( SettingsText ( SET_WEBPWD ) ) ;
}
2019-07-28 16:57:09 +01:00
} else {
2021-04-08 16:57:37 +01:00
show_asterisk = true ;
}
if ( show_asterisk ) {
2019-07-28 16:57:09 +01:00
Response_P ( S_JSON_COMMAND_ASTERISK , XdrvMailbox . command ) ;
2018-10-10 21:21:44 +01:00
}
2019-07-28 16:57:09 +01:00
}
void CmndWeblog ( void )
{
2019-10-24 07:55:00 +01:00
if ( ( XdrvMailbox . payload > = LOG_LEVEL_NONE ) & & ( XdrvMailbox . payload < = LOG_LEVEL_DEBUG_MORE ) ) {
2021-06-11 17:14:12 +01:00
Settings - > weblog_level = XdrvMailbox . payload ;
2018-10-10 21:21:44 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > weblog_level ) ;
2019-07-28 16:57:09 +01:00
}
void CmndWebRefresh ( void )
{
2021-04-03 15:17:48 +01:00
if ( ( XdrvMailbox . payload > 999 ) & & ( XdrvMailbox . payload < = 65000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > web_refresh = XdrvMailbox . payload ;
2018-10-10 21:21:44 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > web_refresh ) ;
2019-07-28 16:57:09 +01:00
}
void CmndWebSend ( void )
{
if ( XdrvMailbox . data_len > 0 ) {
uint32_t result = WebSend ( XdrvMailbox . data ) ;
char stemp1 [ 20 ] ;
2021-09-01 20:30:54 +01:00
ResponseCmndChar ( GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , result , kWebCmndStatus ) ) ;
}
}
2021-09-24 10:34:44 +01:00
void CmndWebQuery ( void )
{
if ( XdrvMailbox . data_len > 0 ) {
uint32_t result = WebQuery ( XdrvMailbox . data ) ;
char stemp1 [ 20 ] ;
ResponseCmndChar ( GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , result , kWebCmndStatus ) ) ;
}
}
2021-09-01 20:30:54 +01:00
# ifdef USE_WEBGETCONFIG
2023-04-03 15:12:29 +01:00
void CmndWebGetConfig ( void ) {
2021-09-02 09:46:29 +01:00
// WebGetConfig http://myserver:8000/tasmota/conf/%id%.dmp where %id% is expanded to device mac address
// WebGetConfig http://myserver:8000/tasmota/conf/Config_demo_9.5.0.8.dmp
2021-09-01 20:30:54 +01:00
if ( XdrvMailbox . data_len > 0 ) {
uint32_t result = WebGetConfig ( XdrvMailbox . data ) ;
char stemp1 [ 20 ] ;
ResponseCmndChar ( GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , result , kWebCmndStatus ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-07-28 16:57:09 +01:00
}
2021-09-01 20:30:54 +01:00
# endif // USE_WEBGETCONFIG
2019-07-28 16:57:09 +01:00
void CmndWebColor ( void )
{
if ( XdrvMailbox . data_len > 0 ) {
2020-11-04 10:20:17 +00:00
if ( strchr ( XdrvMailbox . data , ' { ' ) = = nullptr ) { // If no JSON it must be parameter
2019-07-28 16:57:09 +01:00
if ( ( XdrvMailbox . data_len > 3 ) & & ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = COL_LAST ) ) {
WebHexCode ( XdrvMailbox . index - 1 , XdrvMailbox . data ) ;
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
}
2019-07-28 16:57:09 +01:00
else if ( 0 = = XdrvMailbox . payload ) {
SettingsDefaultWebColor ( ) ;
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
}
}
2019-07-28 16:57:09 +01:00
else {
2020-12-27 13:13:23 +00:00
# ifndef FIRMWARE_MINIMAL // if tasmota-minimal, read only and don't parse JSON
2019-07-28 16:57:09 +01:00
JsonWebColor ( XdrvMailbox . data ) ;
2020-12-27 13:13:23 +00:00
# endif // FIRMWARE_MINIMAL
Add command WebColor
* Add rule Http#Initialized
* Add command WebColor to change non-persistent GUI colors on the fly
Use a rule like:
rule3 on http#initialized do webcolor {"webcolor":["#eeeeee","#181818","#4f4f4f","#000000","#dddddd","#008000","#222222","#ff0000","#008000","#ffffff","#1fa3ec","#0e70a4","#d43535","#931f1f","#47c266","#5aaf6f","#ffffff","#999999","#000000"]} endon
or
rule3 on http#initialized do webcolor {"webcolor":["#eee","#181818","#4f4f4f","#000","#ddd","#008000","#222"]} endon
to make color changes persistent)
2019-04-08 21:37:39 +01:00
}
}
2023-03-25 10:59:42 +00:00
Response_P ( PSTR ( " { \" %s \" :[ " ) , XdrvMailbox . command ) ;
2019-07-28 16:57:09 +01:00
for ( uint32_t i = 0 ; i < COL_LAST ; i + + ) {
2023-03-25 10:59:42 +00:00
ResponseAppend_P ( PSTR ( " %s \" #%06x \" " ) , ( i > 0 ) ? " , " : " " , WebColor ( i ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-07-28 16:57:09 +01:00
ResponseAppend_P ( PSTR ( " ]} " ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-08-16 15:54:36 +01:00
void CmndWebSensor ( void )
{
if ( XdrvMailbox . index < MAX_XSNS_DRIVERS ) {
if ( XdrvMailbox . payload > = 0 ) {
2021-07-14 13:20:50 +01:00
bitWrite ( Settings - > sensors [ 1 ] [ XdrvMailbox . index / 32 ] , XdrvMailbox . index % 32 , XdrvMailbox . payload & 1 ) ;
2019-08-16 15:54:36 +01:00
}
}
2019-08-18 12:23:43 +01:00
Response_P ( PSTR ( " { \" " D_CMND_WEBSENSOR " \" : " ) ) ;
2021-07-14 13:20:50 +01:00
XsnsSensorState ( 1 ) ;
2019-08-18 12:23:43 +01:00
ResponseJsonEnd ( ) ;
2019-08-16 15:54:36 +01:00
}
2023-09-29 08:56:52 +01:00
String * WebButton1732 [ 16 ] = { 0 , } ;
void SetWebButton ( uint8_t button_index , const char * text ) {
if ( button_index < 16 )
SettingsUpdateText ( SET_BUTTON1 + button_index , text ) ;
else if ( button_index < MAX_BUTTON_TEXT ) {
button_index - = 16 ;
if ( ! WebButton1732 [ button_index ] )
WebButton1732 [ button_index ] = new String ( text ) ;
else
* WebButton1732 [ button_index ] = text ;
}
}
const char * GetWebButton ( uint8_t button_index ) {
static char empty [ 1 ] = { 0 } ;
if ( button_index < 16 )
return SettingsText ( SET_BUTTON1 + button_index ) ;
else if ( button_index < MAX_BUTTON_TEXT ) {
button_index - = 16 ;
if ( WebButton1732 [ button_index ] )
return WebButton1732 [ button_index ] - > c_str ( ) ;
}
return empty ;
}
2019-12-24 16:10:50 +00:00
void CmndWebButton ( void )
{
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = MAX_BUTTON_TEXT ) ) {
if ( ! XdrvMailbox . usridx ) {
2020-01-12 12:10:21 +00:00
ResponseCmndAll ( SET_BUTTON1 , MAX_BUTTON_TEXT ) ;
2019-12-24 16:10:50 +00:00
} else {
if ( XdrvMailbox . data_len > 0 ) {
2023-09-29 08:56:52 +01:00
SetWebButton ( XdrvMailbox . index - 1 , ( ' " ' = = XdrvMailbox . data [ 0 ] ) ? " " : XdrvMailbox . data ) ;
2019-12-24 16:10:50 +00:00
}
2023-09-29 08:56:52 +01:00
ResponseCmndIdxChar ( GetWebButton ( XdrvMailbox . index - 1 ) ) ;
2019-12-24 16:10:50 +00:00
}
}
}
2021-08-05 16:55:07 +01:00
# ifdef USE_CORS
2019-11-29 17:28:25 +00:00
void CmndCors ( void )
{
2019-12-16 14:13:57 +00:00
if ( XdrvMailbox . data_len > 0 ) {
2021-04-08 16:57:37 +01:00
SettingsUpdateText ( SET_CORS , ( SC_CLEAR = = Shortcut ( ) ) ? " " : ( SC_DEFAULT = = Shortcut ( ) ) ? CORS_DOMAIN : XdrvMailbox . data ) ;
2019-11-29 17:28:25 +00:00
}
2019-12-16 14:13:57 +00:00
ResponseCmndChar ( SettingsText ( SET_CORS ) ) ;
2019-11-29 17:28:25 +00:00
}
2021-08-05 16:55:07 +01:00
# endif
2019-11-29 17:28:25 +00:00
2018-10-10 21:21:44 +01:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-11-11 09:44:56 +00:00
bool Xdrv01 ( uint32_t function )
2018-10-10 21:21:44 +01:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2018-10-10 21:21:44 +01:00
switch ( function ) {
case FUNC_LOOP :
2018-11-26 16:00:18 +00:00
PollDnsWebserver ( ) ;
2018-10-10 21:21:44 +01:00
# ifdef USE_EMULATION
2021-06-11 17:14:12 +01:00
if ( Settings - > flag2 . emulation ) { PollUdp ( ) ; }
2018-10-10 21:21:44 +01:00
# endif // USE_EMULATION
break ;
2021-04-12 17:36:43 +01:00
case FUNC_EVERY_SECOND :
if ( Web . initial_config ) {
Wifi . config_counter = 200 ; // Do not restart the device if it has SSId Blank
}
2022-08-03 06:35:16 +01:00
if ( Wifi . wifi_test_counter ) {
Wifi . wifi_test_counter - - ;
2021-06-05 10:47:09 +01:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_TRYING_TO_CONNECT " %s " ) , SettingsText ( SET_STASSID1 ) ) ;
2023-05-18 10:23:09 +01:00
IPAddress local_ip ;
if ( WifiGetIP ( & local_ip , true ) ) { // Got IP - Connection Established (exclude AP address)
2022-08-03 06:35:16 +01:00
Wifi . wifi_test_AP_TIMEOUT = false ;
Wifi . wifi_test_counter = 0 ;
Wifi . wifiTest = WIFI_TEST_FINISHED ;
2023-05-18 10:23:09 +01:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CMND_SSID " %s: " D_CONNECTED " - " D_IP_ADDRESS " %s " ) , SettingsText ( Wifi . wifi_Test_Save_SSID2 ? SET_STASSID2 : SET_STASSID1 ) , local_ip . toString ( ) . c_str ( ) ) ;
2021-04-12 17:36:43 +01:00
// TasmotaGlobal.blinks = 255; // Signal wifi connection with blinks
2022-08-03 06:35:16 +01:00
if ( MAX_WIFI_OPTION ! = Wifi . old_wificonfig ) {
TasmotaGlobal . wifi_state_flag = Settings - > sta_config = Wifi . old_wificonfig ;
2021-05-30 20:29:15 +01:00
}
2022-08-03 06:35:16 +01:00
TasmotaGlobal . save_data_counter = Wifi . save_data_counter ;
Settings - > save_data = Wifi . save_data_counter ;
2021-04-12 17:36:43 +01:00
SettingsSaveAll ( ) ;
2022-08-03 06:35:16 +01:00
if ( Wifi . wifi_Test_Restart ) { TasmotaGlobal . restart_flag = 2 ; }
2021-04-13 11:00:42 +01:00
# if (!RESTART_AFTER_INITIAL_WIFI_CONFIG)
2021-04-12 17:36:43 +01:00
Web . initial_config = false ;
Web . state = HTTP_ADMIN ;
# endif
2022-08-03 06:35:16 +01:00
} else if ( ! Wifi . wifi_test_counter ) { // Test TimeOut
Wifi . wifi_test_counter = 0 ;
Wifi . wifiTest = WIFI_TEST_FINISHED_BAD ;
2021-04-12 17:36:43 +01:00
switch ( WiFi . status ( ) ) {
case WL_CONNECTED :
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CONNECT_FAILED_NO_IP_ADDRESS ) ) ;
2022-08-03 06:35:16 +01:00
Wifi . wifi_test_AP_TIMEOUT = false ;
2021-04-12 17:36:43 +01:00
break ;
case WL_NO_SSID_AVAIL :
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CONNECT_FAILED_AP_NOT_REACHED ) ) ;
2022-08-03 06:35:16 +01:00
Wifi . wifi_test_AP_TIMEOUT = false ;
2021-04-12 17:36:43 +01:00
break ;
case WL_CONNECT_FAILED :
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CONNECT_FAILED_WRONG_PASSWORD ) ) ;
2022-08-03 06:35:16 +01:00
Wifi . wifi_test_AP_TIMEOUT = false ;
2021-04-12 17:36:43 +01:00
break ;
2021-07-05 14:00:10 +01:00
default : // WL_IDLE_STATUS and WL_DISCONNECTED - SSId in range but no answer from the router
2021-04-12 17:36:43 +01:00
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CONNECT_FAILED_AP_TIMEOUT ) ) ;
2022-08-03 06:35:16 +01:00
// If this error occurs twice, Tasmota will connect directly to the router without testing credentials.
2021-07-05 14:00:10 +01:00
// ESP8266 in AP+STA mode can manage only 11b and 11g, so routers that are 11n-ONLY won't respond.
// For this case, the user will see in the UI a message to check credentials. After that, if the user hits
// save and connect again, and the CONNECT_FAILED_AP_TIMEOUT is shown again, Credentials will be saved and
// Tasmota will restart and try to connect in STA mode only (11b/g/n).
//
// If it fails again, depending on the WIFICONFIG settings, the user will need to wait or will need to
// push 6 times the button to enable Tasmota AP mode again.
2022-08-03 06:35:16 +01:00
if ( Wifi . wifi_test_AP_TIMEOUT ) {
Wifi . wifiTest = WIFI_TEST_FINISHED ;
AddLog ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CMND_SSID " %s: " D_ATTEMPTING_CONNECTION ) , SettingsText ( Wifi . wifi_Test_Save_SSID2 ? SET_STASSID2 : SET_STASSID1 ) ) ;
if ( MAX_WIFI_OPTION ! = Wifi . old_wificonfig ) {
TasmotaGlobal . wifi_state_flag = Settings - > sta_config = Wifi . old_wificonfig ;
2021-07-05 14:00:10 +01:00
}
2022-08-03 06:35:16 +01:00
TasmotaGlobal . save_data_counter = Wifi . save_data_counter ;
Settings - > save_data = Wifi . save_data_counter ;
2021-07-05 14:00:10 +01:00
SettingsSaveAll ( ) ;
}
2022-08-03 06:35:16 +01:00
Wifi . wifi_test_AP_TIMEOUT = true ;
2021-04-12 17:36:43 +01:00
}
2022-06-03 21:57:05 +01:00
WiFi . scanNetworks ( ) ; // restart scan
2021-04-12 17:36:43 +01:00
}
}
2021-04-13 11:00:42 +01:00
break ;
2018-10-10 21:21:44 +01:00
case FUNC_COMMAND :
2019-08-01 14:46:12 +01:00
result = DecodeCommand ( kWebCommands , WebCommand ) ;
2018-10-10 21:21:44 +01:00
break ;
}
return result ;
}
2022-01-17 18:41:17 +00:00
# endif // USE_WEBSERVER