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
2019-12-31 13:23:34 +00:00
Copyright ( C ) 2020 Theo Arends
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)
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-11-26 16:00:18 +00:00
# define XDRV_01 1
2018-11-07 09:30:03 +00:00
2018-12-22 15:13:07 +00:00
# ifndef WIFI_SOFT_AP_CHANNEL
2019-10-22 15:34:25 +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
2020-03-29 14:17:54 +01:00
const uint16_t CHUNKED_BUFFER_SIZE = ( MESSZ / 2 ) - 100 ; // Chunk buffer size (should be smaller than half mqtt_data size = MESSZ)
2019-03-31 10:59:04 +01:00
const uint16_t HTTP_REFRESH_TIME = 2345 ; // milliseconds
# define HTTP_RESTART_RECONNECT_TIME 9000 // milliseconds
# define HTTP_OTA_RESTART_RECONNECT_TIME 20000 // milliseconds
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
2018-10-10 21:21:44 +01:00
# ifdef USE_RF_FLASH
2019-03-26 17:26:50 +00:00
uint8_t * efm8bb1_update = nullptr ;
2018-10-10 21:21:44 +01:00
# endif // USE_RF_FLASH
2019-10-26 21:58:04 +01:00
enum UploadTypes { UPL_TASMOTA , UPL_SETTINGS , UPL_EFM8BB1 , UPL_TASMOTASLAVE } ;
2018-10-10 21:21:44 +01:00
2019-08-06 09:57:50 +01:00
static const char * HEADER_KEYS [ ] = { " User-Agent " , } ;
2020-04-10 17:24:08 +01:00
const char HTTP_HEADER1 [ ] PROGMEM =
2018-10-10 21:21:44 +01:00
" <!DOCTYPE html><html lang= \" " D_HTML_LANGUAGE " \" class= \" \" > "
" <head> "
" <meta charset='utf-8'> "
" <meta name= \" viewport \" content= \" width=device-width,initial-scale=1,user-scalable=no \" /> "
2019-03-04 17:16:07 +00:00
" <title>%s - %s</title> "
2018-10-10 21:21:44 +01:00
" <script> "
2019-02-18 10:35:49 +00:00
" var x=null,lt,to,tp,pc=''; " // x=null allow for abortion
2019-06-11 15:19:56 +01:00
2019-06-12 16:32:25 +01:00
# ifdef USE_JAVASCRIPT_ES6
// Following bytes saving ES6 syntax fails on old browsers like IE 11 - https://kangax.github.io/compat-table/es6/
" eb=s=>document.getElementById(s); " // Alias to save code space
" qs=s=>document.querySelector(s); " // Alias to save code space
" sp=i=>eb(i).type=(eb(i).type==='text'?'password':'text'); " // Toggle password visibility
2019-06-15 15:09:04 +01:00
" wl=f=>window.addEventListener('load',f); " // Execute multiple window.onload
;
2019-06-12 16:32:25 +01:00
# else
2018-10-10 21:21:44 +01:00
" function eb(s){ "
2019-06-11 15:19:56 +01:00
" return document.getElementById(s); " // Alias to save code space
2019-05-31 17:24:56 +01:00
" } "
2019-06-02 15:44:02 +01:00
" function qs(s){ " // Alias to save code space
2019-05-31 18:51:24 +01:00
" return document.querySelector(s); "
" } "
2019-06-11 13:30:07 +01:00
" function sp(i){ " // Toggle password visibility
2019-06-11 13:56:05 +01:00
" eb(i).type=(eb(i).type==='text'?'password':'text'); "
2019-06-11 13:30:07 +01:00
" } "
2019-06-02 15:44:02 +01:00
" function wl(f){ " // Execute multiple window.onload
2019-06-15 15:09:04 +01:00
" window.addEventListener('load',f); "
2019-06-02 15:44:02 +01:00
" } " ;
2019-06-15 15:09:04 +01: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
const char HTTP_SCRIPT_ROOT [ ] PROGMEM =
2019-09-24 07:43:13 +01:00
# ifdef USE_SCRIPT_WEB_DISPLAY
2019-09-24 07:25:32 +01:00
" var rfsh=1; "
2018-10-10 21:21:44 +01:00
" function la(p){ "
" var a=''; "
" if(la.arguments.length==1){ "
" a=p; "
" clearTimeout(lt); "
" } "
2019-03-04 17:16:07 +00:00
" if(x!=null){x.abort();} " // Abort if no response within 2 seconds (happens on restart 1)
2018-10-10 21:21:44 +01:00
" x=new XMLHttpRequest(); "
" x.onreadystatechange=function(){ "
" if(x.readyState==4&&x.status==200){ "
2019-03-04 17:16:07 +00:00
" var s=x.responseText.replace(/{t}/g, \" <table style='width:100%%'> \" ).replace(/{s}/g, \" <tr><th> \" ).replace(/{m}/g, \" </th><td> \" ).replace(/{e}/g, \" </td></tr> \" ).replace(/{c}/g, \" %%'><div style='text-align:center;font-weight: \" ); "
2018-10-10 21:21:44 +01:00
" eb('l1').innerHTML=s; "
" } "
" }; "
2019-09-24 07:25:32 +01:00
" if (rfsh) { "
2020-04-15 08:58:38 +01:00
" x.open('GET','.?m=1'+a,true); " // ?m related to Webserver->hasArg("m")
2019-09-24 07:25:32 +01:00
" x.send(); "
" lt=setTimeout(la,%d); " // Settings.web_refresh
" } "
2018-10-10 21:21:44 +01:00
" } "
2019-09-16 18:52:53 +01:00
" function seva(par,ivar){ "
" la('&sv='+ivar+'_'+par); "
" } "
2019-09-24 07:25:32 +01:00
" function siva(par,ivar){ "
" rfsh=1; "
" la('&sv='+ivar+'_'+par); "
" rfsh=0; "
" } "
" function pr(f){ "
" if (f) { "
" lt=setTimeout(la,%d); "
" rfsh=1; "
" } else { "
" clearTimeout(lt); "
" rfsh=0; "
" } "
2019-11-25 16:21:31 +00:00
" } " ;
2019-09-29 17:00:01 +01:00
# else // USE_SCRIPT_WEB_DISPLAY
2019-09-24 07:32:55 +01:00
" function la(p){ "
" var a=''; "
" if(la.arguments.length==1){ "
" a=p; "
" clearTimeout(lt); "
" } "
" if(x!=null){x.abort();} " // Abort if no response within 2 seconds (happens on restart 1)
" x=new XMLHttpRequest(); "
" x.onreadystatechange=function(){ "
" if(x.readyState==4&&x.status==200){ "
" var s=x.responseText.replace(/{t}/g, \" <table style='width:100%%'> \" ).replace(/{s}/g, \" <tr><th> \" ).replace(/{m}/g, \" </th><td> \" ).replace(/{e}/g, \" </td></tr> \" ).replace(/{c}/g, \" %%'><div style='text-align:center;font-weight: \" ); "
" eb('l1').innerHTML=s; "
" } "
" }; "
2020-04-15 08:58:38 +01:00
" x.open('GET','.?m=1'+a,true); " // ?m related to Webserver->hasArg("m")
2019-09-24 07:32:55 +01:00
" x.send(); "
" lt=setTimeout(la,%d); " // Settings.web_refresh
2019-11-25 16:21:31 +00:00
" } " ;
2019-09-29 17:00:01 +01:00
# endif // USE_SCRIPT_WEB_DISPLAY
2019-06-15 15:09:04 +01:00
2019-11-25 16:21:31 +00:00
const char HTTP_SCRIPT_ROOT_PART2 [ ] PROGMEM =
2019-10-15 15:41:53 +01:00
" function lc(v,i,p){ "
2019-11-30 15:05:09 +00:00
" if(eb('s')){ " // Check if Saturation is in DOM otherwise javascript fails on la()
" if(v=='h'||v=='d'){ " // Hue or Brightness changed so change Saturation colors too
" var sl=eb('sl4').value; "
" 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
" } "
2019-10-15 15:41:53 +01:00
" la('&'+v+i+'='+p); "
2019-11-22 09:49:15 +00:00
" } "
2019-06-02 15:44:02 +01:00
" wl(la); " ;
2018-11-10 15:45:32 +00:00
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
2018-11-10 16:30:23 +00:00
const char HTTP_SCRIPT_RELOAD [ ] PROGMEM =
2019-03-04 11:36:44 +00:00
" setTimeout(function(){location.href='.';}, " STR ( HTTP_RESTART_RECONNECT_TIME ) " ); " ;
2018-11-24 10:46:32 +00:00
// Local OTA upgrade requires more time to complete cp: before web ui should be reloaded
const char HTTP_SCRIPT_RELOAD_OTA [ ] PROGMEM =
2019-03-04 11:36:44 +00:00
" setTimeout(function(){location.href='.';}, " STR ( HTTP_OTA_RESTART_RECONNECT_TIME ) " ); " ;
2018-10-10 21:21:44 +01:00
const char HTTP_SCRIPT_CONSOL [ ] PROGMEM =
2019-06-15 14:20:31 +01:00
" var sn=0,id=0; " // Scroll position, Get most of weblog initially
2019-02-18 10:35:49 +00:00
" function l(p){ " // Console log and command service
2019-06-15 14:20:31 +01:00
" var c,o='',t; "
2018-10-10 21:21:44 +01:00
" clearTimeout(lt); "
" t=eb('t1'); "
" if(p==1){ "
2020-03-29 14:17:54 +01:00
" c=eb('c1'); " // Console command id
2018-10-10 21:21:44 +01:00
" o='&c1='+encodeURIComponent(c.value); "
" c.value=''; "
2020-01-14 14:38:16 +00:00
" t.scrollTop=99999; "
" sn=t.scrollTop; "
2018-10-10 21:21:44 +01:00
" } "
2019-02-18 10:35:49 +00:00
" if(t.scrollTop>=sn){ " // User scrolled back so no updates
" if(x!=null){x.abort();} " // Abort if no response within 2 seconds (happens on restart 1)
2018-10-10 21:21:44 +01:00
" x=new XMLHttpRequest(); "
" x.onreadystatechange=function(){ "
" if(x.readyState==4&&x.status==200){ "
" var z,d; "
2019-03-04 17:16:07 +00:00
" d=x.responseText.split(/}1/); " // Field separator
2019-02-07 19:41:38 +00:00
" id=d.shift(); "
" if(d.shift()==0){t.value='';} "
" z=d.shift(); "
" if(z.length>0){t.value+=z;} "
2018-10-10 21:21:44 +01:00
" t.scrollTop=99999; "
" sn=t.scrollTop; "
" } "
" }; "
2020-04-15 08:58:38 +01:00
" x.open('GET','cs?c2='+id+o,true); " // Related to Webserver->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp))
2018-10-10 21:21:44 +01:00
" x.send(); "
" } "
2019-03-04 17:16:07 +00:00
" lt=setTimeout(l,%d); "
2018-10-10 21:21:44 +01:00
" return false; "
" } "
2020-03-31 12:01:50 +01:00
" wl(l); " // Load initial console text
2020-03-29 14:17:54 +01:00
2020-03-31 12:01:50 +01:00
// Console command history
2020-03-29 14:35:58 +01:00
" var hc=[],cn=0; " // hc = History commands, cn = Number of history being shown
2020-03-31 12:01:50 +01:00
" function h(){ "
// "if(!(navigator.maxTouchPoints||'ontouchstart'in document.documentElement)){eb('c1').autocomplete='off';}" // No touch so stop browser autocomplete
" eb('c1').addEventListener('keydown',function(e){ "
" var b=eb('c1'),c=e.keyCode; " // c1 = Console command id
" if(38==c||40==c){b.autocomplete='off';} " // ArrowUp or ArrowDown must be a keyboard so stop browser autocomplete
" 38==c?(++cn>hc.length&&(cn=hc.length),b.value=hc[cn-1]||''): " // ArrowUp
" 40==c?(0>--cn&&(cn=0),b.value=hc[cn-1]||''): " // ArrowDown
" 13==c&&(hc.length>19&&hc.pop(),hc.unshift(b.value),cn=0) " // Enter, 19 = Max number -1 of commands in history
" }); "
2020-03-29 14:17:54 +01:00
" } "
2020-03-31 12:01:50 +01:00
" wl(h); " ; // Add console command key eventlistener after name has been synced with id (= wl(jd))
2019-02-17 10:32:53 +00:00
2019-02-24 14:05:18 +00:00
const char HTTP_MODULE_TEMPLATE_REPLACE [ ] PROGMEM =
2020-05-01 15:47:41 +01:00
" }2%d'>%s (%d}3 " ; // }2 and }3 are used in below os.replace
2019-02-24 14:05:18 +00:00
2019-02-17 10:32:53 +00:00
const char HTTP_SCRIPT_MODULE_TEMPLATE [ ] PROGMEM =
2020-04-30 17:47:34 +01:00
# ifdef ESP8266
" var os; "
" function sk(s,g){ " // s = value, g = id and name
2020-05-01 15:47:41 +01:00
" var o=os.replace(/}2/g, \" <option value=' \" ).replace(/}3/g, \" )</option> \" ); "
2020-04-30 17:47:34 +01:00
" eb('g'+g).innerHTML=o; "
" eb('g'+g).value=s; "
2020-05-01 15:47:41 +01:00
" } " ;
2020-04-30 17:47:34 +01:00
# else // ESP32
" var os,hs; "
" function ce(i,q){ " // Create index select
" var o=document.createElement('option'); "
" o.textContent=i; "
" q.appendChild(o); "
" } "
" function ot(g,s){ " // g = id and name, s = value
" var p,l,t=qs('#h'+g),u=s&0x001f; "
" l=t.options.length; " // Remove current options
" for(i=l;i;i--){p=t.options[i-1].parentNode;p.removeChild(t.options[i-1]);} "
" s>>=5; " // Add options
" for(i=1;i<=hs[s];i++){ce((i<10)?(' '+i):i,t);} "
" eb('h'+g).value=u+1; " // Set selected value
" t.style.visibility=(hs[s]>0)?'':'hidden'; "
" } "
" function sk(s,g){ " // s = value, g = id and name
2020-05-01 15:47:41 +01:00
" var o=os.replace(/}2/g, \" <option value=' \" ).replace(/}3/g, \" )</option> \" ); "
2020-04-30 17:47:34 +01:00
" eb('g'+g).innerHTML=o; "
2020-05-01 15:47:41 +01:00
" eb('g'+g).value=(g<99)?s&0xffe0:s; "
2020-04-30 17:47:34 +01:00
" if(g<99){ot(g,s);} "
2020-05-01 15:47:41 +01:00
" } " ;
2020-04-30 17:47:34 +01:00
# endif // ESP8266 - ESP32
2020-05-01 15:47:41 +01:00
const char HTTP_SCRIPT_TEMPLATE [ ] PROGMEM =
2019-02-18 10:35:49 +00:00
" function ld(u,f){ "
" var x=new XMLHttpRequest(); "
" x.onreadystatechange=function(){ "
" if(this.readyState==4&&this.status==200){ "
" f(this); "
" } "
" }; "
" x.open('GET',u,true); "
" x.send(); "
2020-05-01 15:47:41 +01:00
" } "
2019-02-18 10:35:49 +00:00
" var c; " // Need a global for BASE
" function x1(b){ "
2019-02-24 14:05:18 +00:00
" var i,j,g,k,o; "
2019-03-04 17:16:07 +00:00
" o=b.responseText.split(/}1/); " // Field separator
2019-02-24 14:05:18 +00:00
" k=o.shift(); " // Template name
2019-02-18 10:35:49 +00:00
" if(eb('s1').value==''){ "
2019-02-24 14:05:18 +00:00
" eb('s1').value=k; " // Set NAME if not yet set
2019-02-18 10:35:49 +00:00
" } "
2020-04-25 14:34:18 +01:00
" g=o.shift().split(','); " // GPIO - Array separator
" os= \" " ; // }2'0'>None (0)}3}2'17'>Button1 (17)}3...
const char HTTP_SCRIPT_TEMPLATE2 [ ] PROGMEM =
2019-02-18 10:35:49 +00:00
" j=0; "
2020-04-12 17:17:35 +01:00
" for(i=0;i< " STR ( MAX_USER_PINS ) " ;i++){ " // Supports 13 GPIOs
2019-02-18 10:35:49 +00:00
" if(6==i){j=9;} "
" if(8==i){j=12;} "
" sk(g[i],j); " // Set GPIO
" j++; "
" } "
2020-05-01 15:47:41 +01:00
" g=o.shift(); " ; // FLAG
2020-04-25 14:34:18 +01:00
const char HTTP_SCRIPT_TEMPLATE3 [ ] PROGMEM =
" \" ; "
2020-04-12 17:17:35 +01:00
" sk(g&15, " STR ( ADC0_PIN ) " ); " // Set ADC0
2020-05-01 15:47:41 +01:00
" g>>=4; " ;
const char HTTP_SCRIPT_TEMPLATE4 [ ] PROGMEM =
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); " ;
const char HTTP_HEAD_LAST_SCRIPT [ ] PROGMEM =
2019-06-15 14:20:31 +01:00
" function jd(){ " // Add label name='' based on provided id=''
2019-06-02 15:44:02 +01:00
" var t=0,i=document.querySelectorAll('input,button,textarea,select'); "
" while(i.length>=t){ "
" if(i[t]){ "
" i[t]['name']=(i[t].hasAttribute('id')&&(!i[t].hasAttribute('name')))?i[t]['id']:i[t]['name']; "
" } "
" t++; "
" } "
" } "
2019-06-15 14:20:31 +01:00
" wl(jd); " // Add name='' to any id='' in input,button,textarea,select
2019-06-02 15:44:02 +01:00
" </script> " ;
2018-11-10 16:30:23 +00:00
2019-03-04 17:16:07 +00:00
const char HTTP_HEAD_STYLE1 [ ] PROGMEM =
2018-11-10 16:30:23 +00:00
" <style> "
" div,fieldset,input,select{padding:5px;font-size:1em;} "
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
" fieldset{background:#%06x;} " // COLOR_FORM, Also update HTTP_TIMER_STYLE
2019-02-13 15:26:16 +00:00
" p{margin:0.5em 0;} "
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
" input{width:100%%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;background:#%06x;color:#%06x;} " // COLOR_INPUT, COLOR_INPUT_TEXT
2019-02-13 15:05:25 +00:00
" input[type=checkbox],input[type=radio]{width:1em;margin-right:6px;vertical-align:-1px;} "
2019-11-24 14:13:07 +00:00
" input[type=range]{width:99%%;} "
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
" select{width:100%%;background:#%06x;color:#%06x;} " // COLOR_INPUT, COLOR_INPUT_TEXT
2020-01-14 14:38:16 +00:00
" textarea{resize:vertical;width:98%%;height:318px;padding:5px;overflow:auto;background:#%06x;color:#%06x;} " // COLOR_CONSOLE, COLOR_CONSOLE_TEXT
2019-04-18 09:34:55 +01:00
" body{text-align:center;font-family:verdana,sans-serif;background:#%06x;} " // COLOR_BACKGROUND
2019-03-04 17:16:07 +00:00
" td{padding:0px;} " ;
const char HTTP_HEAD_STYLE2 [ ] PROGMEM =
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
" button{border:0;border-radius:0.3rem;background:#%06x;color:#%06x;line-height:2.4rem;font-size:1.2rem;width:100%%;-webkit-transition-duration:0.4s;transition-duration:0.4s;cursor:pointer;} " // COLOR_BUTTON, COLOR_BUTTON_TEXT
" button:hover{background:#%06x;} " // COLOR_BUTTON_HOVER
" .bred{background:#%06x;} " // COLOR_BUTTON_RESET
" .bred:hover{background:#%06x;} " // COLOR_BUTTON_RESET_HOVER
" .bgrn{background:#%06x;} " // COLOR_BUTTON_SAVE
" .bgrn:hover{background:#%06x;} " // COLOR_BUTTON_SAVE_HOVER
2019-11-06 10:16:43 +00:00
" a{color:#%06x;text-decoration:none;} " // COLOR_BUTTON
2018-11-10 16:30:23 +00:00
" .p{float:left;text-align:left;} "
2019-11-22 11:25:55 +00:00
" .q{float:right;text-align:right;} "
" .r{border-radius:0.3em;padding:2px;margin:6px 2px;} " ;
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
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
2018-11-10 16:30:23 +00:00
# endif
2019-11-02 04:33:40 +00:00
" <div style='text-align:center;color:#%06x;'><noscript> " D_NOSCRIPT " <br></noscript> " // COLOR_TITLE
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
2019-03-14 15:50:56 +00:00
" <h2>%s</h2> " ;
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:24:56 +00:00
const char HTTP_MSG_SLIDER_SHUTTER [ ] PROGMEM =
" <div><span class='p'> " D_CLOSE " </span><span class='q'> " D_OPEN " </span></div> "
" <div><input type='range' min='0' max='100' value='%d' onchange='lc( \" u \" ,%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
2018-10-10 21:21:44 +01:00
const char HTTP_FORM_WIFI [ ] PROGMEM =
2019-02-13 15:05:25 +00:00
" <fieldset><legend><b> " D_WIFI_PARAMETERS " </b></legend> "
" <form method='get' action='wi'> "
2019-05-31 17:24:56 +01:00
" <p><b> " D_AP1_SSID " </b> ( " STA_SSID1 " )<br><input id='s1' placeholder=' " STA_SSID1 " ' value='%s'></p> "
2020-04-05 13:11:49 +01:00
" <p><label><b> " D_AP1_PASSWORD " </b><input type='checkbox' onclick='sp( \" p1 \" )'></label><br><input id='p1' type='password' placeholder=' " D_AP1_PASSWORD " ' value=' " D_ASTERISK_PWD " '></p> "
2019-05-31 17:24:56 +01:00
" <p><b> " D_AP2_SSID " </b> ( " STA_SSID2 " )<br><input id='s2' placeholder=' " STA_SSID2 " ' value='%s'></p> "
2020-04-05 13:11:49 +01:00
" <p><label><b> " D_AP2_PASSWORD " </b><input type='checkbox' onclick='sp( \" p2 \" )'></label><br><input id='p2' type='password' placeholder=' " D_AP2_PASSWORD " ' value=' " D_ASTERISK_PWD " '></p> "
2019-11-29 17:28:25 +00:00
" <p><b> " D_HOSTNAME " </b> (%s)<br><input id='h' placeholder='%s' value='%s'></p> "
" <p><b> " D_CORS_DOMAIN " </b><input id='c' placeholder=' " CORS_DOMAIN " ' value='%s'></p> " ;
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 =
2019-05-31 17:24:56 +01:00
" <p><b> " D_SYSLOG_HOST " </b> ( " SYS_LOG_HOST " )<br><input id='lh' placeholder=' " SYS_LOG_HOST " ' value='%s'></p> "
" <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> "
2019-05-31 17:24:56 +01:00
" <p><input id='t1' placeholder=' " D_TEMPLATE " ' value='%s'></p> "
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-04-05 13:11:49 +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> "
2020-04-05 13:11:49 +01:00
" <label><input id='b1' type='checkbox'%s><b> " D_MQTT_ENABLE " </b></label><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'> "
2019-05-31 17:24:56 +01:00
" <br><b> " D_OTA_URL " </b><br><input id='o' placeholder='OTA_URL' value='%s'><br> "
" <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 =
" <form method='post' action='u2' enctype='multipart/form-data'> "
2019-05-31 17:24:56 +01:00
" <br><input type='file' name='u2'><br> "
" <br><button type='submit' onclick='eb( \" f1 \" ).style.display= \" none \" ;eb( \" f2 \" ).style.display= \" block \" ;this.form.submit();'> " D_START " %s</button></form> "
2018-10-10 21:21:44 +01:00
" </fieldset> "
" </div> "
2019-05-31 17:24:56 +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
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> " ;
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> " ;
2019-03-01 17:25:46 +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("o", tmp, sizeof(tmp));
2019-03-16 15:23:41 +00:00
const char HTTP_DEVICE_STATE [ ] PROGMEM = " <td style='width:%d{c}%s;font-size:%dpx'>%s</div></td> " ; // {c} = %'><div style='text-align:center;font-weight:
2018-10-10 21:21:44 +01:00
2019-03-11 09:38:41 +00:00
enum ButtonTitle {
BUTTON_RESTART , BUTTON_RESET_CONFIGURATION ,
BUTTON_MAIN , BUTTON_CONFIGURATION , BUTTON_INFORMATION , BUTTON_FIRMWARE_UPGRADE , BUTTON_CONSOLE ,
BUTTON_MODULE , BUTTON_WIFI , BUTTON_LOGGING , BUTTON_OTHER , BUTTON_TEMPLATE , BUTTON_BACKUP , BUTTON_RESTORE } ;
const char kButtonTitle [ ] PROGMEM =
D_RESTART " | " D_RESET_CONFIGURATION " | "
D_MAIN_MENU " | " D_CONFIGURATION " | " D_INFORMATION " | " D_FIRMWARE_UPGRADE " | " D_CONSOLE " | "
D_CONFIGURE_MODULE " | " D_CONFIGURE_WIFI " | " D_CONFIGURE_LOGGING " | " D_CONFIGURE_OTHER " | " D_CONFIGURE_TEMPLATE " | " D_BACKUP_CONFIGURATION " | " D_RESTORE_CONFIGURATION ;
const char kButtonAction [ ] PROGMEM =
" .|rt| "
" .|cn|in|up|cs| "
" md|wi|lg|co|tp|dl|rs " ;
const char kButtonConfirm [ ] PROGMEM = D_CONFIRM_RESTART " | " D_CONFIRM_RESET_CONFIGURATION ;
2019-02-23 14:29:42 +00:00
enum CTypes { CT_HTML , CT_PLAIN , CT_XML , CT_JSON , CT_STREAM } ;
const char kContentTypes [ ] PROGMEM = " text/html|text/plain|text/xml|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 =
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
# ifdef USE_RF_FLASH
" | " D_UPLOAD_ERR_10 " | " D_UPLOAD_ERR_11 " | " D_UPLOAD_ERR_12 " | " D_UPLOAD_ERR_13
# endif
2019-12-20 17:24:20 +00:00
" | " D_UPLOAD_ERR_14
2019-02-23 12:17:02 +00:00
;
2019-03-31 10:59:04 +01:00
const uint16_t DNS_PORT = 53 ;
2019-02-21 16:49:11 +00:00
enum HttpOptions { HTTP_OFF , HTTP_USER , HTTP_ADMIN , HTTP_MANAGER , HTTP_MANAGER_RESET_ONLY } ;
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
bool reset_web_log_flag = false ; // Reset web console log
uint8_t state = HTTP_OFF ;
uint8_t upload_error = 0 ;
uint8_t upload_file_type ;
uint8_t upload_progress_dot_count ;
uint8_t config_block_count = 0 ;
uint8_t config_xor_on = 0 ;
uint8_t config_xor_on_set = CONFIG_FILE_XOR ;
} Web ;
2018-10-10 21:21:44 +01:00
// Helper function to avoid code duplication (saves 4k Flash)
static void WebGetArg ( const char * arg , char * out , size_t max )
{
2020-04-15 08:58:38 +01:00
String s = Webserver - > arg ( arg ) ;
2018-10-10 21:21:44 +01:00
strlcpy ( out , s . c_str ( ) , max ) ;
// out[max-1] = '\0'; // Ensure terminating NUL
}
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 ] ;
2020-04-15 08:58:38 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " SRC: %s from %s " ) , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , source , kCommandSource ) , Webserver - > client ( ) . remoteIP ( ) . toString ( ) . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
}
2019-09-04 11:58:37 +01:00
void ExecuteWebCommand ( char * svalue , uint32_t source )
2018-10-10 21:21:44 +01:00
{
ShowWebSource ( source ) ;
2019-09-29 17:00:01 +01:00
last_source = source ;
2018-10-10 21:21:44 +01:00
ExecuteCommand ( svalue , SRC_IGNORE ) ;
}
void StartWebserver ( int type , IPAddress ipweb )
{
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 ) ;
Webserver - > on ( " / " , HandleRoot ) ;
Webserver - > onNotFound ( HandleNotFound ) ;
Webserver - > on ( " /up " , HandleUpgradeFirmware ) ;
Webserver - > on ( " /u1 " , HandleUpgradeFirmwareStart ) ; // OTA
Webserver - > on ( " /u2 " , HTTP_POST , HandleUploadDone , HandleUploadLoop ) ;
Webserver - > on ( " /u2 " , HTTP_OPTIONS , HandlePreflightRequest ) ;
Webserver - > on ( " /cs " , HTTP_GET , HandleConsole ) ;
Webserver - > on ( " /cs " , HTTP_OPTIONS , HandlePreflightRequest ) ;
Webserver - > on ( " /cm " , HandleHttpCommand ) ;
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2020-04-15 08:58:38 +01:00
Webserver - > on ( " /cn " , HandleConfiguration ) ;
Webserver - > on ( " /md " , HandleModuleConfiguration ) ;
Webserver - > on ( " /wi " , HandleWifiConfiguration ) ;
Webserver - > on ( " /lg " , HandleLoggingConfiguration ) ;
Webserver - > on ( " /tp " , HandleTemplateConfiguration ) ;
Webserver - > on ( " /co " , HandleOtherConfiguration ) ;
Webserver - > on ( " /dl " , HandleBackupConfiguration ) ;
Webserver - > on ( " /rs " , HandleRestoreConfiguration ) ;
Webserver - > on ( " /rt " , HandleResetConfiguration ) ;
Webserver - > on ( " /in " , HandleInformation ) ;
2019-03-07 17:18:30 +00:00
XdrvCall ( FUNC_WEB_ADD_HANDLER ) ;
XsnsCall ( FUNC_WEB_ADD_HANDLER ) ;
2019-02-08 13:55:45 +00:00
# endif // Not FIRMWARE_MINIMAL
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
// Collect User-Agent for Alexa Hue Emulation
// This is used in xdrv_20_hue.ino in function findEchoGeneration()
2020-04-15 08:58:38 +01:00
Webserver - > collectHeaders ( HEADER_KEYS , sizeof ( HEADER_KEYS ) / sizeof ( char * ) ) ;
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 ) {
2019-12-11 14:53:19 +00:00
# if LWIP_IPV6
String ipv6_addr = WifiGetIPv6 ( ) ;
if ( ipv6_addr ! = " " ) AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s " ) , my_hostname , ( Wifi . mdns_begun ) ? " .local " : " " , ipweb . toString ( ) . c_str ( ) , ipv6_addr . c_str ( ) ) ;
else AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s " ) , my_hostname , ( Wifi . mdns_begun ) ? " .local " : " " , ipweb . toString ( ) . c_str ( ) ) ;
# else
2019-08-17 16:13:09 +01:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s " ) , my_hostname , ( Wifi . mdns_begun ) ? " .local " : " " , ipweb . toString ( ) . c_str ( ) ) ;
2019-12-11 14:53:19 +00:00
# endif // LWIP_IPV6 = 1
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
rules_flag . http_init = 1 ;
2018-10-10 21:21:44 +01:00
}
2019-08-15 12:50:28 +01:00
if ( type ) { 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 ;
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP D_WEBSERVER_STOPPED ) ) ;
}
}
2019-02-21 16:49:11 +00:00
void WifiManagerBegin ( bool reset_only )
2018-10-10 21:21:44 +01:00
{
// setup AP
2018-11-04 17:00:07 +00:00
if ( ! global_state . wifi_down ) {
2019-11-08 12:00:32 +00:00
// WiFi.mode(WIFI_AP_STA);
WifiSetMode ( WIFI_AP_STA ) ;
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION ) ) ;
} else {
2019-11-08 12:00:32 +00:00
// WiFi.mode(WIFI_AP);
WifiSetMode ( WIFI_AP ) ;
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT ) ) ;
}
StopWebserver ( ) ;
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
# ifdef ARDUINO_ESP8266_RELEASE_2_3_0
// bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0);
WiFi . softAP ( my_hostname , WIFI_AP_PASSPHRASE , channel , 0 ) ;
# else
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-02-10 13:24:53 +00:00
WiFi . softAP ( my_hostname , WIFI_AP_PASSPHRASE , channel , 0 , 1 ) ;
# endif
2018-12-22 15:13:07 +00:00
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 ( ) ) ;
2019-02-21 16:49:11 +00:00
StartWebserver ( ( reset_only ? HTTP_MANAGER_RESET_ONLY : HTTP_MANAGER ) , WiFi . softAPIP ( ) ) ;
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 ;
}
return true ;
}
2018-10-10 21:21:44 +01:00
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
}
}
2019-03-04 17:16:07 +00:00
void WSHeaderSend ( void )
{
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 " ) ) ;
2019-10-28 12:36:04 +00:00
HttpHeaderCors ( ) ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-03-16 15:23:41 +00: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 ( ) ;
# ifdef ARDUINO_ESP8266_RELEASE_2_3_0
2020-04-15 08:58:38 +01:00
Webserver - > sendHeader ( F ( " Accept-Ranges " ) , F ( " none " ) ) ;
Webserver - > sendHeader ( F ( " Transfer-Encoding " ) , F ( " chunked " ) ) ;
2019-03-16 15:23:41 +00:00
# endif
2020-04-15 08:58:38 +01:00
Webserver - > setContentLength ( CONTENT_LENGTH_UNKNOWN ) ;
2019-03-16 15:23:41 +00: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
}
2019-03-10 14:36:34 +00:00
void _WSContentSend ( const String & content ) // Low level sendContent for all core versions
2019-03-04 17:16:07 +00:00
{
size_t len = content . length ( ) ;
# ifdef ARDUINO_ESP8266_RELEASE_2_3_0
const char * footer = " \r \n " ;
char chunk_size [ 11 ] ;
sprintf ( chunk_size , " %x \r \n " , len ) ;
2020-04-15 08:58:38 +01:00
Webserver - > sendContent ( String ( ) + chunk_size + content + footer ) ;
2019-03-04 17:16:07 +00:00
# else
2020-04-15 08:58:38 +01:00
Webserver - > sendContent ( content ) ;
2019-03-04 17:16:07 +00:00
# endif
2019-03-11 09:38:41 +00:00
# ifdef USE_DEBUG_DRIVER
ShowFreeMem ( PSTR ( " WSContentSend " ) ) ;
# endif
2020-03-29 14:17:54 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Chunk size %d/%d " ) , len , sizeof ( mqtt_data ) ) ;
2019-03-04 17:16:07 +00:00
}
2019-11-20 19:53:12 +00:00
void WSContentFlush ( void )
2019-03-04 17:16:07 +00:00
{
2019-08-15 12:50:28 +01:00
if ( Web . chunk_buffer . length ( ) > 0 ) {
_WSContentSend ( Web . chunk_buffer ) ; // Flush chunk buffer
Web . chunk_buffer = " " ;
2019-03-04 17:16:07 +00:00
}
}
2019-03-19 16:31:43 +00:00
void _WSContentSendBuffer ( void )
2019-03-04 17:16:07 +00:00
{
2019-03-19 16:31:43 +00:00
int len = strlen ( mqtt_data ) ;
2019-03-04 17:16:07 +00:00
2019-03-10 14:36:34 +00:00
if ( 0 = = len ) { // No content
2019-03-04 17:16:07 +00:00
return ;
}
2019-03-10 14:36:34 +00:00
else if ( len = = sizeof ( mqtt_data ) ) {
AddLog_P ( LOG_LEVEL_INFO , PSTR ( " HTP: Content too large " ) ) ;
}
else if ( len < CHUNKED_BUFFER_SIZE ) { // Append chunk buffer with small content
2019-08-15 12:50:28 +01:00
Web . chunk_buffer + = mqtt_data ;
len = Web . chunk_buffer . length ( ) ;
2019-03-04 17:16:07 +00:00
}
2019-03-10 14:36:34 +00:00
if ( len > = CHUNKED_BUFFER_SIZE ) { // Either content or chunk buffer is oversize
WSContentFlush ( ) ; // Send chunk buffer before possible content oversize
2019-03-04 17:16:07 +00:00
}
2019-03-10 14:36:34 +00:00
if ( strlen ( mqtt_data ) > = CHUNKED_BUFFER_SIZE ) { // Content is oversize
_WSContentSend ( mqtt_data ) ; // Send content
2019-03-04 17:16:07 +00:00
}
}
2019-03-19 16:31:43 +00:00
void WSContentSend_P ( const char * formatP , . . . ) // Content send snprintf_P char data
{
// This uses char strings. Be aware of sending %% if % is needed
va_list arg ;
va_start ( arg , formatP ) ;
2019-11-25 16:58:37 +00:00
int len = vsnprintf_P ( mqtt_data , sizeof ( mqtt_data ) , formatP , arg ) ;
2019-03-19 16:31:43 +00:00
va_end ( arg ) ;
2019-11-25 16:58:37 +00:00
# ifdef DEBUG_TASMOTA_CORE
if ( len > ( sizeof ( mqtt_data ) - 1 ) ) {
mqtt_data [ 33 ] = ' \0 ' ;
DEBUG_CORE_LOG ( PSTR ( " ERROR: WSContentSend_P size %d > mqtt_data size %d. Start of data [%s...] " ) , len , sizeof ( mqtt_data ) , mqtt_data ) ;
}
# endif
2019-03-19 16:31:43 +00:00
_WSContentSendBuffer ( ) ;
}
void WSContentSend_PD ( const char * formatP , . . . ) // Content send snprintf_P char data checked for decimal separator
{
// This uses char strings. Be aware of sending %% if % is needed
va_list arg ;
va_start ( arg , formatP ) ;
int len = vsnprintf_P ( mqtt_data , sizeof ( mqtt_data ) , formatP , arg ) ;
va_end ( arg ) ;
2019-11-25 16:58:37 +00:00
# ifdef DEBUG_TASMOTA_CORE
if ( len > ( sizeof ( mqtt_data ) - 1 ) ) {
mqtt_data [ 33 ] = ' \0 ' ;
DEBUG_CORE_LOG ( PSTR ( " ERROR: WSContentSend_PD size %d > mqtt_data size %d. Start of data [%s...] " ) , len , sizeof ( mqtt_data ) , mqtt_data ) ;
}
# endif
2019-03-19 16:31:43 +00:00
if ( D_DECIMAL_SEPARATOR [ 0 ] ! = ' . ' ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2019-03-19 16:31:43 +00:00
if ( ' . ' = = mqtt_data [ i ] ) {
mqtt_data [ i ] = D_DECIMAL_SEPARATOR [ 0 ] ;
}
}
}
_WSContentSendBuffer ( ) ;
}
2019-03-10 14:36:34 +00:00
void WSContentStart_P ( const char * title , bool auth )
2019-03-04 17:16:07 +00:00
{
2020-04-15 08:58:38 +01:00
if ( auth & & strlen ( SettingsText ( SET_WEBPWD ) ) & & ! Webserver - > authenticate ( WEB_USERNAME , SettingsText ( SET_WEBPWD ) ) ) {
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 ) {
2019-03-16 15:23:41 +00:00
char ctitle [ strlen_P ( title ) + 1 ] ;
strcpy_P ( ctitle , title ) ; // Get title from flash to RAM
2020-04-10 17:24:08 +01:00
WSContentSend_P ( HTTP_HEADER1 , SettingsText ( SET_FRIENDLYNAME1 ) , ctitle ) ;
2019-03-16 15:23:41 +00:00
}
2019-03-04 17:16:07 +00:00
}
2018-10-29 11:21:27 +00:00
2019-03-10 14:36:34 +00:00
void WSContentStart_P ( const char * title )
2019-03-04 17:16:07 +00:00
{
2019-03-10 14:36:34 +00:00
WSContentStart_P ( title , true ) ;
2019-03-04 17:16:07 +00:00
}
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
void WSContentSendStyle_P ( const char * formatP , . . . )
2019-03-04 17:16:07 +00:00
{
2019-02-21 16:49:11 +00:00
if ( WifiIsInManagerMode ( ) ) {
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
}
}
2019-06-02 15:44:02 +01:00
WSContentSend_P ( HTTP_HEAD_LAST_SCRIPT ) ;
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 ) ) ;
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 ) ;
2019-11-25 16:58:37 +00:00
int len = vsnprintf_P ( mqtt_data , sizeof ( mqtt_data ) , 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-11-25 16:58:37 +00:00
# ifdef DEBUG_TASMOTA_CORE
if ( len > ( sizeof ( mqtt_data ) - 1 ) ) {
mqtt_data [ 33 ] = ' \0 ' ;
DEBUG_CORE_LOG ( PSTR ( " ERROR: WSContentSendStyle_P size %d > mqtt_data size %d. Start of data [%s...] " ) , len , sizeof ( mqtt_data ) , mqtt_data ) ;
}
# endif
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
_WSContentSendBuffer ( ) ;
}
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
2019-04-09 12:56:19 +01: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
2019-11-02 04:33:40 +00:00
WebColor ( COL_TITLE ) ,
2019-12-16 14:13:57 +00:00
ModuleName ( ) . c_str ( ) , SettingsText ( SET_FRIENDLYNAME1 ) ) ;
2019-11-03 12:51:22 +00:00
if ( Settings . flag3 . gui_hostname_ip ) { // SetOption53 - Show hostanme and IP address in GUI main menu
2019-03-14 15:50:56 +00:00
bool lip = ( static_cast < uint32_t > ( WiFi . localIP ( ) ) ! = 0 ) ;
bool sip = ( static_cast < uint32_t > ( WiFi . softAPIP ( ) ) ! = 0 ) ;
2019-11-03 14:37:33 +00:00
WSContentSend_P ( PSTR ( " <h4>%s%s (%s%s%s)</h4> " ) , // tasmota.local (192.168.2.12, 192.168.4.1)
2019-03-14 15:50:56 +00:00
my_hostname ,
2019-08-17 16:13:09 +01:00
( Wifi . mdns_begun ) ? " .local " : " " ,
2019-03-14 15:50:56 +00:00
( lip ) ? WiFi . localIP ( ) . toString ( ) . c_str ( ) : " " ,
2019-03-16 15:23:41 +00:00
( lip & & sip ) ? " , " : " " ,
2019-03-14 15:50:56 +00:00
( sip ) ? WiFi . softAPIP ( ) . toString ( ) . c_str ( ) : " " ) ;
}
WSContentSend_P ( PSTR ( " </div> " ) ) ;
2019-03-04 17:16:07 +00:00
}
2018-10-10 21:21:44 +01:00
2019-03-10 14:36:34 +00:00
void WSContentSendStyle ( void )
2019-03-04 17:16:07 +00:00
{
2019-03-26 17:26:50 +00:00
WSContentSendStyle_P ( nullptr ) ;
2018-10-10 21:21:44 +01:00
}
2019-07-27 17:37:56 +01:00
void WSContentButton ( uint32_t title_index )
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
if ( title_index < = BUTTON_RESET_CONFIGURATION ) {
2019-07-06 11:53:07 +01:00
char confirm [ 100 ] ;
2019-03-11 09:38:41 +00:00
WSContentSend_P ( PSTR ( " <p><form action='%s' method='get' onsubmit='return confirm( \" %s \" );'><button name='%s' class='button bred'>%s</button></form></p> " ) ,
GetTextIndexed ( action , sizeof ( action ) , title_index , kButtonAction ) ,
GetTextIndexed ( confirm , sizeof ( confirm ) , title_index , kButtonConfirm ) ,
( ! title_index ) ? " rst " : " non " ,
GetTextIndexed ( title , sizeof ( title ) , title_index , kButtonTitle ) ) ;
} else {
WSContentSend_P ( PSTR ( " <p><form action='%s' method='get'><button>%s</button></form></p> " ) ,
GetTextIndexed ( action , sizeof ( action ) , title_index , kButtonAction ) ,
GetTextIndexed ( title , sizeof ( title ) , title_index , kButtonTitle ) ) ;
}
}
2019-07-27 17:37:56 +01:00
void WSContentSpaceButton ( uint32_t title_index )
2019-03-11 09:38:41 +00:00
{
WSContentSend_P ( PSTR ( " <div></div> " ) ) ; // 5px padding
WSContentButton ( title_index ) ;
}
2020-03-17 15:29:59 +00:00
void WSContentSend_THD ( const char * types , float f_temperature , float f_humidity )
{
char parameter [ FLOATSZ ] ;
dtostrfd ( f_temperature , Settings . flag2 . temperature_resolution , parameter ) ;
WSContentSend_PD ( HTTP_SNS_TEMP , types , parameter , TempUnit ( ) ) ;
dtostrfd ( f_humidity , Settings . flag2 . humidity_resolution , parameter ) ;
WSContentSend_PD ( HTTP_SNS_HUM , types , parameter ) ;
dtostrfd ( CalcTempHumToDew ( f_temperature , f_humidity ) , Settings . flag2 . temperature_resolution , parameter ) ;
WSContentSend_PD ( HTTP_SNS_DEW , types , parameter , TempUnit ( ) ) ;
}
2019-03-07 17:18:30 +00:00
void WSContentEnd ( void )
2019-03-16 15:23:41 +00:00
{
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
}
void WSContentStop ( void )
2018-10-10 21:21:44 +01:00
{
2019-03-04 17:16:07 +00:00
if ( WifiIsInManagerMode ( ) ) {
if ( WifiConfigCounter ( ) ) {
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_COUNTER ) ;
2019-03-04 17:16:07 +00:00
}
}
WSContentSend_P ( HTTP_END , my_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
2019-07-27 17:37:56 +01:00
void WebRestart ( uint32_t type )
2018-10-12 10:42:52 +01:00
{
// type 0 = restart
// type 1 = restart after config change
// type 2 = restart after config change with possible ip address change too
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_RESTART ) ;
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
2019-03-10 14:36:34 +00:00
WSContentStart_P ( ( type ) ? S_SAVE_CONFIGURATION : S_RESTART , ! reset_only ) ;
WSContentSend_P ( HTTP_SCRIPT_RELOAD ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2018-10-12 10:42:52 +01:00
if ( type ) {
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <div style='text-align:center;'><b> " D_CONFIGURATION_SAVED " </b><br> " ) ) ;
2018-10-12 10:42:52 +01:00
if ( 2 = = type ) {
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <br> " D_TRYING_TO_CONNECT " <br> " ) ) ;
2018-10-12 10:42:52 +01:00
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " </div> " ) ) ;
2018-10-12 10:42:52 +01:00
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_MSG_RSTRT ) ;
2019-08-15 12:50:28 +01:00
if ( HTTP_MANAGER = = Web . state | | reset_only ) {
Web . state = HTTP_ADMIN ;
2018-10-12 10:42:52 +01:00
} else {
2019-03-11 09:38:41 +00:00
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
ShowWebSource ( SRC_WEBGUI ) ;
restart_flag = 2 ;
}
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
{
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_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
}
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
" a " , // a - Unique HTML id
" #fff " , " #ff0 " , // White to Yellow
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
{
if ( CaptivePortal ( ) ) { return ; } // If captive portal redirect instead of displaying the page.
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " 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
2020-04-15 08:58:38 +01:00
if ( strlen ( SettingsText ( SET_WEBPWD ) ) & & ! ( Webserver - > hasArg ( " USER1 " ) ) & & ! ( Webserver - > hasArg ( " PASS1 " ) ) & & HTTP_MANAGER_RESET_ONLY ! = Web . state ) {
2018-10-10 21:21:44 +01:00
HandleWifiLogin ( ) ;
} else {
2020-04-15 08:58:38 +01:00
if ( ! strlen ( SettingsText ( SET_WEBPWD ) ) | | ( ( ( Webserver - > arg ( " USER1 " ) = = WEB_USERNAME ) & & ( Webserver - > arg ( " 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 ;
}
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_MAIN_MENU ) ;
2019-12-24 16:10:50 +00:00
char stemp [ 33 ] ;
2019-03-01 17:25:46 +00:00
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_MAIN_MENU ) ;
2019-09-24 07:25:32 +01:00
# ifdef USE_SCRIPT_WEB_DISPLAY
WSContentSend_P ( HTTP_SCRIPT_ROOT , Settings . web_refresh , Settings . web_refresh ) ;
# else
2019-03-04 17:16:07 +00: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
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " <div id='l1' name='l1'></div> " ) ) ;
2019-03-01 17:25:46 +00:00
if ( devices_present ) {
2019-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
2019-03-01 17:25:46 +00:00
if ( light_type ) {
2019-11-22 16:24:56 +00:00
uint8_t light_subtype = light_type & 7 ;
2019-11-03 12:51:22 +00:00
if ( ! Settings . flag3 . pwm_multi_channels ) { // SetOption68 0 - Enable multi-channels PWM instead of Color PWM
2020-01-16 13:22:39 +00:00
bool split_white = ( ( LST_RGBW < = light_subtype ) & & ( devices_present > 1 ) ) ; // Only on RGBW or RGBCW and SetOption37 128
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
" b " , // b - Unique HTML id
" #800 " , " #f00 5%,#ff0 20%,#0f0 35%,#0ff 50%,#00f 65%,#f0f 80%,#f00 95%,#800 " , // Hue colors
2 , // sl2 - Unique range HTML id - Used as source for Saturation end color
1 , 359 , // Range valid Hue
hue ,
' h ' , 0 ) ; // h0 - Value id
uint8_t dcolor = changeUIntScale ( Settings . light_dimmer , 0 , 100 , 0 , 255 ) ;
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 ;
LightHsToRgb ( hue , 255 , & red , & green , & blue ) ;
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " #%02X%02X%02X " ) , red , green , blue ) ; // Saturation end color
WSContentSend_P ( HTTP_MSG_SLIDER_GRADIENT , // Saturation
" 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%%))';
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
" c " , // c - Unique HTML id
" #000 " , " #fff " , // Black to White
4 , // sl4 - Unique range HTML id - Used as source for Saturation begin color
2019-11-29 12:11:35 +00:00
Settings . flag3 . slider_dimmer_stay_on , 100 , // Range 0/1 to 100%
2019-11-25 14:20:44 +00:00
Settings . light_dimmer ,
' 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
" f " , // f - Unique HTML id
" #000 " , " #fff " , // Black to White
5 , // sl5 - Unique range HTML id - Not used
Settings . flag3 . slider_dimmer_stay_on , 100 , // Range 0/1 to 100%
LightGetDimmer ( 2 ) ,
' w ' , 0 ) ; // w0 - Value id is related to lc("w0", value) and WebGetArg("w0", tmp, sizeof(tmp));
}
2019-11-03 12:51:22 +00: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
2019-11-25 14:20:44 +00:00
" #000 " , " #fff " , // Black to White
i + 1 , // sl1 to sl5 - Unique range HTML id - Not used
1 , 100 , // Range 1 to 100%
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
}
} // 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-09-29 17:00:01 +01:00
# ifdef USE_SHUTTER
2019-11-03 12:51:22 +00:00
if ( Settings . flag3 . shutter_mode ) { // SetOption80 - Enable shutter support
2019-09-29 17:00:01 +01:00
for ( uint32_t i = 0 ; i < shutters_present ; i + + ) {
2019-11-22 16:24:56 +00:00
WSContentSend_P ( HTTP_MSG_SLIDER_SHUTTER , Settings . shutter_position [ i ] , i + 1 ) ;
2019-09-29 17:00:01 +01:00
}
}
# endif // USE_SHUTTER
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 ,
( strlen ( SettingsText ( SET_BUTTON1 ) ) ) ? SettingsText ( SET_BUTTON1 ) : D_BUTTON_TOGGLE ,
" " ) ;
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
2019-06-30 15:44:36 +01:00
for ( uint32_t idx = 1 ; idx < = devices_present ; idx + + ) {
2019-12-24 16:10:50 +00:00
bool set_button = ( ( idx < = MAX_BUTTON_TEXT ) & & strlen ( SettingsText ( SET_BUTTON1 + 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 ) ) {
WSContentSend_P ( HTTP_DEVICE_CONTROL , 100 / devices_present , idx ,
2020-03-31 17:04:32 +01:00
( set_button ) ? SettingsText ( SET_BUTTON1 + idx - 1 ) : ( ( Settings . shutter_options [ abs ( ShutterWebButton ) - 1 ] & 2 ) /* is locked */ ? " - " : ( ( Settings . shutter_options [ abs ( ShutterWebButton ) - 1 ] & 8 ) /* invert web buttons */ ? ( ( ShutterWebButton > 0 ) ? " ▼ " : " ▲ " ) : ( ( ShutterWebButton > 0 ) ? " ▲ " : " ▼ " ) ) ) ,
2020-01-09 08:17:39 +00:00
" " ) ;
continue ;
2019-12-10 11:33:45 +00:00
}
# endif // USE_SHUTTER
2019-03-01 17:25:46 +00:00
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , idx ) ;
2019-12-24 16:10:50 +00:00
WSContentSend_P ( HTTP_DEVICE_CONTROL , 100 / devices_present , idx ,
( set_button ) ? SettingsText ( SET_BUTTON1 + idx - 1 ) : ( devices_present < 5 ) ? D_BUTTON_TOGGLE : " " ,
( set_button ) ? " " : ( devices_present > 1 ) ? stemp : " " ) ;
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
}
2019-10-15 14:37:22 +01:00
# ifdef USE_SONOFF_RF
2019-03-01 17:25:46 +00:00
if ( SONOFF_BRIDGE = = my_module_type ) {
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_TABLE100 ) ;
WSContentSend_P ( PSTR ( " <tr> " ) ) ;
2019-07-27 17:37:56 +01:00
uint32_t idx = 0 ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < 4 ; i + + ) {
2019-03-10 14:36:34 +00:00
if ( idx > 0 ) { WSContentSend_P ( PSTR ( " </tr><tr> " ) ) ; }
2019-06-30 15:44:36 +01:00
for ( uint32_t j = 0 ; j < 4 ; j + + ) {
2019-03-01 17:25:46 +00:00
idx + + ;
2019-12-24 16:10:50 +00:00
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , idx ) ;
WSContentSend_P ( PSTR ( " <td style='width:25%%'><button onclick='la( \" &k=%d \" );'>%s</button></td> " ) , idx , // &k is related to WebGetArg("k", tmp, sizeof(tmp));
( strlen ( SettingsText ( SET_BUTTON1 + idx - 1 ) ) ) ? SettingsText ( SET_BUTTON1 + idx - 1 ) : stemp ) ;
2018-10-10 21:21:44 +01:00
}
}
2019-03-10 14:36:34 +00:00
WSContentSend_P ( PSTR ( " </tr></table> " ) ) ;
2019-03-01 17:25:46 +00:00
}
2019-10-15 14:37:22 +01:00
# endif // USE_SONOFF_RF
2019-02-08 13:55:45 +00:00
# ifndef FIRMWARE_MINIMAL
2019-03-01 17:25:46 +00:00
XdrvCall ( FUNC_WEB_ADD_MAIN_BUTTON ) ;
XsnsCall ( 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
WSContentSpaceButton ( BUTTON_FIRMWARE_UPGRADE ) ;
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 ) ;
2019-03-07 17:18:30 +00:00
# endif // Not FIRMWARE_MINIMAL
2019-03-11 09:38:41 +00:00
WSContentButton ( BUTTON_CONSOLE ) ;
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
2019-02-23 17:38:36 +00:00
WebGetArg ( " 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-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 ) ) ;
2020-01-09 08:17:39 +00:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
} 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
2018-10-10 21:21:44 +01:00
}
2020-03-05 17:45:43 +00:00
# ifdef USE_LIGHT
2019-11-25 14:20:44 +00:00
WebGetArg ( " 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 ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2020-01-16 13:22:39 +00:00
WebGetArg ( " w0 " , tmp , sizeof ( tmp ) ) ; // 0 - 100 White value
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_WHITE " %s " ) , tmp ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2020-03-05 13:53:51 +00:00
uint32_t light_device = LightDevice ( ) ; // Channel number offset
2019-10-15 15:41:53 +01:00
uint32_t pwm_channels = ( light_type & 7 ) > LST_MAX ? LST_MAX : ( 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 ) ;
2019-10-15 15:41:53 +01:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
}
2019-11-25 14:20:44 +00:00
WebGetArg ( " 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 ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2019-11-25 14:20:44 +00:00
WebGetArg ( " 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 ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2019-11-25 14:20:44 +00:00
WebGetArg ( " 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 ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2020-03-05 17:45:43 +00:00
# endif // USE_LIGHT
2019-09-29 17:00:01 +01:00
# ifdef USE_SHUTTER
2019-10-01 09:49:42 +01:00
for ( uint32_t j = 1 ; j < = shutters_present ; j + + ) {
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
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " ShutterPosition%d %s " ) , j , tmp ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
}
# endif // USE_SHUTTER
2019-10-15 14:37:22 +01:00
# ifdef USE_SONOFF_RF
2019-02-23 17:38:36 +00:00
WebGetArg ( " k " , tmp , sizeof ( tmp ) ) ; // 1 - 16 Pre defined RF keys
2018-10-10 21:21:44 +01:00
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_RFKEY " %s " ) , tmp ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2019-10-15 14:37:22 +01:00
# endif // USE_SONOFF_RF
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_HTML ) ;
2019-03-19 16:31:43 +00:00
WSContentSend_P ( PSTR ( " {t} " ) ) ;
XsnsCall ( FUNC_WEB_SENSOR ) ;
2019-08-31 09:10:16 +01:00
# ifdef USE_SCRIPT_WEB_DISPLAY
XdrvCall ( FUNC_WEB_SENSOR ) ;
# endif
2019-09-04 19:58:17 +01:00
2019-03-19 16:31:43 +00:00
WSContentSend_P ( PSTR ( " </table> " ) ) ;
2018-10-10 21:21:44 +01:00
if ( devices_present ) {
2019-03-16 15:23:41 +00:00
WSContentSend_P ( PSTR ( " {t}<tr> " ) ) ;
2019-07-27 17:37:56 +01:00
uint32_t fsize = ( devices_present < 5 ) ? 70 - ( devices_present * 8 ) : 32 ;
2019-07-14 21:08:19 +01:00
# ifdef USE_SONOFF_IFAN
2019-07-14 14:23:02 +01:00
if ( IsModuleIfan ( ) ) {
2019-03-16 15:23:41 +00:00
WSContentSend_P ( HTTP_DEVICE_STATE , 36 , ( bitRead ( power , 0 ) ) ? " bold " : " normal " , 54 , GetStateText ( bitRead ( 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 ) ;
2019-03-16 15:23:41 +00:00
WSContentSend_P ( HTTP_DEVICE_STATE , 64 , ( fanspeed ) ? " bold " : " 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
2019-06-30 15:44:36 +01:00
for ( uint32_t idx = 1 ; idx < = devices_present ; idx + + ) {
2018-10-10 21:21:44 +01:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %d " ) , bitRead ( power , idx - 1 ) ) ;
2019-03-16 15:23:41 +00:00
WSContentSend_P ( HTTP_DEVICE_STATE , 100 / devices_present , ( bitRead ( power , idx - 1 ) ) ? " bold " : " normal " , fsize , ( devices_present < 5 ) ? GetStateText ( bitRead ( power , idx - 1 ) ) : svalue ) ;
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-16 15:23:41 +00:00
WSContentSend_P ( PSTR ( " </tr></table> " ) ) ;
2018-10-10 21:21:44 +01:00
}
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 ;
if ( Settings . flag3 . shutter_mode ) { // SetOption80 - Enable shutter support
for ( uint32_t i = 0 ; i < MAX_SHUTTERS ; i + + ) {
if ( Settings . shutter_startrelay [ i ] & & ( ( Settings . shutter_startrelay [ i ] = = idx ) | | ( Settings . shutter_startrelay [ i ] = = ( idx - 1 ) ) ) ) {
ShutterWebButton = ( Settings . shutter_startrelay [ i ] = = idx ) ? ( i + 1 ) : ( - 1 - i ) ;
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 ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURATION ) ;
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_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
XdrvCall ( FUNC_WEB_ADD_BUTTON ) ;
2018-10-21 15:30:05 +01:00
XsnsCall ( 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
}
/*-------------------------------------------------------------------------------------------*/
2019-02-17 10:32:53 +00:00
void HandleTemplateConfiguration ( void )
{
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " 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
2019-02-23 17:38:36 +00:00
WebGetArg ( " 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 ) ;
uint32_t module_save = Settings . module ;
2019-02-17 10:32:53 +00:00
Settings . module = module ;
myio cmodule ;
ModuleGpios ( & cmodule ) ;
gpio_flag flag = ModuleFlag ( ) ;
Settings . module = module_save ;
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_PLAIN ) ;
WSContentSend_P ( PSTR ( " %s}1 " ) , AnyModuleName ( module ) . c_str ( ) ) ; // NAME: Generic
2020-04-25 14:34:18 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( cmodule . io ) ; i + + ) { // 17,148,29,149,7,255,255,255,138,255,139,255,255
2020-04-12 17:17:35 +01:00
if ( ! FlashPin ( i ) ) {
2019-03-16 15:23:41 +00:00
WSContentSend_P ( PSTR ( " %s%d " ) , ( i > 0 ) ? " , " : " " , cmodule . io [ i ] ) ;
2019-02-17 10:32:53 +00:00
}
}
2019-03-16 15:23:41 +00:00
WSContentSend_P ( PSTR ( " }1%d}1%d " ) , flag , Settings . user_template_base ) ; // FLAG: 1 BASE: 17
WSContentEnd ( ) ;
2019-02-17 10:32:53 +00:00
return ;
}
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_TEMPLATE ) ;
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_CONFIGURE_TEMPLATE ) ;
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-04-29 16:44:03 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( kGpioNiceList ) ; i + + ) { // GPIO: }2'0'>None (0)}3}2'17'>Button1 (17)}3...
2020-04-25 14:34:18 +01:00
if ( 1 = = i ) {
2020-04-29 16:44:03 +01:00
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , AGPIO ( GPIO_USER ) , D_SENSOR_USER , AGPIO ( GPIO_USER ) ) ; // }2'255'>User (255)}3
2020-04-25 14:34:18 +01:00
}
2020-04-29 16:44:03 +01:00
# ifdef ESP8266
uint32_t midx = pgm_read_byte ( kGpioNiceList + i ) ;
uint32_t ridx = midx ;
# else // ESP32
2020-05-01 15:47:41 +01:00
uint32_t ridx = pgm_read_word ( kGpioNiceList + i ) & 0xFFE0 ;
2020-04-30 17:47:34 +01:00
uint32_t midx = ridx > > 5 ;
2020-04-29 16:44:03 +01:00
# endif // ESP8266 - ESP32
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , ridx , GetTextIndexed ( stemp , sizeof ( stemp ) , midx , kSensorNames ) , ridx ) ;
2020-04-25 14:34:18 +01:00
}
2020-05-01 15:47:41 +01:00
WSContentSend_P ( PSTR ( " \" ; " ) ) ;
# ifdef ESP32
WSContentSend_P ( PSTR ( " hs=[ " ) ) ;
bool first_done = false ;
2020-05-02 16:53:57 +01:00
/*
2020-05-01 15:47:41 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( kGpioNiceList ) ; i + + ) {
uint32_t midx = pgm_read_word ( kGpioNiceList + i ) & 0x001F ;
if ( first_done ) { WSContentSend_P ( PSTR ( " , " ) ) ; }
WSContentSend_P ( PSTR ( " %d " ) , midx ) ;
first_done = true ;
}
2020-05-02 16:53:57 +01:00
*/
uint32_t j = 0 ;
for ( uint32_t i = 0 ; i < GPIO_SENSOR_END ; i + + ) {
uint32_t midx = pgm_read_word ( kGpioNiceList + j ) ;
if ( ( midx > > 5 ) ! = i ) {
midx = 0 ;
} else {
midx & = 0x001F ;
j + + ;
}
if ( first_done ) { WSContentSend_P ( PSTR ( " , " ) ) ; }
WSContentSend_P ( PSTR ( " %d " ) , midx ) ;
first_done = true ;
}
2020-05-01 15:47:41 +01:00
WSContentSend_P ( PSTR ( " ]; " ) ) ;
# endif // ESP32
2020-04-25 14:34:18 +01:00
WSContentSend_P ( HTTP_SCRIPT_TEMPLATE2 ) ;
2020-05-01 15:47:41 +01:00
# ifdef ESP8266
WSContentSend_P ( PSTR ( " os= \" " ) ) ;
2020-04-25 14:34:18 +01:00
for ( uint32_t i = 0 ; i < ADC0_END ; i + + ) { // FLAG: }2'0'>None (0)}3}2'17'>Analog (17)}3...
if ( 1 = = i ) {
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , ADC0_USER , D_SENSOR_USER , ADC0_USER ) ; // }2'15'>User (15)}3
}
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , i , GetTextIndexed ( stemp , sizeof ( stemp ) , i , kAdc0Names ) , i ) ;
}
WSContentSend_P ( HTTP_SCRIPT_TEMPLATE3 ) ;
2020-05-01 15:47:41 +01:00
# endif
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 ) ;
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , midx , AnyModuleName ( midx ) . c_str ( ) , midx + 1 ) ;
}
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 + + ) {
if ( ! FlashPin ( i ) ) {
2020-05-01 15:47:41 +01:00
# ifdef ESP8266
2019-06-02 15:44:02 +01:00
WSContentSend_P ( PSTR ( " <tr><td><b><font color='#%06x'> " D_GPIO " %d</font></b></td><td%s><select id='g%d'></select></td></tr> " ) ,
( ( 9 = = i ) | | ( 10 = = i ) ) ? WebColor ( COL_TEXT_WARNING ) : WebColor ( COL_TEXT ) , i , ( 0 = = i ) ? " style='width:200px' " : " " , i ) ;
2020-05-01 15:47:41 +01:00
# else // ESP32
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> " ) ,
( ( 9 = = i ) | | ( 10 = = i ) ) ? WebColor ( COL_TEXT_WARNING ) : WebColor ( COL_TEXT ) , i , ( 0 = = i ) ? " style='width:150px' " : " " , i , i ) ;
WSContentSend_P ( PSTR ( " <td style='width:50px'><select id='h%d'></select></td></tr> " ) , i ) ;
# endif // ESP8266
2019-02-17 10:32:53 +00:00
}
}
2020-04-12 17:17:35 +01:00
# ifdef ESP8266
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <tr><td><b><font color='#%06x'> " D_ADC " 0</font></b></td><td><select id='g17'></select></td></tr> " ) , WebColor ( COL_TEXT ) ) ;
2020-04-12 17:17:35 +01:00
# endif
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
# ifdef ESP8266
2019-05-13 14:56:01 +01:00
if ( flag . data > ADC0_USER ) {
2020-05-01 15:47:41 +01:00
# else // ESP32
if ( flag . data ) {
# endif // ESP32
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
}
void TemplateSaveSettings ( void )
{
2020-03-29 16:41:31 +01:00
char tmp [ TOPSZ ] ; // WebGetArg NAME and GPIO/BASE/FLAG byte value
2019-02-24 14:32:54 +00:00
char webindex [ 5 ] ; // WebGetArg name
2020-04-12 17:17:35 +01:00
char svalue [ 300 ] ; // Template command string
2019-02-17 10:32:53 +00:00
2019-02-24 14:32:54 +00:00
WebGetArg ( " s1 " , tmp , sizeof ( tmp ) ) ; // NAME
2019-02-17 10:32:53 +00:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_TEMPLATE " { \" " D_JSON_NAME " \" : \" %s \" , \" " D_JSON_GPIO " \" :[ " ) , tmp ) ;
2019-07-27 17:37:56 +01:00
uint32_t j = 0 ;
2020-04-25 10:37:36 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( Settings . user_template . gp . io ) ; i + + ) {
2019-02-17 10:32:53 +00:00
if ( 6 = = i ) { j = 9 ; }
if ( 8 = = i ) { j = 12 ; }
2019-02-23 17:38:36 +00:00
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " g%d " ) , j ) ;
2019-02-24 14:32:54 +00:00
WebGetArg ( webindex , tmp , sizeof ( tmp ) ) ; // GPIO
2020-04-29 16:44:03 +01:00
uint32_t gpio = atoi ( tmp ) ;
2020-05-01 15:47:41 +01:00
# ifdef ESP32
char tmp2 [ 8 ] ; // WebGetArg numbers only
char webindex2 [ 5 ] ; // WebGetArg name
snprintf_P ( webindex2 , sizeof ( webindex2 ) , PSTR ( " h%d " ) , j ) ;
WebGetArg ( webindex2 , tmp2 , sizeof ( tmp2 ) ) ;
uint32_t value2 = ( ! strlen ( tmp2 ) ) ? 0 : atoi ( tmp2 ) - 1 ;
gpio + = value2 ;
# endif // ESP32
2019-02-17 10:32:53 +00:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s%s%d " ) , svalue , ( i > 0 ) ? " , " : " " , gpio ) ;
j + + ;
}
2020-05-01 15:47:41 +01:00
# ifdef ESP8266
2020-04-12 17:17:35 +01:00
WebGetArg ( " g " STR ( ADC0_PIN ) , tmp , sizeof ( tmp ) ) ; // FLAG - ADC0
2019-07-27 17:37:56 +01:00
uint32_t flag = atoi ( tmp ) ;
2020-05-01 15:47:41 +01:00
# else // ESP32
uint32_t flag = 0 ;
# endif // ESP32
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 ) ;
2020-04-15 08:58:38 +01:00
uint32_t state = Webserver - > hasArg ( webindex ) < < i + 4 ; // FLAG
2019-02-17 10:32:53 +00:00
flag + = state ;
}
2019-02-24 14:32:54 +00:00
WebGetArg ( " 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
2019-02-24 14:32:54 +00:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s], \" " D_JSON_FLAG " \" :%d, \" " D_JSON_BASE " \" :%d} " ) , svalue , flag , base ) ;
2019-02-17 10:32:53 +00:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandleModuleConfiguration ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
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
ModuleSaveSettings ( ) ;
2018-10-12 10:42:52 +01:00
WebRestart ( 1 ) ;
2018-10-10 21:21:44 +01:00
return ;
}
2020-04-25 12:30:00 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_MODULE ) ;
2019-07-23 22:19:27 +01:00
char stemp [ 30 ] ; // Sensor name
2019-07-27 17:37:56 +01:00
uint32_t midx ;
2018-12-29 16:19:13 +00:00
myio cmodule ;
ModuleGpios ( & cmodule ) ;
2018-11-10 14:10:58 +00:00
2020-04-25 12:30:00 +01:00
WSContentStart_P ( S_CONFIGURE_MODULE ) ;
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-04-25 12:30:00 +01:00
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , midx , AnyModuleName ( midx ) . c_str ( ) , vidx ) ;
2018-10-10 21:21:44 +01:00
}
2020-04-25 12:30:00 +01:00
WSContentSend_P ( PSTR ( " \" ;sk(%d,99);os= \" " ) , Settings . module ) ;
2020-04-29 16:44:03 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( kGpioNiceList ) ; i + + ) {
# ifdef ESP8266
midx = pgm_read_byte ( kGpioNiceList + i ) ;
uint32_t ridx = midx ;
# else // ESP32
2020-04-30 17:47:34 +01:00
uint32_t ridx = pgm_read_word ( kGpioNiceList + i ) & 0xFFE0 ;
midx = ridx > > 5 ;
2020-05-01 10:48:12 +01:00
# endif // ESP8266 - ESP32
2020-05-01 15:47:41 +01:00
if ( ! GetUsedInModule ( midx , cmodule . io ) ) {
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , ridx , GetTextIndexed ( stemp , sizeof ( stemp ) , midx , kSensorNames ) , ridx ) ;
}
2019-05-13 14:56:01 +01:00
}
2020-04-25 12:30:00 +01:00
WSContentSend_P ( PSTR ( " \" ; " ) ) ;
2020-04-30 17:47:34 +01:00
# ifdef ESP32
WSContentSend_P ( PSTR ( " hs=[ " ) ) ;
bool first_done = false ;
2020-05-02 16:53:57 +01:00
/*
2020-04-30 17:47:34 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( kGpioNiceList ) ; i + + ) {
midx = pgm_read_word ( kGpioNiceList + i ) & 0x001F ;
if ( first_done ) { WSContentSend_P ( PSTR ( " , " ) ) ; }
WSContentSend_P ( PSTR ( " %d " ) , midx ) ;
first_done = true ;
}
2020-05-02 16:53:57 +01:00
*/
uint32_t j = 0 ;
for ( uint32_t i = 0 ; i < GPIO_SENSOR_END ; i + + ) {
midx = pgm_read_word ( kGpioNiceList + j ) ;
if ( ( midx > > 5 ) ! = i ) {
midx = 0 ;
} else {
midx & = 0x001F ;
j + + ;
}
if ( first_done ) { WSContentSend_P ( PSTR ( " , " ) ) ; }
WSContentSend_P ( PSTR ( " %d " ) , midx ) ;
first_done = true ;
}
2020-04-30 17:47:34 +01:00
WSContentSend_P ( PSTR ( " ]; " ) ) ;
# endif // ESP32
2020-04-25 10:37:36 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( cmodule . io ) ; i + + ) {
2019-02-11 18:21:49 +00:00
if ( ValidGPIO ( i , cmodule . io [ i ] ) ) {
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " sk(%d,%d); " ) , my_module . io [ i ] , i ) ; // g0 - g16
2018-10-10 21:21:44 +01:00
}
}
2020-05-01 10:48:12 +01:00
# ifdef ESP8266
2020-04-25 12:30:00 +01:00
# ifndef USE_ADC_VCC
WSContentSend_P ( PSTR ( " os= \" " ) ) ;
for ( uint32_t j = 0 ; j < ADC0_END ; j + + ) {
WSContentSend_P ( HTTP_MODULE_TEMPLATE_REPLACE , j , GetTextIndexed ( stemp , sizeof ( stemp ) , j , kAdc0Names ) , j ) ;
}
WSContentSend_P ( PSTR ( " \" ;sk(%d, " STR ( ADC0_PIN ) " ); " ) , Settings . my_adc0 ) ;
# endif // USE_ADC_VCC
2020-05-01 10:48:12 +01:00
# endif // ESP8266 - ESP32
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 ( ) ) ;
2020-04-25 10:37:36 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( cmodule . io ) ; i + + ) {
2019-02-11 18:21:49 +00:00
if ( ValidGPIO ( i , cmodule . io [ i ] ) ) {
2020-04-18 17:10:41 +01:00
snprintf_P ( stemp , 3 , PINS_WEMOS + i * 2 ) ;
2020-04-20 09:40:54 +01:00
# ifdef ESP8266
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
char sesp8285 [ 40 ] ;
2019-04-09 12:56:19 +01:00
snprintf_P ( sesp8285 , sizeof ( sesp8285 ) , PSTR ( " <font color='#%06x'>ESP8285</font> " ) , WebColor ( COL_TEXT_WARNING ) ) ;
2019-06-02 15:44:02 +01:00
WSContentSend_P ( PSTR ( " <tr><td style='width:190px'>%s <b> " D_GPIO " %d</b> %s</td><td style='width:176px'><select id='g%d'></select></td></tr> " ) ,
( WEMOS = = my_module_type ) ? stemp : " " , i , ( 0 = = i ) ? D_SENSOR_BUTTON " 1 " : ( 1 = = i ) ? D_SERIAL_OUT : ( 3 = = i ) ? D_SERIAL_IN : ( ( 9 = = i ) | | ( 10 = = i ) ) ? sesp8285 : ( 12 = = i ) ? D_SENSOR_RELAY " 1 " : ( 13 = = i ) ? D_SENSOR_LED " 1i " : ( 14 = = i ) ? D_SENSOR : " " , i ) ;
2020-04-14 16:21:39 +01:00
# else // ESP32
2020-05-01 15:47:41 +01:00
WSContentSend_P ( PSTR ( " <tr><td style='width:116px'>%s <b> " D_GPIO " %d</b></td><td style='width:150px'><select id='g%d' onchange='ot(%d,this.value)'></select></td> " ) ,
2020-04-30 17:47:34 +01:00
( WEMOS = = my_module_type ) ? stemp : " " , i , i , i ) ;
WSContentSend_P ( PSTR ( " <td style='width:50px'><select id='h%d'></select></td></tr> " ) , i ) ;
2020-04-14 16:21:39 +01:00
# endif // ESP8266
2018-10-10 21:21:44 +01:00
}
}
2020-04-14 16:21:39 +01:00
# ifdef ESP8266
2019-05-13 14:56:01 +01:00
# ifndef USE_ADC_VCC
if ( ValidAdc ( ) ) {
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <tr><td>%s <b> " D_ADC " 0</b></td><td style='width:176px'><select id='g17'></select></td></tr> " ) , ( WEMOS = = my_module_type ) ? " A0 " : " " ) ;
2019-05-13 14:56:01 +01:00
}
# endif // USE_ADC_VCC
2020-04-14 16:21:39 +01:00
# endif // ESP8266
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
}
2018-11-14 13:32:09 +00:00
void ModuleSaveSettings ( void )
2018-10-10 21:21:44 +01:00
{
2019-02-23 17:38:36 +00:00
char tmp [ 8 ] ; // WebGetArg numbers only
char webindex [ 5 ] ; // WebGetArg name
2018-10-10 21:21:44 +01:00
WebGetArg ( " g99 " , tmp , sizeof ( tmp ) ) ;
2019-07-27 17:37:56 +01:00
uint32_t new_module = ( ! strlen ( tmp ) ) ? MODULE : atoi ( tmp ) ;
2018-10-10 21:21:44 +01:00
Settings . last_module = Settings . module ;
Settings . module = new_module ;
2019-02-11 18:21:49 +00:00
SetModuleType ( ) ;
2018-12-29 16:19:13 +00:00
myio cmodule ;
ModuleGpios ( & cmodule ) ;
2018-10-10 21:21:44 +01:00
String gpios = " " ;
2020-04-25 10:37:36 +01:00
for ( uint32_t i = 0 ; i < ARRAY_SIZE ( cmodule . io ) ; i + + ) {
2018-10-10 21:21:44 +01:00
if ( Settings . last_module ! = new_module ) {
2019-02-11 18:21:49 +00:00
Settings . my_gp . io [ i ] = GPIO_NONE ;
2018-10-10 21:21:44 +01:00
} else {
2019-02-11 18:21:49 +00:00
if ( ValidGPIO ( i , cmodule . io [ i ] ) ) {
2019-02-23 17:38:36 +00:00
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " g%d " ) , i ) ;
WebGetArg ( webindex , tmp , sizeof ( tmp ) ) ;
2020-04-29 16:44:03 +01:00
uint32_t value = ( ! strlen ( tmp ) ) ? 0 : atoi ( tmp ) ;
2020-05-01 15:47:41 +01:00
# ifdef ESP32
2020-04-30 17:47:34 +01:00
char tmp2 [ 8 ] ; // WebGetArg numbers only
char webindex2 [ 5 ] ; // WebGetArg name
snprintf_P ( webindex2 , sizeof ( webindex2 ) , PSTR ( " h%d " ) , i ) ;
WebGetArg ( webindex2 , tmp2 , sizeof ( tmp2 ) ) ;
uint32_t value2 = ( ! strlen ( tmp2 ) ) ? 0 : atoi ( tmp2 ) - 1 ;
value + = value2 ;
2020-04-16 15:29:33 +01:00
# endif // ESP8266 - ESP32
2020-05-01 15:47:41 +01:00
Settings . my_gp . io [ i ] = value ;
2020-04-16 15:29:33 +01:00
gpios + = F ( " , " D_GPIO ) ; gpios + = String ( i ) ; gpios + = F ( " " ) ; gpios + = String ( value ) ;
2018-10-10 21:21:44 +01:00
}
}
}
2020-04-16 15:29:33 +01:00
# ifdef ESP8266
2019-05-13 14:56:01 +01:00
# ifndef USE_ADC_VCC
2020-04-12 17:17:35 +01:00
WebGetArg ( " g " STR ( ADC0_PIN ) , tmp , sizeof ( tmp ) ) ;
2019-05-13 14:56:01 +01:00
Settings . my_adc0 = ( ! strlen ( tmp ) ) ? 0 : atoi ( tmp ) ;
gpios + = F ( " , " D_ADC " 0 " ) ; gpios + = String ( Settings . my_adc0 ) ;
# endif // USE_ADC_VCC
2020-04-16 15:29:33 +01:00
# endif // ESP8266
2019-05-13 14:56:01 +01:00
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_MODULE " %s " D_CMND_MODULE " %s " ) , ModuleName ( ) . c_str ( ) , gpios . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2019-05-27 13:09:33 +01:00
const char kUnescapeCode [ ] = " &>< \" \' " ;
const char kEscapeCode [ ] PROGMEM = " &|>|<|"|' " ;
String HtmlEscape ( const String unescaped ) {
char escaped [ 10 ] ;
2019-07-27 17:37:56 +01:00
size_t ulen = unescaped . length ( ) ;
2019-05-27 13:09:33 +01:00
String result = " " ;
for ( size_t i = 0 ; i < ulen ; i + + ) {
char c = unescaped [ i ] ;
char * p = strchr ( kUnescapeCode , c ) ;
if ( p ! = nullptr ) {
result + = GetTextIndexed ( escaped , sizeof ( escaped ) , p - kUnescapeCode , kEscapeCode ) ;
} else {
result + = c ;
}
}
return result ;
2018-10-10 21:21:44 +01:00
}
2019-05-27 14:08:11 +01:00
// Indexed by enum wl_enc_type in file wl_definitions.h starting from -1
const char kEncryptionType [ ] PROGMEM = " ||| " D_WPA_PSK " || " D_WPA2_PSK " | " D_WEP " || " D_NONE " | " D_AUTO ;
2018-11-14 13:32:09 +00:00
void HandleWifiConfiguration ( 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
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_WIFI ) ;
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " save " ) & & HTTP_MANAGER_RESET_ONLY ! = Web . state ) {
2018-10-10 21:21:44 +01:00
WifiSaveSettings ( ) ;
2018-10-12 10:42:52 +01:00
WebRestart ( 2 ) ;
2018-10-10 21:21:44 +01:00
return ;
}
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_CONFIGURE_WIFI , ! WifiIsInManagerMode ( ) ) ;
WSContentSend_P ( HTTP_SCRIPT_WIFI ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2018-10-10 21:21:44 +01:00
2019-08-15 12:50:28 +01:00
if ( HTTP_MANAGER_RESET_ONLY ! = Web . state ) {
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " scan " ) ) {
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 ( ) ;
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_SCAN_DONE ) ) ;
if ( 0 = = n ) {
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_WIFI , S_NO_NETWORKS_FOUND ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( S_NO_NETWORKS_FOUND ) ;
WSContentSend_P ( PSTR ( " . " D_REFRESH_TO_SCAN_AGAIN " . " ) ) ;
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
}
}
}
2019-02-21 16:49:11 +00:00
// remove duplicates ( must be RSSI sorted )
2019-08-15 12:50:28 +01:00
String cssid ;
for ( uint32_t i = 0 ; i < n ; i + + ) {
if ( - 1 = = indices [ i ] ) { continue ; }
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
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < n ; 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 ) ;
2019-08-15 12:50:28 +01:00
int auth = WiFi . encryptionType ( indices [ i ] ) ;
char encryption [ 20 ] ;
2019-12-08 18:42:08 +00:00
WSContentSend_P ( PSTR ( " <div><a href='#p' onclick='c(this)'>%s</a> (%d) <span class='q'>%s %d%% (%d dBm)</span></div> " ) ,
2019-08-15 12:50:28 +01:00
HtmlEscape ( WiFi . SSID ( indices [ i ] ) ) . c_str ( ) ,
WiFi . channel ( indices [ i ] ) ,
GetTextIndexed ( encryption , sizeof ( encryption ) , auth + 1 , kEncryptionType ) ,
2020-02-20 09:07:00 +00:00
quality , rssi
2019-08-15 12:50:28 +01:00
) ;
delay ( 0 ) ;
2019-02-21 16:49:11 +00:00
}
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <br> " ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-02-21 16:49:11 +00:00
} else {
2019-05-31 17:24:56 +01:00
WSContentSend_P ( PSTR ( " <div><a href='/wi?scan='> " D_SCAN_FOR_WIFI_NETWORKS " </a></div><br> " ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-04 17:16:07 +00:00
// As WIFI_HOSTNAME may contain %s-%04d it cannot be part of HTTP_FORM_WIFI where it will exception
2019-12-16 14:13:57 +00:00
WSContentSend_P ( HTTP_FORM_WIFI , SettingsText ( SET_STASSID1 ) , SettingsText ( SET_STASSID2 ) , WIFI_HOSTNAME , WIFI_HOSTNAME , SettingsText ( SET_HOSTNAME ) , SettingsText ( SET_CORS ) ) ;
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
2019-12-26 00:59:42 +00:00
WSContentSpaceButton ( BUTTON_RESTORE ) ;
2019-12-26 01:13:17 +00:00
WSContentButton ( BUTTON_RESET_CONFIGURATION ) ;
2019-03-04 17:16:07 +00:00
# endif // FIRMWARE_MINIMAL
2019-12-26 00:59:42 +00:00
WSContentSpaceButton ( BUTTON_RESTART ) ;
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
}
2018-11-14 13:32:09 +00:00
void WifiSaveSettings ( void )
2018-10-10 21:21:44 +01:00
{
2019-12-22 14:23:52 +00:00
char tmp [ TOPSZ ] ; // Max length is currently 150
2018-10-10 21:21:44 +01:00
WebGetArg ( " h " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_HOSTNAME , ( ! strlen ( tmp ) ) ? WIFI_HOSTNAME : tmp ) ;
if ( strstr ( SettingsText ( SET_HOSTNAME ) , " % " ) ! = nullptr ) {
SettingsUpdateText ( SET_HOSTNAME , WIFI_HOSTNAME ) ;
2018-10-10 21:21:44 +01:00
}
2019-11-29 17:28:25 +00:00
WebGetArg ( " c " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_CORS , ( ! strlen ( tmp ) ) ? CORS_DOMAIN : tmp ) ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " s1 " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_STASSID1 , ( ! strlen ( tmp ) ) ? STA_SSID1 : tmp ) ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " s2 " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_STASSID2 , ( ! strlen ( tmp ) ) ? STA_SSID2 : tmp ) ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " p1 " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_STAPWD1 , ( ! strlen ( tmp ) ) ? " " : ( strlen ( tmp ) < 5 ) ? SettingsText ( SET_STAPWD1 ) : tmp ) ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " p2 " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_STAPWD2 , ( ! strlen ( tmp ) ) ? " " : ( strlen ( tmp ) < 5 ) ? SettingsText ( SET_STAPWD2 ) : tmp ) ;
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID " 1 %s, " D_CMND_SSID " 2 %s, " D_CMND_CORS " %s " ) ,
SettingsText ( SET_HOSTNAME ) , SettingsText ( SET_STASSID1 ) , SettingsText ( SET_STASSID2 ) , SettingsText ( SET_CORS ) ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandleLoggingConfiguration ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_LOGGING ) ;
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " save " ) ) {
2018-10-10 21:21:44 +01:00
LoggingSaveSettings ( ) ;
HandleConfiguration ( ) ;
return ;
}
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_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 + + ) {
2019-11-03 11:33:36 +00:00
if ( ( 2 = = idx ) & & ! Settings . flag . mqtt_enabled ) { continue ; } // SetOption3 - Enable MQTT
2019-10-03 13:45:24 +01:00
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> " ) ,
( i = = llevel ) ? " selected " : " " , i , i ,
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
}
2019-12-16 14:13:57 +00: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
}
2018-11-14 13:32:09 +00:00
void LoggingSaveSettings ( void )
2018-10-10 21:21:44 +01:00
{
2019-12-22 14:23:52 +00:00
char tmp [ TOPSZ ] ; // Max length is currently 33
2018-10-10 21:21:44 +01:00
2019-03-04 17:16:07 +00:00
WebGetArg ( " l0 " , tmp , sizeof ( tmp ) ) ;
2019-06-03 16:05:09 +01:00
SetSeriallog ( ( ! strlen ( tmp ) ) ? SERIAL_LOG_LEVEL : atoi ( tmp ) ) ;
2019-03-04 17:16:07 +00:00
WebGetArg ( " l1 " , tmp , sizeof ( tmp ) ) ;
2018-10-10 21:21:44 +01:00
Settings . weblog_level = ( ! strlen ( tmp ) ) ? WEB_LOG_LEVEL : atoi ( tmp ) ;
2019-03-04 17:16:07 +00:00
WebGetArg ( " l2 " , tmp , sizeof ( tmp ) ) ;
2019-10-04 09:24:21 +01:00
Settings . mqttlog_level = ( ! strlen ( tmp ) ) ? MQTT_LOG_LEVEL : atoi ( tmp ) ;
2019-10-03 13:45:24 +01:00
WebGetArg ( " l3 " , tmp , sizeof ( tmp ) ) ;
2019-06-03 16:05:09 +01:00
SetSyslog ( ( ! strlen ( tmp ) ) ? SYS_LOG_LEVEL : atoi ( tmp ) ) ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " lh " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_SYSLOG_HOST , ( ! strlen ( tmp ) ) ? SYS_LOG_HOST : tmp ) ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " lp " , tmp , sizeof ( tmp ) ) ;
Settings . syslog_port = ( ! strlen ( tmp ) ) ? SYS_LOG_PORT : atoi ( tmp ) ;
WebGetArg ( " lt " , tmp , sizeof ( tmp ) ) ;
Settings . tele_period = ( ! strlen ( tmp ) ) ? TELE_PERIOD : atoi ( tmp ) ;
if ( ( Settings . tele_period > 0 ) & & ( Settings . tele_period < 10 ) ) {
Settings . tele_period = 10 ; // Do not allow periods < 10 seconds
}
2019-10-03 13:45:24 +01:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_MQTTLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d " ) ,
2019-12-16 14:13:57 +00:00
Settings . seriallog_level , Settings . weblog_level , Settings . mqttlog_level , Settings . syslog_level , SettingsText ( SET_SYSLOG_HOST ) , Settings . syslog_port , Settings . tele_period ) ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandleOtherConfiguration ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_OTHER ) ;
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " 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 ;
}
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_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 ( ) ;
2019-03-04 17:16:07 +00:00
char stemp [ strlen ( mqtt_data ) + 1 ] ;
strlcpy ( stemp , mqtt_data , sizeof ( stemp ) ) ; // Get JSON template
2019-11-03 11:33:36 +00:00
WSContentSend_P ( HTTP_FORM_OTHER , stemp , ( USER_MODULE = = Settings . module ) ? " checked disabled " : " " , ( Settings . flag . mqtt_enabled ) ? " checked " : " " ) ; // SetOption3 - Enable MQTT
2019-01-07 15:33:18 +00:00
2019-07-27 17:37:56 +01:00
uint32_t maxfn = ( devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : ( ! devices_present ) ? 1 : 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 ) ;
2019-06-02 15:44:02 +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 ,
( i = = Settings . flag2 . emulation ) ? " checked " : " " ,
GetTextIndexed ( stemp , sizeof ( stemp ) , i , kEmulationOptions ) ,
( i = = EMUL_NONE ) ? " " : ( i = = EMUL_WEMO ) ? D_SINGLE_DEVICE : D_MULTI_DEVICE ) ;
}
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
}
2018-11-14 13:32:09 +00:00
void OtherSaveSettings ( void )
2018-10-10 21:21:44 +01:00
{
2019-12-22 14:23:52 +00:00
char tmp [ TOPSZ ] ;
2019-02-23 17:38:36 +00:00
char webindex [ 5 ] ;
2019-12-16 14:13:57 +00:00
char friendlyname [ TOPSZ ] ;
2019-12-24 14:06:19 +00:00
char message [ LOGSZ ] ;
2018-10-10 21:21:44 +01:00
2019-04-07 15:36:54 +01:00
WebGetArg ( " wp " , tmp , sizeof ( tmp ) ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_WEBPWD , ( ! strlen ( tmp ) ) ? " " : ( strchr ( tmp , ' * ' ) ) ? SettingsText ( SET_WEBPWD ) : tmp ) ;
2020-04-15 08:58:38 +01:00
Settings . flag . mqtt_enabled = Webserver - > hasArg ( " b1 " ) ; // SetOption3 - Enable MQTT
2018-10-10 21:21:44 +01:00
# ifdef USE_EMULATION
2020-03-10 15:11:34 +00:00
UdpDisconnect ( ) ;
2020-02-26 12:45:46 +00:00
# if defined(USE_EMULATION_WEMO) || defined(USE_EMULATION_HUE)
2018-10-10 21:21:44 +01:00
WebGetArg ( " b2 " , tmp , sizeof ( tmp ) ) ;
Settings . flag2 . emulation = ( ! strlen ( tmp ) ) ? 0 : atoi ( tmp ) ;
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
snprintf_P ( message , sizeof ( message ) , PSTR ( D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME ) , GetStateText ( Settings . flag . mqtt_enabled ) , Settings . flag2 . emulation ) ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < MAX_FRIENDLYNAMES ; i + + ) {
2019-03-04 17:16:07 +00:00
snprintf_P ( webindex , sizeof ( webindex ) , PSTR ( " a%d " ) , i ) ;
2019-02-23 17:38:36 +00:00
WebGetArg ( webindex , tmp , sizeof ( tmp ) ) ;
snprintf_P ( friendlyname , sizeof ( friendlyname ) , PSTR ( FRIENDLY_NAME " %d " ) , i + 1 ) ;
2019-12-16 14:13:57 +00:00
SettingsUpdateText ( SET_FRIENDLYNAME1 + i , ( ! strlen ( tmp ) ) ? ( i ) ? friendlyname : FRIENDLY_NAME : tmp ) ;
2019-12-24 14:06:19 +00:00
snprintf_P ( message , sizeof ( message ) , PSTR ( " %s%s %s " ) , message , ( i ) ? " , " : " " , SettingsText ( SET_FRIENDLYNAME1 + i ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-12-24 14:06:19 +00:00
AddLog_P ( LOG_LEVEL_INFO , message ) ;
2020-03-14 16:46:22 +00:00
/*
// This sometimes provides intermittent watchdog
2020-04-15 08:58:38 +01:00
bool template_activate = Webserver - > hasArg ( " t2 " ) ; // Try this to tackle intermittent watchdog after execution of Template command
2019-02-12 10:55:47 +00:00
WebGetArg ( " t1 " , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
char svalue [ 128 ] ;
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_TEMPLATE " %s " ) , tmp ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
2019-02-13 15:05:25 +00:00
2020-03-14 16:46:22 +00:00
if ( template_activate ) {
2019-02-13 15:05:25 +00:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_MODULE " 0 " ) ) ;
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
}
2020-03-14 16:46:22 +00:00
}
// Try async execution of commands
*/
WebGetArg ( " t1 " , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
2020-04-15 08:58:38 +01:00
snprintf_P ( message , sizeof ( message ) , PSTR ( D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s " ) , tmp , ( Webserver - > hasArg ( " t2 " ) ) ? " ; " D_CMND_MODULE " 0 " : " " ) ;
2020-03-14 16:46:22 +00:00
ExecuteWebCommand ( message , SRC_WEBGUI ) ;
2019-02-12 10:55:47 +00:00
}
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 ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_BACKUP_CONFIGURATION ) ) ;
if ( ! SettingsBufferAlloc ( ) ) { return ; }
2020-04-15 08:58:38 +01:00
WiFiClient myClient = Webserver - > client ( ) ;
Webserver - > setContentLength ( sizeof ( Settings ) ) ;
2018-10-10 21:21:44 +01:00
2019-12-22 14:23:52 +00:00
char attachment [ TOPSZ ] ;
2019-07-25 13:18:28 +01:00
2019-12-16 14:13:57 +00:00
// char friendlyname[TOPSZ];
// snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(friendlyname, SettingsText(SET_FRIENDLYNAME1)), my_version);
2019-07-25 13:18:28 +01:00
char hostname [ sizeof ( my_hostname ) ] ;
snprintf_P ( attachment , sizeof ( attachment ) , PSTR ( " attachment; filename=Config_%s_%s.dmp " ) , NoAlNumToUnderscore ( hostname , my_hostname ) , my_version ) ;
2020-04-15 08:58:38 +01:00
Webserver - > sendHeader ( F ( " Content-Disposition " ) , attachment ) ;
2018-10-10 21:21:44 +01:00
2019-02-23 14:29:42 +00:00
WSSend ( 200 , CT_STREAM , " " ) ;
2018-10-10 21:21:44 +01:00
2019-09-07 17:32:11 +01:00
uint32_t cfg_crc32 = Settings . cfg_crc32 ;
Settings . cfg_crc32 = GetSettingsCrc32 ( ) ; // Calculate crc (again) as it might be wrong when savedata = 0 (#3918)
2018-10-10 21:21:44 +01:00
memcpy ( settings_buffer , & Settings , sizeof ( Settings ) ) ;
2019-08-15 12:50:28 +01:00
if ( Web . config_xor_on_set ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 2 ; i < sizeof ( Settings ) ; i + + ) {
2019-08-15 12:50:28 +01:00
settings_buffer [ i ] ^ = ( Web . config_xor_on_set + i ) ;
2018-10-10 21:21:44 +01:00
}
}
# ifdef ARDUINO_ESP8266_RELEASE_2_3_0
size_t written = myClient . write ( ( const char * ) settings_buffer , sizeof ( Settings ) ) ;
if ( written < sizeof ( Settings ) ) { // https://github.com/esp8266/Arduino/issues/3218
myClient . write ( ( const char * ) settings_buffer + written , sizeof ( Settings ) - written ) ;
}
# else
myClient . write ( ( const char * ) settings_buffer , sizeof ( Settings ) ) ;
# endif
SettingsBufferFree ( ) ;
2019-09-07 17:32:11 +01:00
Settings . cfg_crc32 = cfg_crc32 ; // Restore crc in case savedata = 0 to make sure settings will be noted as changed
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
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
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_RESET_CONFIGURATION ) ;
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_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 " ) ) ;
ExecuteWebCommand ( command , SRC_WEBGUI ) ;
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 ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_RESTORE_CONFIGURATION ) ;
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_RESTORE_CONFIGURATION ) ;
2019-03-04 17:16:07 +00:00
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_RST ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( HTTP_FORM_RST_UPG , 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_error = 0 ;
Web . upload_file_type = UPL_SETTINGS ;
2018-10-10 21:21:44 +01:00
}
/*-------------------------------------------------------------------------------------------*/
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 ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_INFORMATION ) ;
char stopic [ TOPSZ ] ;
2020-04-22 15:07:52 +01:00
int freeMem = ESP_getFreeHeap ( ) ;
2018-10-10 21:21:44 +01:00
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_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> " ) ) ;
WSContentSend_P ( PSTR ( D_PROGRAM_VERSION " }2%s%s " ) , my_version , my_image ) ;
WSContentSend_P ( PSTR ( " }1 " D_BUILD_DATE_AND_TIME " }2%s " ) , GetBuildDateAndTime ( ) . c_str ( ) ) ;
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
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_FLASH_WRITE_COUNT " }2%d at 0x%X " ) , Settings . save_flag , GetSettingsAddress ( ) ) ;
2020-04-19 15:58:13 +01:00
# else
WSContentSend_P ( PSTR ( " }1 " D_FLASH_WRITE_COUNT " }2%d " ) , Settings . save_flag ) ;
# endif
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_BOOT_COUNT " }2%d " ) , Settings . bootcount ) ;
WSContentSend_P ( PSTR ( " }1 " D_RESTART_REASON " }2%s " ) , GetResetReason ( ) . c_str ( ) ) ;
2019-07-27 17:37:56 +01:00
uint32_t maxfn = ( devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : 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
2020-02-20 09:07:00 +00:00
int32_t rssi = WiFi . RSSI ( ) ;
WSContentSend_P ( PSTR ( " }1 " D_AP " %d " D_SSID " ( " D_RSSI " )}2%s (%d%%, %d dBm) " ) , Settings . sta_active + 1 , SettingsText ( SET_STASSID1 + Settings . sta_active ) , WifiGetRssiAsQuality ( rssi ) , rssi ) ;
2019-08-17 16:13:09 +01:00
WSContentSend_P ( PSTR ( " }1 " D_HOSTNAME " }2%s%s " ) , my_hostname , ( Wifi . mdns_begun ) ? " .local " : " " ) ;
2019-12-11 14:53:19 +00:00
# if LWIP_IPV6
String ipv6_addr = WifiGetIPv6 ( ) ;
if ( ipv6_addr ! = " " ) {
WSContentSend_P ( PSTR ( " }1 IPv6 Address }2%s " ) , ipv6_addr . c_str ( ) ) ;
}
# endif
2018-10-10 21:21:44 +01:00
if ( static_cast < uint32_t > ( WiFi . localIP ( ) ) ! = 0 ) {
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_IP_ADDRESS " }2%s " ) , WiFi . localIP ( ) . toString ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_GATEWAY " }2%s " ) , IPAddress ( Settings . ip_address [ 1 ] ) . toString ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_SUBNET_MASK " }2%s " ) , IPAddress ( Settings . ip_address [ 2 ] ) . toString ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_DNS_SERVER " }2%s " ) , IPAddress ( Settings . ip_address [ 3 ] ) . toString ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_MAC_ADDRESS " }2%s " ) , WiFi . macAddress ( ) . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
if ( static_cast < uint32_t > ( WiFi . softAPIP ( ) ) ! = 0 ) {
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_IP_ADDRESS " }2%s " ) , WiFi . softAPIP ( ) . toString ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_GATEWAY " }2%s " ) , WiFi . softAPIP ( ) . toString ( ) . c_str ( ) ) ;
WSContentSend_P ( PSTR ( " }1 " D_MAC_ADDRESS " }2%s " ) , WiFi . softAPmacAddress ( ) . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2019-11-03 11:33:36 +00: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 ) ) ;
2019-06-10 11:06:03 +01:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_PORT " }2%d " ) , Settings . mqtt_port ) ;
2019-12-16 14:13:57 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_USER " }2%s " ) , SettingsText ( SET_MQTT_USER ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_CLIENT " }2%s " ) , 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
}
}
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT_FULL_TOPIC " }2%s " ) , GetTopic_P ( stopic , CMND , mqtt_topic , " " ) ) ;
2019-10-31 16:24:06 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MQTT " " D_FALLBACK_TOPIC " }2%s " ) , GetFallbackTopic_P ( stopic , " " ) ) ;
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
}
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2018-10-10 21:21:44 +01:00
# ifdef USE_EMULATION
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_EMULATION " }2%s " ) , GetTextIndexed ( stopic , sizeof ( stopic ) , Settings . flag2 . emulation , kEmulationOptions ) ) ;
2018-10-10 21:21:44 +01:00
# else
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_EMULATION " }2 " D_DISABLED ) ) ;
2018-10-10 21:21:44 +01:00
# endif // USE_EMULATION
2019-03-04 17:16:07 +00:00
2018-10-10 21:21:44 +01:00
# ifdef USE_DISCOVERY
2019-11-03 12:51:22 +00: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 ) ) ;
2018-10-10 21:21:44 +01:00
# endif // WEBSERVER_ADVERTISE
2019-01-03 17:07:03 +00:00
}
2018-10-10 21:21:44 +01:00
# else
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_MDNS_DISCOVERY " }2 " D_DISABLED ) ) ;
2018-10-10 21:21:44 +01:00
# endif // USE_DISCOVERY
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1}2 " ) ) ; // Empty line
2020-04-13 16:45:06 +01:00
WSContentSend_P ( PSTR ( " }1 " D_ESP_CHIP_ID " }2%d " ) , ESP_getChipId ( ) ) ;
2020-04-19 15:58:13 +01:00
# ifdef ESP8266
WSContentSend_P ( PSTR ( " }1 " D_FLASH_CHIP_ID " }20x%06X " ) , ESP . getFlashChipId ( ) ) ;
# endif
2020-04-16 17:33:26 +01:00
WSContentSend_P ( PSTR ( " }1 " D_FLASH_CHIP_SIZE " }2%dkB " ) , ESP . getFlashChipRealSize ( ) / 1024 ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_PROGRAM_FLASH_SIZE " }2%dkB " ) , ESP . getFlashChipSize ( ) / 1024 ) ;
2020-04-13 16:45:06 +01:00
WSContentSend_P ( PSTR ( " }1 " D_PROGRAM_SIZE " }2%dkB " ) , ESP_getSketchSize ( ) / 1024 ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( PSTR ( " }1 " D_FREE_PROGRAM_SPACE " }2%dkB " ) , ESP . getFreeSketchSpace ( ) / 1024 ) ;
WSContentSend_P ( PSTR ( " }1 " D_FREE_MEMORY " }2%dkB " ) , freeMem / 1024 ) ;
WSContentSend_P ( PSTR ( " </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
}
2019-02-08 13:55:45 +00:00
# endif // Not FIRMWARE_MINIMAL
2018-10-10 21:21:44 +01:00
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandleUpgradeFirmware ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_FIRMWARE_UPGRADE ) ;
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_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 ) ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( HTTP_FORM_RST_UPG , D_UPGRADE ) ;
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_error = 0 ;
Web . upload_file_type = UPL_TASMOTA ;
2018-10-10 21:21:44 +01:00
}
2018-11-14 13:32:09 +00:00
void HandleUpgradeFirmwareStart ( void )
2018-10-10 21:21:44 +01:00
{
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
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_UPGRADE_STARTED ) ) ;
WifiConfigCounter ( ) ;
2019-12-22 14:23:52 +00:00
char otaurl [ TOPSZ ] ;
2019-02-23 17:38:36 +00:00
WebGetArg ( " o " , otaurl , sizeof ( otaurl ) ) ;
if ( strlen ( otaurl ) ) {
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_OTAURL " %s " ) , otaurl ) ;
ExecuteWebCommand ( command , SRC_WEBGUI ) ;
2018-10-10 21:21:44 +01:00
}
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_INFORMATION ) ;
WSContentSend_P ( HTTP_SCRIPT_RELOAD_OTA ) ;
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 " ) ) ;
ExecuteWebCommand ( command , SRC_WEBGUI ) ;
2018-10-10 21:21:44 +01:00
}
2018-11-14 13:32:09 +00:00
void HandleUploadDone ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-10 11:57:42 +00:00
if ( ! HttpCheckPriviledgedAccess ( ) ) { return ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_UPLOAD_DONE ) ) ;
char error [ 100 ] ;
WifiConfigCounter ( ) ;
restart_flag = 0 ;
MqttRetryCounter ( 0 ) ;
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_INFORMATION ) ;
2019-08-15 12:50:28 +01:00
if ( ! Web . upload_error ) {
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_SCRIPT_RELOAD_OTA ) ; // 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 ) ) ;
2018-10-10 21:21:44 +01:00
# ifdef USE_RF_FLASH
2019-12-20 17:24:20 +00:00
if ( Web . upload_error < 15 ) {
2019-02-23 12:17:02 +00:00
# else
2019-12-20 17:24:20 +00:00
if ( ( Web . upload_error < 10 ) | | ( 14 = = Web . upload_error ) ) {
if ( 14 = = Web . upload_error ) { Web . upload_error = 10 ; }
2018-10-10 21:21:44 +01:00
# endif
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 ) ;
2019-11-03 11:33:36 +00:00
stop_flash_rotate = Settings . flag . stop_flash_rotate ; // SetOption12 - Switch between dynamic or fixed slot flash save location
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 ) ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_MSG_RSTRT ) ;
2018-10-10 21:21:44 +01:00
ShowWebSource ( SRC_WEBGUI ) ;
2019-10-26 21:58:04 +01:00
# ifdef USE_TASMOTA_SLAVE
if ( TasmotaSlave_GetFlagFlashing ( ) ) {
2019-10-20 19:11:07 +01:00
restart_flag = 0 ;
} else { // It was a normal firmware file, or we are ready to restart device
restart_flag = 2 ;
}
2019-10-22 15:34:25 +01:00
# else
2018-10-10 21:21:44 +01:00
restart_flag = 2 ; // Always restart to re-enable disabled features during update
2019-10-22 15:34:25 +01:00
# endif
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 ( ) ;
2019-10-26 21:58:04 +01:00
# ifdef USE_TASMOTA_SLAVE
if ( TasmotaSlave_GetFlagFlashing ( ) ) {
TasmotaSlave_Flash ( ) ;
2019-10-20 19:11:07 +01:00
}
2019-10-22 15:34:25 +01:00
# endif
2018-10-10 21:21:44 +01:00
}
2018-11-14 13:32:09 +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)
2019-01-28 13:08:33 +00:00
bool _serialoutput = ( LOG_LEVEL_DEBUG < = seriallog_level ) ;
2018-10-10 21:21:44 +01:00
2019-08-15 12:50:28 +01:00
if ( HTTP_USER = = Web . state ) { return ; }
if ( Web . upload_error ) {
if ( UPL_TASMOTA = = Web . upload_file_type ) { Update . end ( ) ; }
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
if ( UPLOAD_FILE_START = = upload . status ) {
restart_flag = 60 ;
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
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD D_FILE " %s ... " ) , upload . filename . c_str ( ) ) ;
2019-08-15 12:50:28 +01:00
if ( UPL_SETTINGS = = Web . upload_file_type ) {
2018-10-10 21:21:44 +01:00
if ( ! SettingsBufferAlloc ( ) ) {
2019-08-15 12:50:28 +01:00
Web . upload_error = 2 ; // Not enough space
2018-10-10 21:21:44 +01:00
return ;
}
} else {
MqttRetryCounter ( 60 ) ;
# ifdef USE_EMULATION
UdpDisconnect ( ) ;
# endif // USE_EMULATION
# ifdef USE_ARILUX_RF
AriluxRfDisable ( ) ; // Prevent restart exception on Arilux Interrupt routine
# endif // USE_ARILUX_RF
2019-11-03 11:33:36 +00:00
if ( Settings . flag . mqtt_enabled ) { // SetOption3 - Enable MQTT
MqttDisconnect ( ) ;
}
2018-10-10 21:21:44 +01:00
uint32_t maxSketchSpace = ( ESP . getFreeSketchSpace ( ) - 0x1000 ) & 0xFFFFF000 ;
if ( ! Update . begin ( maxSketchSpace ) ) { //start with max available size
// if (_serialoutput) Update.printError(Serial);
// if (Update.getError() == UPDATE_ERROR_BOOTSTRAP) {
// if (_serialoutput) Serial.println("Device still in UART update mode, perform powercycle");
// }
2019-08-15 12:50:28 +01:00
Web . upload_error = 2 ; // Not enough space
2018-10-10 21:21:44 +01:00
return ;
}
}
2019-08-15 12:50:28 +01:00
Web . upload_progress_dot_count = 0 ;
} else if ( ! Web . upload_error & & ( UPLOAD_FILE_WRITE = = upload . status ) ) {
2018-10-10 21:21:44 +01:00
if ( 0 = = upload . totalSize ) {
2019-08-15 12:50:28 +01:00
if ( UPL_SETTINGS = = Web . upload_file_type ) {
Web . config_block_count = 0 ;
2018-10-10 21:21:44 +01:00
}
else {
2019-10-15 14:37:22 +01:00
# ifdef USE_RF_FLASH
2019-02-11 18:21:49 +00:00
if ( ( SONOFF_BRIDGE = = my_module_type ) & & ( upload . buf [ 0 ] = = ' : ' ) ) { // Check if this is a RF bridge FW file
2018-10-10 21:21:44 +01:00
Update . end ( ) ; // End esp8266 update session
2019-08-15 12:50:28 +01:00
Web . upload_file_type = UPL_EFM8BB1 ;
2018-10-10 21:21:44 +01:00
2019-12-20 17:37:14 +00:00
Web . upload_error = SnfBrUpdateInit ( ) ; // 10, 11
2019-08-15 12:50:28 +01:00
if ( Web . upload_error ! = 0 ) { return ; }
2018-10-10 21:21:44 +01:00
} else
# endif // USE_RF_FLASH
2019-10-26 21:58:04 +01:00
# ifdef USE_TASMOTA_SLAVE
2019-10-20 19:11:07 +01:00
if ( ( WEMOS = = my_module_type ) & & ( upload . buf [ 0 ] = = ' : ' ) ) { // Check if this is a ARDUINO SLAVE hex file
Update . end ( ) ; // End esp8266 update session
2019-10-26 21:58:04 +01:00
Web . upload_file_type = UPL_TASMOTASLAVE ;
2019-12-20 17:37:14 +00:00
Web . upload_error = TasmotaSlave_UpdateInit ( ) ; // 0
2019-10-20 19:11:07 +01:00
if ( Web . upload_error ! = 0 ) { return ; }
} else
# endif
2018-10-10 21:21:44 +01:00
{
2020-01-06 13:52:04 +00:00
if ( ( upload . buf [ 0 ] ! = 0xE9 ) & & ( upload . buf [ 0 ] ! = 0x1F ) ) { // 0x1F is gzipped 0xE9
2019-08-15 12:50:28 +01:00
Web . upload_error = 3 ; // Magic byte is not 0xE9
2018-10-10 21:21:44 +01:00
return ;
}
2020-01-06 13:52:04 +00:00
if ( 0xE9 = = upload . buf [ 0 ] ) {
uint32_t bin_flash_size = ESP . magicFlashChipSize ( ( upload . buf [ 3 ] & 0xf0 ) > > 4 ) ;
if ( bin_flash_size > ESP . getFlashChipRealSize ( ) ) {
Web . upload_error = 4 ; // Program flash size is larger than real flash size
return ;
}
// upload.buf[2] = 3; // Force DOUT - ESP8285
2018-10-10 21:21:44 +01:00
}
}
}
}
2019-08-15 12:50:28 +01:00
if ( UPL_SETTINGS = = Web . upload_file_type ) {
if ( ! Web . upload_error ) {
if ( upload . currentSize > ( sizeof ( Settings ) - ( Web . config_block_count * HTTP_UPLOAD_BUFLEN ) ) ) {
Web . upload_error = 9 ; // File too large
2018-10-10 21:21:44 +01:00
return ;
}
2019-08-15 12:50:28 +01: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
}
}
# ifdef USE_RF_FLASH
2019-08-15 12:50:28 +01:00
else if ( UPL_EFM8BB1 = = Web . upload_file_type ) {
2019-03-26 17:26:50 +00:00
if ( efm8bb1_update ! = nullptr ) { // We have carry over data since last write, i. e. a start but not an end
2018-10-10 21:21:44 +01:00
ssize_t result = rf_glue_remnant_with_new_data_and_write ( efm8bb1_update , upload . buf , upload . currentSize ) ;
free ( efm8bb1_update ) ;
2019-03-26 17:26:50 +00:00
efm8bb1_update = nullptr ;
2018-10-10 21:21:44 +01:00
if ( result ! = 0 ) {
2019-12-20 17:37:14 +00:00
Web . upload_error = abs ( result ) ; // 2 = Not enough space, 8 = File invalid, 12, 13
2018-10-10 21:21:44 +01:00
return ;
}
}
ssize_t result = rf_search_and_write ( upload . buf , upload . currentSize ) ;
if ( result < 0 ) {
2019-12-20 17:37:14 +00:00
Web . upload_error = abs ( result ) ; // 8, 12, 13
2018-10-10 21:21:44 +01:00
return ;
} else if ( result > 0 ) {
2018-12-24 17:14:25 +00:00
if ( ( size_t ) result > upload . currentSize ) {
2018-10-10 21:21:44 +01:00
// Offset is larger than the buffer supplied, this should not happen
2019-08-15 12:50:28 +01:00
Web . upload_error = 9 ; // File too large - Failed to decode RF firmware
2018-10-10 21:21:44 +01:00
return ;
}
// A remnant has been detected, allocate data for it plus a null termination byte
size_t remnant_sz = upload . currentSize - result ;
efm8bb1_update = ( uint8_t * ) malloc ( remnant_sz + 1 ) ;
2019-03-26 17:26:50 +00:00
if ( efm8bb1_update = = nullptr ) {
2019-08-15 12:50:28 +01:00
Web . upload_error = 2 ; // Not enough space - Unable to allocate memory to store new RF firmware
2018-10-10 21:21:44 +01:00
return ;
}
memcpy ( efm8bb1_update , upload . buf + result , remnant_sz ) ;
// Add null termination at the end of of remnant buffer
efm8bb1_update [ remnant_sz ] = ' \0 ' ;
}
}
# endif // USE_RF_FLASH
2019-10-26 21:58:04 +01:00
# ifdef USE_TASMOTA_SLAVE
else if ( UPL_TASMOTASLAVE = = Web . upload_file_type ) {
TasmotaSlave_WriteBuffer ( upload . buf , upload . currentSize ) ;
2019-10-20 19:11:07 +01:00
}
# endif
2018-10-10 21:21:44 +01:00
else { // firmware
2019-08-15 12:50:28 +01:00
if ( ! Web . upload_error & & ( Update . write ( upload . buf , upload . currentSize ) ! = upload . currentSize ) ) {
Web . upload_error = 5 ; // Upload buffer miscompare
2018-10-10 21:21:44 +01:00
return ;
}
if ( _serialoutput ) {
Serial . printf ( " . " ) ;
2019-08-15 12:50:28 +01:00
Web . upload_progress_dot_count + + ;
if ( ! ( Web . upload_progress_dot_count % 80 ) ) { Serial . println ( ) ; }
2018-10-10 21:21:44 +01:00
}
}
2019-08-15 12:50:28 +01:00
} else if ( ! Web . upload_error & & ( UPLOAD_FILE_END = = upload . status ) ) {
if ( _serialoutput & & ( Web . upload_progress_dot_count % 80 ) ) {
2018-10-10 21:21:44 +01:00
Serial . println ( ) ;
}
2019-08-15 12:50:28 +01:00
if ( UPL_SETTINGS = = Web . upload_file_type ) {
if ( Web . config_xor_on_set ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 2 ; i < sizeof ( Settings ) ; i + + ) {
2019-08-15 12:50:28 +01:00
settings_buffer [ i ] ^ = ( Web . config_xor_on_set + i ) ;
2018-10-10 21:21:44 +01:00
}
}
bool valid_settings = false ;
unsigned long buffer_version = settings_buffer [ 11 ] < < 24 | settings_buffer [ 10 ] < < 16 | settings_buffer [ 9 ] < < 8 | settings_buffer [ 8 ] ;
if ( buffer_version > 0x06000000 ) {
2019-07-27 17:37:56 +01:00
uint32_t buffer_size = settings_buffer [ 3 ] < < 8 | settings_buffer [ 2 ] ;
2019-09-07 17:32:11 +01:00
if ( buffer_version > 0x0606000A ) {
uint32_t buffer_crc32 = settings_buffer [ 4095 ] < < 24 | settings_buffer [ 4094 ] < < 16 | settings_buffer [ 4093 ] < < 8 | settings_buffer [ 4092 ] ;
valid_settings = ( GetCfgCrc32 ( settings_buffer , buffer_size - 4 ) = = buffer_crc32 ) ;
} else {
uint16_t buffer_crc16 = settings_buffer [ 15 ] < < 8 | settings_buffer [ 14 ] ;
valid_settings = ( GetCfgCrc16 ( settings_buffer , buffer_size ) = = buffer_crc16 ) ;
2018-10-10 21:21:44 +01:00
}
} else {
valid_settings = ( settings_buffer [ 0 ] = = CONFIG_FILE_SIGN ) ;
}
2020-04-17 10:57:09 +01:00
if ( valid_settings ) {
# ifdef ESP8266
valid_settings = ( 0 = = settings_buffer [ 0xF36 ] ) ; // Settings.config_version
# endif // ESP8266
# ifdef ESP32
valid_settings = ( 1 = = settings_buffer [ 0xF36 ] ) ; // Settings.config_version
# endif // ESP32
}
2018-10-10 21:21:44 +01:00
if ( valid_settings ) {
SettingsDefaultSet2 ( ) ;
memcpy ( ( char * ) & Settings + 16 , settings_buffer + 16 , sizeof ( Settings ) - 16 ) ;
Settings . version = buffer_version ; // Restore version and auto upgrade after restart
SettingsBufferFree ( ) ;
} else {
2019-08-15 12:50:28 +01:00
Web . upload_error = 8 ; // File invalid
2018-10-10 21:21:44 +01:00
return ;
}
}
# ifdef USE_RF_FLASH
2019-08-15 12:50:28 +01:00
else if ( UPL_EFM8BB1 = = Web . upload_file_type ) {
2018-10-10 21:21:44 +01:00
// RF FW flash done
2019-08-15 12:50:28 +01:00
Web . upload_file_type = UPL_TASMOTA ;
2018-10-10 21:21:44 +01:00
}
# endif // USE_RF_FLASH
2019-10-26 21:58:04 +01:00
# ifdef USE_TASMOTA_SLAVE
else if ( UPL_TASMOTASLAVE = = Web . upload_file_type ) {
2019-10-20 19:11:07 +01:00
// Done writing the hex to SPI flash
2019-10-26 21:58:04 +01:00
TasmotaSlave_SetFlagFlashing ( true ) ; // So we know on upload success page if it needs to flash hex or do a normal restart
2019-10-20 19:11:07 +01:00
Web . upload_file_type = UPL_TASMOTA ;
}
# endif
2018-10-10 21:21:44 +01:00
else {
if ( ! Update . end ( true ) ) { // true to set the size to the current progress
if ( _serialoutput ) { Update . printError ( Serial ) ; }
2019-08-15 12:50:28 +01:00
Web . upload_error = 6 ; // Upload failed. Enable logging 3
2018-10-10 21:21:44 +01:00
return ;
}
2020-01-07 16:01:48 +00:00
if ( ! VersionCompatible ( ) ) {
2019-12-20 17:24:20 +00:00
Web . upload_error = 14 ; // Not compatible
2019-12-20 14:12:44 +00:00
return ;
}
2018-10-10 21:21:44 +01:00
}
2019-08-15 12:50:28 +01:00
if ( ! Web . upload_error ) {
2019-03-08 14:15:42 +00:00
AddLog_P2 ( LOG_LEVEL_INFO , PSTR ( D_LOG_UPLOAD D_SUCCESSFUL " %u bytes. " D_RESTARTING ) , upload . totalSize ) ;
2018-10-10 21:21:44 +01:00
}
} else if ( UPLOAD_FILE_ABORTED = = upload . status ) {
restart_flag = 0 ;
MqttRetryCounter ( 0 ) ;
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
}
delay ( 0 ) ;
}
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void HandlePreflightRequest ( void )
2018-10-10 21:21:44 +01:00
{
2019-10-28 12:36:04 +00:00
HttpHeaderCors ( ) ;
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
}
/*-------------------------------------------------------------------------------------------*/
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 ; }
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_COMMAND ) ) ;
2019-12-16 14:13:57 +00:00
if ( strlen ( SettingsText ( SET_WEBPWD ) ) ) {
char tmp1 [ 33 ] ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " user " , tmp1 , sizeof ( tmp1 ) ) ;
2019-12-16 14:13:57 +00:00
char tmp2 [ strlen ( SettingsText ( SET_WEBPWD ) ) + 1 ] ;
2018-10-10 21:21:44 +01:00
WebGetArg ( " password " , tmp2 , sizeof ( tmp2 ) ) ;
2020-04-15 09:14:16 +01:00
if ( ! ( ! strcmp ( tmp1 , WEB_USERNAME ) & & ! strcmp ( tmp2 , SettingsText ( SET_WEBPWD ) ) ) ) {
WSContentBegin ( 401 , CT_JSON ) ;
WSContentSend_P ( PSTR ( " { \" " D_RSLT_WARNING " \" : \" " D_NEED_USER_AND_PASSWORD " \" } " ) ) ;
WSContentEnd ( ) ;
return ;
}
2018-10-10 21:21:44 +01:00
}
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_JSON ) ;
2020-04-15 09:14:16 +01:00
uint32_t curridx = web_log_index ;
String svalue = Webserver - > arg ( " cmnd " ) ;
if ( svalue . length ( ) & & ( svalue . length ( ) < MQTT_MAX_PACKET_SIZE ) ) {
ExecuteWebCommand ( ( char * ) svalue . c_str ( ) , SRC_WEBCOMMAND ) ;
if ( web_log_index ! = curridx ) {
uint32_t counter = curridx ;
WSContentSend_P ( PSTR ( " { " ) ) ;
bool cflg = false ;
do {
char * tmp ;
size_t len ;
GetLog ( counter , & tmp , & len ) ;
if ( len ) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char * JSON = ( char * ) memchr ( tmp , ' { ' , len ) ;
if ( JSON ) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
size_t JSONlen = len - ( JSON - tmp ) ;
if ( JSONlen > sizeof ( mqtt_data ) ) { JSONlen = sizeof ( mqtt_data ) ; }
char stemp [ JSONlen ] ;
strlcpy ( stemp , JSON + 1 , JSONlen - 2 ) ;
WSContentSend_P ( PSTR ( " %s%s " ) , ( cflg ) ? " , " : " " , stemp ) ;
cflg = true ;
2018-10-10 21:21:44 +01:00
}
2020-04-15 09:14:16 +01:00
}
counter + + ;
counter & = 0xFF ;
if ( ! counter ) counter + + ; // Skip 0 as it is not allowed
} while ( counter ! = web_log_index ) ;
WSContentSend_P ( PSTR ( " } " ) ) ;
2018-10-10 21:21:44 +01:00
} else {
2020-04-15 09:14:16 +01:00
WSContentSend_P ( PSTR ( " { \" " D_RSLT_WARNING " \" : \" " D_ENABLE_WEBLOG_FOR_RESPONSE " \" } " ) ) ;
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
}
/*-------------------------------------------------------------------------------------------*/
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 ; }
2020-04-15 08:58:38 +01:00
if ( Webserver - > hasArg ( " c2 " ) ) { // Console refresh requested
2019-03-01 17:25:46 +00:00
HandleConsoleRefresh ( ) ;
return ;
}
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONSOLE ) ;
2019-03-10 14:36:34 +00:00
WSContentStart_P ( S_CONSOLE ) ;
2019-03-04 17:16:07 +00:00
WSContentSend_P ( HTTP_SCRIPT_CONSOL , Settings . web_refresh ) ;
WSContentSendStyle ( ) ;
2019-03-10 14:36:34 +00:00
WSContentSend_P ( HTTP_FORM_CMND ) ;
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-03-01 17:25:46 +00:00
void HandleConsoleRefresh ( void )
2018-10-10 21:21:44 +01:00
{
2019-01-28 13:08:33 +00:00
bool cflg = true ;
2019-07-27 17:37:56 +01:00
uint32_t counter = 0 ; // Initial start, should never be 0 again
2018-10-10 21:21:44 +01:00
2020-04-15 08:58:38 +01:00
String svalue = Webserver - > arg ( " c1 " ) ;
2019-08-01 21:59:12 +01:00
if ( svalue . length ( ) & & ( svalue . length ( ) < MQTT_MAX_PACKET_SIZE ) ) {
2019-03-08 14:15:42 +00:00
AddLog_P2 ( 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 ] ;
2019-02-22 11:04:05 +00:00
WebGetArg ( " c2 " , stmp , sizeof ( stmp ) ) ;
if ( strlen ( stmp ) ) { counter = atoi ( stmp ) ; }
2018-10-10 21:21:44 +01:00
2019-03-16 15:23:41 +00:00
WSContentBegin ( 200 , CT_PLAIN ) ;
2019-08-15 12:50:28 +01:00
WSContentSend_P ( PSTR ( " %d}1%d}1 " ) , web_log_index , Web . reset_web_log_flag ) ;
if ( ! Web . reset_web_log_flag ) {
2018-10-10 21:21:44 +01:00
counter = 0 ;
2019-08-15 12:50:28 +01:00
Web . reset_web_log_flag = true ;
2018-10-10 21:21:44 +01:00
}
if ( counter ! = web_log_index ) {
if ( ! counter ) {
counter = web_log_index ;
2019-01-28 13:08:33 +00:00
cflg = false ;
2018-10-10 21:21:44 +01:00
}
do {
char * tmp ;
size_t len ;
GetLog ( counter , & tmp , & len ) ;
if ( len ) {
2019-02-21 13:31:31 +00:00
if ( len > sizeof ( mqtt_data ) - 2 ) { len = sizeof ( mqtt_data ) ; }
2019-03-16 15:23:41 +00:00
char stemp [ len + 1 ] ;
strlcpy ( stemp , tmp , len ) ;
WSContentSend_P ( PSTR ( " %s%s " ) , ( cflg ) ? " \n " : " " , stemp ) ;
cflg = true ;
2018-10-10 21:21:44 +01:00
}
counter + + ;
2019-07-27 17:37:56 +01:00
counter & = 0xFF ;
2019-03-16 15:23:41 +00:00
if ( ! counter ) { counter + + ; } // Skip log index 0 as it is not allowed
2018-10-10 21:21:44 +01:00
} while ( counter ! = web_log_index ) ;
}
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
{
2020-04-15 08:58:38 +01:00
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Not found (%s)"), Webserver->uri().c_str());
2018-10-10 21:21:44 +01:00
if ( CaptivePortal ( ) ) { return ; } // If captive portal redirect instead of displaying the error page.
# 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 ( ) ;
2018-10-10 21:21:44 +01:00
if ( ( EMUL_HUE = = Settings . flag2 . emulation ) & & ( path . startsWith ( " /api " ) ) ) {
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 ) ;
2020-04-15 08:58:38 +01: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 ) ? " GET " : " POST " , Webserver - > args ( ) ) ;
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
}
}
/* 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 ( ) ) ) {
2018-10-10 21:21:44 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_REDIRECTED ) ) ;
2020-04-15 08:58:38 +01:00
Webserver - > sendHeader ( F ( " Location " ) , String ( " http:// " ) + Webserver - > client ( ) . localIP ( ) . toString ( ) , 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 ;
}
/*********************************************************************************************/
String UrlEncode ( const String & text )
{
const char hex [ ] = " 0123456789ABCDEF " ;
String encoded = " " ;
int len = text . length ( ) ;
int i = 0 ;
while ( i < len ) {
char decodedChar = text . charAt ( i + + ) ;
/*
if ( ( ' a ' < = decodedChar & & decodedChar < = ' z ' ) | |
( ' A ' < = decodedChar & & decodedChar < = ' Z ' ) | |
( ' 0 ' < = decodedChar & & decodedChar < = ' 9 ' ) | |
( ' = ' = = decodedChar ) ) {
encoded + = decodedChar ;
} else {
encoded + = ' % ' ;
encoded + = hex [ decodedChar > > 4 ] ;
encoded + = hex [ decodedChar & 0xF ] ;
}
*/
2019-07-14 21:25:13 +01:00
if ( ( ' ' = = decodedChar ) | | ( ' + ' = = decodedChar ) ) {
2018-10-10 21:21:44 +01:00
encoded + = ' % ' ;
encoded + = hex [ decodedChar > > 4 ] ;
encoded + = hex [ decodedChar & 0xF ] ;
} else {
encoded + = decodedChar ;
}
}
return encoded ;
}
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 ;
int status = 1 ; // Wrong parameters
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
}
2019-02-19 11:51:38 +00:00
url + = command ; // url = |http://192.168.178.86/cm?cmnd=POWER1 ON|
2018-10-10 21:21:44 +01:00
2019-08-09 13:05:12 +01:00
DEBUG_CORE_LOG ( PSTR ( " WEB: Uri |%s| " ) , url . c_str ( ) ) ;
2018-10-10 21:21:44 +01:00
2019-02-21 08:48:58 +00:00
# if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
2019-02-19 11:51:38 +00:00
HTTPClient http ;
if ( http . begin ( UrlEncode ( url ) ) ) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
2019-02-21 08:48:58 +00:00
# else
WiFiClient http_client ;
HTTPClient http ;
2019-02-21 13:56:39 +00:00
if ( http . begin ( http_client , UrlEncode ( url ) ) ) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
2019-02-21 08:48:58 +00:00
# endif
2019-02-19 11:51:38 +00:00
int http_code = http . GET ( ) ; // Start connection and send HTTP header
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!
2019-07-27 17:37:56 +01:00
uint32_t j = 0 ;
2019-08-19 10:21:00 +01:00
char text = ' . ' ;
while ( text ! = ' \0 ' ) {
text = * read + + ;
2019-02-19 11:51:38 +00:00
if ( text > 31 ) { // Remove control characters like linefeed
2019-02-21 08:48:58 +00:00
mqtt_data [ j + + ] = text ;
2019-02-19 11:51:38 +00:00
if ( j = = sizeof ( mqtt_data ) - 2 ) { break ; }
}
}
mqtt_data [ j ] = ' \0 ' ;
MqttPublishPrefixTopic_P ( RESULT_OR_STAT , PSTR ( D_CMND_WEBSEND ) ) ;
2019-08-19 07:20:51 +01:00
# ifdef USE_SCRIPT
extern uint8_t tasm_cmd_activ ;
// recursive call must be possible in this case
tasm_cmd_activ = 0 ;
XdrvRulesProcess ( ) ;
2019-08-19 10:47:59 +01:00
# endif // USE_SCRIPT
# endif // USE_WEBSEND_RESPONSE
2019-02-19 11:51:38 +00:00
}
2018-10-10 21:21:44 +01:00
status = 0 ; // No error - Done
} else {
status = 2 ; // Connection failed
}
2019-02-21 08:48:58 +00:00
http . end ( ) ; // Clean up connection data
2018-10-10 21:21:44 +01:00
} else {
2019-02-19 11:51:38 +00:00
status = 3 ; // Host not found or connection error
2018-10-10 21:21:44 +01:00
}
}
return status ;
}
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
char dataBufLc [ strlen ( dataBuf ) + 1 ] ;
LowerCase ( dataBufLc , dataBuf ) ;
RemoveSpace ( dataBufLc ) ;
if ( strlen ( dataBufLc ) < 9 ) { return false ; } // Workaround exception if empty JSON like {} - Needs checks
StaticJsonBuffer < 450 > jb ; // 421 from https://arduinojson.org/v5/assistant/
JsonObject & obj = jb . parseObject ( dataBufLc ) ;
if ( ! obj . success ( ) ) { return false ; }
char parm_lc [ 10 ] ;
if ( obj [ LowerCase ( parm_lc , D_CMND_WEBCOLOR ) ] . success ( ) ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < COL_LAST ; 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
const char * color = obj [ parm_lc ] [ i ] ;
if ( color ! = nullptr ) {
2019-04-09 12:56:19 +01:00
WebHexCode ( i , color ) ;
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 ;
}
2019-09-04 19:58:17 +01:00
const char kWebSendStatus [ ] PROGMEM = D_JSON_DONE " | " D_JSON_WRONG_PARAMETERS " | " D_JSON_CONNECT_FAILED " | " D_JSON_HOST_NOT_FOUND " | " D_JSON_MEMORY_ERROR ;
2018-10-10 21:21:44 +01:00
2019-08-11 17:12:18 +01:00
const char kWebCommands [ ] PROGMEM = " | " // No prefix
2019-07-28 16:57:09 +01:00
# ifdef USE_EMULATION
D_CMND_EMULATION " | "
2019-09-04 19:58:17 +01:00
# endif
# ifdef USE_SENDMAIL
D_CMND_SENDMAIL " | "
2019-07-28 16:57:09 +01:00
# endif
2019-12-24 16:10:50 +00:00
D_CMND_WEBSERVER " | " D_CMND_WEBPASSWORD " | " D_CMND_WEBLOG " | " D_CMND_WEBREFRESH " | " D_CMND_WEBSEND " | " D_CMND_WEBCOLOR " | "
D_CMND_WEBSENSOR " | " D_CMND_WEBBUTTON " | " D_CMND_CORS ;
2019-07-28 16:57:09 +01:00
void ( * const WebCommand [ ] ) ( void ) PROGMEM = {
# ifdef USE_EMULATION
& CmndEmulation ,
2019-09-04 19:58:17 +01:00
# endif
# ifdef USE_SENDMAIL
& CmndSendmail ,
2019-07-28 16:57:09 +01:00
# endif
2019-12-24 16:10:50 +00:00
& CmndWebServer , & CmndWebPassword , & CmndWeblog , & CmndWebRefresh , & CmndWebSend , & CmndWebColor ,
& CmndWebSensor , & CmndWebButton , & CmndCors } ;
2019-07-28 16:57:09 +01:00
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# 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
Settings . flag2 . emulation = XdrvMailbox . payload ;
restart_flag = 2 ;
}
2020-02-25 10:52:52 +00:00
# endif
2019-08-03 12:01:34 +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
2019-09-04 19:58:17 +01:00
# ifdef USE_SENDMAIL
void CmndSendmail ( void )
{
if ( XdrvMailbox . data_len > 0 ) {
2019-09-05 16:19:19 +01:00
uint8_t result = SendMail ( XdrvMailbox . data ) ;
char stemp1 [ 20 ] ;
ResponseCmndChar ( GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , result , kWebSendStatus ) ) ;
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 ) ) {
Settings . webserver = XdrvMailbox . payload ;
2018-10-10 21:21:44 +01:00
}
2019-07-28 16:57:09 +01:00
if ( Settings . webserver ) {
Response_P ( PSTR ( " { \" " D_CMND_WEBSERVER " \" : \" " D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s \" } " ) ,
( 2 = = Settings . webserver ) ? D_ADMIN : D_USER , my_hostname , WiFi . localIP ( ) . toString ( ) . c_str ( ) ) ;
} 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 )
{
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 ) ;
ResponseCmndChar ( SettingsText ( SET_WEBPWD ) ) ;
2019-07-28 16:57:09 +01:00
} else {
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 ) ) {
2019-07-28 16:57:09 +01:00
Settings . weblog_level = XdrvMailbox . payload ;
2018-10-10 21:21:44 +01:00
}
2019-08-03 12:01:34 +01:00
ResponseCmndNumber ( Settings . weblog_level ) ;
2019-07-28 16:57:09 +01:00
}
void CmndWebRefresh ( void )
{
if ( ( XdrvMailbox . payload > 999 ) & & ( XdrvMailbox . payload < = 10000 ) ) {
Settings . web_refresh = XdrvMailbox . payload ;
2018-10-10 21:21:44 +01:00
}
2019-08-03 12:01:34 +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 ] ;
2019-08-03 12:01:34 +01:00
ResponseCmndChar ( GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , result , kWebSendStatus ) ) ;
2018-10-10 21:21:44 +01:00
}
2019-07-28 16:57:09 +01:00
}
void CmndWebColor ( void )
{
if ( XdrvMailbox . data_len > 0 ) {
if ( strstr ( XdrvMailbox . data , " { " ) = = nullptr ) { // If no JSON it must be parameter
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 {
JsonWebColor ( 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
Response_P ( PSTR ( " { \" " D_CMND_WEBCOLOR " \" :[ " ) ) ;
for ( uint32_t i = 0 ; i < COL_LAST ; i + + ) {
if ( i ) { ResponseAppend_P ( PSTR ( " , " ) ) ; }
ResponseAppend_P ( PSTR ( " \" #%06x \" " ) , 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 ) {
bitWrite ( Settings . sensors [ XdrvMailbox . index / 32 ] , XdrvMailbox . index % 32 , XdrvMailbox . payload & 1 ) ;
}
}
2019-08-18 12:23:43 +01:00
Response_P ( PSTR ( " { \" " D_CMND_WEBSENSOR " \" : " ) ) ;
XsnsSensorState ( ) ;
ResponseJsonEnd ( ) ;
2019-08-16 15:54:36 +01:00
}
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 ) {
SettingsUpdateText ( SET_BUTTON1 + XdrvMailbox . index - 1 , ( ' " ' = = XdrvMailbox . data [ 0 ] ) ? " " : XdrvMailbox . data ) ;
}
ResponseCmndIdxChar ( SettingsText ( SET_BUTTON1 + XdrvMailbox . index - 1 ) ) ;
}
}
}
2019-11-29 17:28:25 +00:00
void CmndCors ( void )
{
2019-12-16 14:13:57 +00:00
if ( XdrvMailbox . data_len > 0 ) {
SettingsUpdateText ( SET_CORS , ( SC_CLEAR = = Shortcut ( ) ) ? " " : ( SC_DEFAULT = = Shortcut ( ) ) ? WEB_PASSWORD : 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
}
2018-10-10 21:21:44 +01:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 13:08:33 +00:00
bool Xdrv01 ( uint8_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
2019-03-30 12:03:45 +00:00
if ( Settings . flag2 . emulation ) { PollUdp ( ) ; }
2018-10-10 21:21:44 +01:00
# endif // USE_EMULATION
break ;
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 ;
}
# endif // USE_WEBSERVER