2017-01-28 13:41:01 +00:00
/*
2018-05-28 10:35:23 +01:00
xdrv_02_webserver . ino - webserver for Sonoff - Tasmota
2017-05-13 12:02:10 +01:00
2017-12-22 13:55:24 +00:00
Copyright ( C ) 2018 Theo Arends
2017-05-13 12:02:10 +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/>.
2017-01-28 13:41:01 +00:00
*/
# ifdef USE_WEBSERVER
/*********************************************************************************************\
* Web server and WiFi Manager
*
* Enables configuration and reconfiguration of WiFi credentials using a Captive Portal
2017-07-15 14:07:30 +01:00
* Based on source by AlexT ( https : //github.com/tzapu)
2017-01-28 13:41:01 +00:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-06-04 17:10:38 +01:00
# ifdef USE_RF_FLASH
uint8_t * efm8bb1_update = NULL ;
# endif // USE_RF_FLASH
enum UploadTypes { UPL_TASMOTA , UPL_SETTINGS , UPL_EFM8BB1 } ;
2017-01-28 13:41:01 +00:00
const char HTTP_HEAD [ ] PROGMEM =
2018-03-10 13:51:40 +00:00
" <!DOCTYPE html><html lang= \" " D_HTML_LANGUAGE " \" class= \" \" > "
2017-01-28 13:41:01 +00:00
" <head> "
" <meta charset='utf-8'> "
" <meta name= \" viewport \" content= \" width=device-width,initial-scale=1,user-scalable=no \" /> "
2017-11-29 16:34:32 +00:00
" <title>{h} - {v}</title> "
2017-03-08 15:20:45 +00:00
2017-01-28 13:41:01 +00:00
" <script> "
2017-03-08 15:20:45 +00:00
" var cn,x,lt; "
2018-01-18 15:19:28 +00:00
" cn=180; "
2017-03-08 15:20:45 +00:00
" x=null; " // Allow for abortion
2018-03-28 17:01:38 +01:00
" function eb(s){ "
" return document.getElementById(s); " // Save code space
" } "
2017-01-28 13:41:01 +00:00
" function u(){ "
" if(cn>=0){ "
2018-03-28 17:01:38 +01:00
" eb('t').innerHTML=' " D_RESTART_IN " '+cn+' " D_SECONDS " '; "
2017-01-28 13:41:01 +00:00
" cn--; "
" setTimeout(u,1000); "
" } "
" } "
" function c(l){ "
2018-03-28 17:01:38 +01:00
" eb('s1').value=l.innerText||l.textContent; "
" eb('p1').focus(); "
2017-01-28 13:41:01 +00:00
" } "
2017-02-24 17:17:48 +00:00
" function la(p){ "
" var a=''; "
" if(la.arguments.length==1){ "
2017-03-08 15:20:45 +00:00
" a=p; "
2017-02-24 17:17:48 +00:00
" 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){ "
2018-01-27 16:52:48 +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-03-28 17:01:38 +01:00
" eb('l1').innerHTML=s; "
2017-02-24 17:17:48 +00:00
" } "
" }; "
" x.open('GET','ay'+a,true); "
" x.send(); "
2017-02-28 15:01:48 +00:00
" lt=setTimeout(la,2345); "
2017-02-24 17:17:48 +00:00
" } "
2017-03-08 15:20:45 +00:00
" function lb(p){ "
" la('?d='+p); "
" } "
2017-08-16 16:05:36 +01:00
" function lc(p){ "
" la('?t='+p); "
2018-01-24 16:31:20 +00:00
" } " ;
const char HTTP_HEAD_STYLE [ ] PROGMEM =
2017-03-08 15:20:45 +00:00
" </script> "
" <style> "
" div,fieldset,input,select{padding:5px;font-size:1em;} "
2017-10-14 10:26:49 +01:00
" input{width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;} "
2017-03-08 15:20:45 +00:00
" select{width:100%;} "
" textarea{resize:none;width:98%;height:318px;padding:5px;overflow:auto;} "
" body{text-align:center;font-family:verdana;} "
" td{padding:0px;} "
2018-02-09 16:16:39 +00:00
" button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;-webkit-transition-duration:0.4s;transition-duration:0.4s;cursor:pointer;} "
2018-04-23 10:37:46 +01:00
" button:hover{background-color:#0e70a4;} "
" .bred{background-color:#d43535;} "
" .bred:hover{background-color:#931f1f;} "
" .bgrn{background-color:#47c266;} "
" .bgrn:hover{background-color:#5aaf6f;} "
2017-11-29 16:34:32 +00:00
" a{text-decoration:none;} "
2017-08-16 16:05:36 +01:00
" .p{float:left;text-align:left;} "
" .q{float:right;text-align:right;} "
2017-03-08 15:20:45 +00:00
" </style> "
" </head> "
" <body> "
2017-08-16 16:05:36 +01:00
" <div style='text-align:left;display:inline-block;min-width:340px;'> "
2017-09-30 12:32:53 +01:00
# ifdef BE_MINIMAL
" <div style='text-align:center;color:red;'><h3> " D_MINIMAL_FIRMWARE_PLEASE_UPGRADE " </h3></div> "
# endif
2018-01-24 16:31:20 +00:00
# ifdef LANGUAGE_MODULE_NAME
" <div style='text-align:center;'><h3> " D_MODULE " {ha</h3><h2>{h}</h2></div> " ;
# else
2017-10-25 13:27:30 +01:00
" <div style='text-align:center;'><h3>{ha " D_MODULE " </h3><h2>{h}</h2></div> " ;
2018-01-24 16:31:20 +00:00
# endif
2017-03-08 15:20:45 +00:00
const char HTTP_SCRIPT_CONSOL [ ] PROGMEM =
2017-02-24 17:17:48 +00:00
" var sn=0; " // Scroll position
2018-01-30 13:14:55 +00:00
" var id=0; " // Get most of weblog initially
2017-02-28 15:01:48 +00:00
" function l(p){ " // Console log and command service
" var c,o,t; "
" clearTimeout(lt); "
" o=''; "
2018-03-28 17:01:38 +01:00
" t=eb('t1'); "
2017-02-28 15:01:48 +00:00
" if(p==1){ "
2018-03-28 17:01:38 +01:00
" c=eb('c1'); "
2017-09-08 11:57:08 +01:00
" o='&c1='+encodeURIComponent(c.value); "
2017-02-28 15:01:48 +00:00
" c.value=''; "
" t.scrollTop=sn; "
" } "
" if(t.scrollTop>=sn){ " // User scrolled back so no updates
2017-02-24 17:17:48 +00:00
" if(x!=null){x.abort();} " // Abort if no response within 2 seconds (happens on restart 1)
" x=new XMLHttpRequest(); "
2017-01-28 13:41:01 +00:00
" x.onreadystatechange=function(){ "
" if(x.readyState==4&&x.status==200){ "
2017-02-24 17:17:48 +00:00
" var z,d; "
" d=x.responseXML; "
" id=d.getElementsByTagName('i')[0].childNodes[0].nodeValue; "
2017-02-28 15:01:48 +00:00
" if(d.getElementsByTagName('j')[0].childNodes[0].nodeValue==0){t.value='';} "
2017-02-24 17:17:48 +00:00
" z=d.getElementsByTagName('l')[0].childNodes; "
2017-11-17 16:52:31 +00:00
" if(z.length>0){t.value+=decodeURIComponent(z[0].nodeValue);} "
2017-02-28 15:01:48 +00:00
" t.scrollTop=99999; "
" sn=t.scrollTop; "
2017-01-28 13:41:01 +00:00
" } "
" }; "
2017-02-28 15:01:48 +00:00
" x.open('GET','ax?c2='+id+o,true); "
2017-01-28 13:41:01 +00:00
" x.send(); "
" } "
2017-02-28 15:01:48 +00:00
" lt=setTimeout(l,2345); "
2017-02-24 17:17:48 +00:00
" return false; "
" } "
2017-03-08 15:20:45 +00:00
" </script> " ;
2017-08-19 15:29:51 +01:00
const char HTTP_SCRIPT_MODULE1 [ ] PROGMEM =
2017-03-29 17:42:05 +01:00
" var os; "
" function sk(s,g){ "
" var o=os.replace( \" value=' \" +s+ \" ' \" , \" selected value=' \" +s+ \" ' \" ); "
2018-03-28 17:01:38 +01:00
" eb('g'+g).innerHTML=o; "
2017-03-29 17:42:05 +01:00
" } "
" function sl(){ "
" var o0= \" " ;
2017-08-19 15:29:51 +01:00
const char HTTP_SCRIPT_MODULE2 [ ] PROGMEM =
2017-10-23 11:18:15 +01:00
" }1'%d'>%02d %s}2 " ; // "}1" and "}2" means do not use "}x" in Module name and Sensor name
2017-08-19 15:29:51 +01:00
const char HTTP_SCRIPT_MODULE3 [ ] PROGMEM =
" \" ; "
" os=o0.replace(/}1/g, \" <option value= \" ).replace(/}2/g, \" </option> \" ); " ;
2017-10-23 11:18:15 +01:00
const char HTTP_SCRIPT_INFO_BEGIN [ ] PROGMEM =
" function i(){ "
" var s,o= \" " ;
const char HTTP_SCRIPT_INFO_END [ ] PROGMEM =
" \" ; " // "}1" and "}2" means do not use "}x" in Information text
" s=o.replace(/}1/g, \" </td></tr><tr><th> \" ).replace(/}2/g, \" </th><td> \" ); "
2018-03-28 17:01:38 +01:00
" eb('i').innerHTML=s; "
2017-10-23 11:18:15 +01:00
" } "
" </script> " ;
2017-09-02 13:37:02 +01:00
const char HTTP_MSG_SLIDER1 [ ] PROGMEM =
" <div><span class='p'> " D_COLDLIGHT " </span><span class='q'> " D_WARMLIGHT " </span></div> "
" <div><input type='range' min='153' max='500' value='%d' onchange='lc(value)'></div> " ;
const char HTTP_MSG_SLIDER2 [ ] PROGMEM =
" <div><span class='p'> " D_DARKLIGHT " </span><span class='q'> " D_BRIGHTLIGHT " </span></div> "
" <div><input type='range' min='1' max='100' value='%d' onchange='lb(value)'></div> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_MSG_RSTRT [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <br/><div style='text-align:center;'> " D_DEVICE_WILL_RESTART " </div><br/> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_BTN_MENU1 [ ] PROGMEM =
2017-09-30 12:32:53 +01:00
# ifndef BE_MINIMAL
2017-09-02 13:37:02 +01:00
" <br/><form action='cn' method='get'><button> " D_CONFIGURATION " </button></form> "
" <br/><form action='in' method='get'><button> " D_INFORMATION " </button></form> "
2017-09-30 12:32:53 +01:00
# endif
2017-09-02 13:37:02 +01:00
" <br/><form action='up' method='get'><button> " D_FIRMWARE_UPGRADE " </button></form> "
" <br/><form action='cs' method='get'><button> " D_CONSOLE " </button></form> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_BTN_RSTRT [ ] PROGMEM =
2018-04-23 10:37:46 +01:00
" <br/><form action='rb' method='get' onsubmit='return confirm( \" " D_CONFIRM_RESTART " \" );'><button class='button bred'> " D_RESTART " </button></form> " ;
2018-03-31 16:29:00 +01:00
const char HTTP_BTN_MENU_MODULE [ ] PROGMEM =
" <br/><form action='md' method='get'><button> " D_CONFIGURE_MODULE " </button></form> " ;
2018-04-11 09:11:20 +01:00
# if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
2018-03-31 16:29:00 +01:00
const char HTTP_BTN_MENU_TIMER [ ] PROGMEM =
" <br/><form action='tm' method='get'><button> " D_CONFIGURE_TIMER " </button></form> " ;
2018-04-11 09:11:20 +01:00
# endif // USE_TIMERS and USE_TIMERS_WEB
2018-03-31 16:29:00 +01:00
const char HTTP_BTN_MENU_WIFI [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <br/><form action='w0' method='get'><button> " D_CONFIGURE_WIFI " </button></form> " ;
2018-03-31 16:29:00 +01:00
const char HTTP_BTN_MENU_MQTT [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <br/><form action='mq' method='get'><button> " D_CONFIGURE_MQTT " </button></form> "
2017-01-28 13:41:01 +00:00
# ifdef USE_DOMOTICZ
2017-09-02 13:37:02 +01:00
" <br/><form action='dm' method='get'><button> " D_CONFIGURE_DOMOTICZ " </button></form> "
2017-01-28 13:41:01 +00:00
# endif // USE_DOMOTICZ
" " ;
const char HTTP_BTN_MENU4 [ ] PROGMEM =
2018-04-17 14:34:18 +01:00
# ifdef USE_KNX
" <br/><form action='kn' method='get'><button> " D_CONFIGURE_KNX " </button></form> "
# endif // USE_KNX
2017-09-02 13:37:02 +01:00
" <br/><form action='lg' method='get'><button> " D_CONFIGURE_LOGGING " </button></form> "
" <br/><form action='co' method='get'><button> " D_CONFIGURE_OTHER " </button></form> "
2017-10-14 10:26:49 +01:00
" <br/> "
2018-04-23 10:37:46 +01:00
" <br/><form action='rt' method='get' onsubmit='return confirm( \" " D_CONFIRM_RESET_CONFIGURATION " \" );'><button class='button bred'> " D_RESET_CONFIGURATION " </button></form> "
2017-09-02 13:37:02 +01:00
" <br/><form action='dl' method='get'><button> " D_BACKUP_CONFIGURATION " </button></form> "
" <br/><form action='rs' method='get'><button> " D_RESTORE_CONFIGURATION " </button></form> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_BTN_MAIN [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <br/><br/><form action='.' method='get'><button> " D_MAIN_MENU " </button></form> " ;
2018-01-20 11:12:39 +00:00
const char HTTP_FORM_LOGIN [ ] PROGMEM =
" <form method='post' action='/'> "
" <br/><b> " D_USER " </b><br/><input name='USER1' placeholder=' " D_USER " '><br/> "
" <br/><b> " D_PASSWORD " </b><br/><input name='PASS1' type='password' placeholder=' " D_PASSWORD " '><br/> "
" <br/> "
" <br/><button> " D_OK " </button></form> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_BTN_CONF [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <br/><br/><form action='cn' method='get'><button> " D_CONFIGURATION " </button></form> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_MODULE [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_MODULE_PARAMETERS " </b></legend><form method='get' action='sv'> "
2018-03-28 17:01:38 +01:00
" <input id='w' name='w' value='6,1' hidden> "
2017-10-25 13:27:30 +01:00
" <br/><b> " D_MODULE_TYPE " </b> ({mt)<br/><select id='g99' name='g99'></select><br/> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_LNK_ITEM [ ] PROGMEM =
2017-06-04 16:40:27 +01:00
" <div><a href='#p' onclick='c(this)'>{v}</a> <span class='q'>{i} {r}%</span></div> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_LNK_SCAN [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <div><a href='/w1'> " D_SCAN_FOR_WIFI_NETWORKS " </a></div><br/> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_WIFI [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_WIFI_PARAMETERS " </b></legend><form method='get' action='sv'> "
2018-03-28 17:01:38 +01:00
" <input id='w' name='w' value='1,1' hidden> "
2017-10-25 13:27:30 +01:00
" <br/><b> " D_AP1_SSID " </b> ( " STA_SSID1 " )<br/><input id='s1' name='s1' placeholder=' " STA_SSID1 " ' value='{s1'><br/> "
2018-04-21 17:17:24 +01:00
" <br/><b> " D_AP1_PASSWORD " </b><br/><input id='p1' name='p1' type='password' placeholder=' " D_AP1_PASSWORD " ' value=' " D_ASTERIX " '><br/> "
2017-10-25 13:27:30 +01:00
" <br/><b> " D_AP2_SSID " </b> ( " STA_SSID2 " )<br/><input id='s2' name='s2' placeholder=' " STA_SSID2 " ' value='{s2'><br/> "
2018-04-21 17:17:24 +01:00
" <br/><b> " D_AP2_PASSWORD " </b><br/><input id='p2' name='p2' type='password' placeholder=' " D_AP2_PASSWORD " ' value=' " D_ASTERIX " '><br/> "
2017-10-25 13:27:30 +01:00
" <br/><b> " D_HOSTNAME " </b> ( " WIFI_HOSTNAME " )<br/><input id='h' name='h' placeholder=' " WIFI_HOSTNAME " ' value='{h1'><br/> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_MQTT [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_MQTT_PARAMETERS " </b></legend><form method='get' action='sv'> "
2018-03-28 17:01:38 +01:00
" <input id='w' name='w' value='2,1' hidden> "
2017-10-25 13:27:30 +01:00
" <br/><b> " D_HOST " </b> ( " MQTT_HOST " )<br/><input id='mh' name='mh' placeholder=' " MQTT_HOST " ' value='{m1'><br/> "
" <br/><b> " D_PORT " </b> ( " STR ( MQTT_PORT ) " )<br/><input id='ml' name='ml' placeholder=' " STR ( MQTT_PORT ) " ' value='{m2'><br/> "
" <br/><b> " D_CLIENT " </b> ({m0)<br/><input id='mc' name='mc' placeholder=' " MQTT_CLIENT_ID " ' value='{m3'><br/> "
" <br/><b> " D_USER " </b> ( " MQTT_USER " )<br/><input id='mu' name='mu' placeholder=' " MQTT_USER " ' value='{m4'><br/> "
" <br/><b> " D_PASSWORD " </b><br/><input id='mp' name='mp' type='password' placeholder=' " MQTT_PASS " ' value='{m5'><br/> "
" <br/><b> " D_TOPIC " </b> = %topic% ( " MQTT_TOPIC " )<br/><input id='mt' name='mt' placeholder=' " MQTT_TOPIC " ' value='{m6'><br/> "
" <br/><b> " D_FULL_TOPIC " </b> ( " MQTT_FULLTOPIC " )<br/><input id='mf' name='mf' placeholder=' " MQTT_FULLTOPIC " ' value='{m7'><br/> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_LOG1 [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_LOGGING_PARAMETERS " </b></legend><form method='get' action='sv'> "
2018-03-28 17:01:38 +01:00
" <input id='w' name='w' value='3,0' hidden> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_LOG2 [ ] PROGMEM =
2018-01-07 13:56:23 +00:00
" <br/><b>{b0</b> ({b1)<br/><select id='{b2' name='{b2'> "
2017-09-02 13:37:02 +01:00
" <option{a0value='0'>0 " D_NONE " </option> "
" <option{a1value='1'>1 " D_ERROR " </option> "
" <option{a2value='2'>2 " D_INFO " </option> "
" <option{a3value='3'>3 " D_DEBUG " </option> "
" <option{a4value='4'>4 " D_MORE_DEBUG " </option> "
2017-10-18 17:22:34 +01:00
" </select><br/> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_LOG3 [ ] PROGMEM =
2017-10-25 13:27:30 +01:00
" <br/><b> " D_SYSLOG_HOST " </b> ( " SYS_LOG_HOST " )<br/><input id='lh' name='lh' placeholder=' " SYS_LOG_HOST " ' value='{l2'><br/> "
" <br/><b> " D_SYSLOG_PORT " </b> ( " STR ( SYS_LOG_PORT ) " )<br/><input id='lp' name='lp' placeholder=' " STR ( SYS_LOG_PORT ) " ' value='{l3'><br/> "
" <br/><b> " D_TELEMETRY_PERIOD " </b> ( " STR ( TELE_PERIOD ) " )<br/><input id='lt' name='lt' placeholder=' " STR ( TELE_PERIOD ) " ' value='{l4'><br/> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_OTHER [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_OTHER_PARAMETERS " </b></legend><form method='get' action='sv'> "
2018-03-28 17:01:38 +01:00
" <input id='w' name='w' value='5,1' hidden> "
2018-04-21 17:17:24 +01:00
" <br/><b> " D_WEB_ADMIN_PASSWORD " </b><br/><input id='p1' name='p1' type='password' placeholder=' " D_WEB_ADMIN_PASSWORD " ' value=' " D_ASTERIX " '><br/> "
2017-10-25 13:27:30 +01:00
" <br/><input style='width:10%;' id='b1' name='b1' type='checkbox'{r1><b> " D_MQTT_ENABLE " </b><br/> " ;
2017-09-30 12:32:53 +01:00
const char HTTP_FORM_OTHER2 [ ] PROGMEM =
2017-10-14 10:26:49 +01:00
" <br/><b> " D_FRIENDLY_NAME " {1</b> ({2)<br/><input id='a{1' name='a{1' placeholder='{2' value='{3'><br/> " ;
2017-01-29 20:36:12 +00:00
# ifdef USE_EMULATION
2017-06-04 16:40:27 +01:00
const char HTTP_FORM_OTHER3a [ ] PROGMEM =
2017-09-02 13:37:02 +01:00
" <br/><fieldset><legend><b> " D_EMULATION " </b></legend> " ;
2017-06-04 16:40:27 +01:00
const char HTTP_FORM_OTHER3b [ ] PROGMEM =
2018-01-20 11:12:39 +00:00
" <br/><input style='width:10%;' id='r{1' name='b2' type='radio' value='{1'{2><b>{3</b>{4 " ; // Different id only used for labels
# endif // USE_EMULATION
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_END [ ] PROGMEM =
2018-04-23 10:37:46 +01:00
" <br/><button type='submit' class='button bgrn'> " D_SAVE " </button></form></fieldset> " ;
2017-02-10 16:03:34 +00:00
const char HTTP_FORM_RST [ ] PROGMEM =
" <div id='f1' name='f1' style='display:block;'> "
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_RESTORE_CONFIGURATION " </b></legend> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_UPG [ ] PROGMEM =
" <div id='f1' name='f1' style='display:block;'> "
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_UPGRADE_BY_WEBSERVER " </b></legend> "
2017-06-16 13:33:49 +01:00
" <form method='get' action='u1'> "
2017-10-25 13:27:30 +01:00
" <br/> " D_OTA_URL " <br/><input id='o' name='o' placeholder='OTA_URL' value='{o1'><br/> "
2017-09-02 13:37:02 +01:00
" <br/><button type='submit'> " D_START_UPGRADE " </button></form> "
2017-01-28 13:41:01 +00:00
" </fieldset><br/><br/> "
2017-09-02 13:37:02 +01:00
" <fieldset><legend><b> " D_UPGRADE_BY_FILE_UPLOAD " </b></legend> " ;
2017-05-13 12:02:10 +01:00
const char HTTP_FORM_RST_UPG [ ] PROGMEM =
2017-01-28 13:41:01 +00:00
" <form method='post' action='u2' enctype='multipart/form-data'> "
" <br/><input type='file' name='u2'><br/> "
2018-03-28 17:01:38 +01:00
" <br/><button type='submit' onclick='eb( \" f1 \" ).style.display= \" none \" ;eb( \" f2 \" ).style.display= \" block \" ;this.form.submit();'> " D_START " {r1</button></form> "
2017-01-28 13:41:01 +00:00
" </fieldset> "
" </div> "
2017-09-02 13:37:02 +01:00
" <div id='f2' name='f2' style='display:none;text-align:center;'><b> " D_UPLOAD_STARTED " ...</b></div> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_FORM_CMND [ ] PROGMEM =
2018-01-18 15:19:28 +00:00
" <br/><textarea readonly id='t1' name='t1' cols='340' wrap='off'></textarea><br/><br/> "
2017-02-28 15:01:48 +00:00
" <form method='get' onsubmit='return l(1);'> "
2017-10-14 10:26:49 +01:00
" <input id='c1' name='c1' placeholder=' " D_ENTER_COMMAND " ' autofocus><br/> "
// "<br/><button type='submit'>Send command</button>"
2017-01-28 13:41:01 +00:00
" </form> " ;
2017-04-03 15:38:15 +01:00
const char HTTP_TABLE100 [ ] PROGMEM =
2018-01-18 15:19:28 +00:00
" <table style='width:100%'> " ;
2017-01-28 13:41:01 +00:00
const char HTTP_COUNTER [ ] PROGMEM =
" <br/><div id='t' name='t' style='text-align:center;'></div> " ;
const char HTTP_END [ ] PROGMEM =
2017-11-29 16:34:32 +00:00
" <br/> "
2018-01-10 13:10:25 +00:00
" <div style='text-align:right;font-size:11px;'><hr/><a href=' " D_WEBLINK " ' target='_blank' style='color:#aaa;'> " D_PROGRAMNAME " {mv " D_BY " " D_AUTHOR " </a></div> "
2017-01-28 13:41:01 +00:00
" </div> "
" </body> "
" </html> " ;
2018-07-01 14:06:44 +01:00
const char HTTP_DEVICE_CONTROL [ ] PROGMEM = " <td style='width:%d%%'><button onclick='la( \" ?o=%d \" );'>%s%s</button></td> " ;
const char HTTP_DEVICE_STATE [ ] PROGMEM = " %s<td style='width:%d{c}%s;font-size:%dpx'>%s</div></td> " ; // {c} = %'><div style='text-align:center;font-weight:
2017-07-15 14:07:30 +01:00
const char HDR_CTYPE_PLAIN [ ] PROGMEM = " text/plain " ;
const char HDR_CTYPE_HTML [ ] PROGMEM = " text/html " ;
const char HDR_CTYPE_XML [ ] PROGMEM = " text/xml " ;
const char HDR_CTYPE_JSON [ ] PROGMEM = " application/json " ;
const char HDR_CTYPE_STREAM [ ] PROGMEM = " application/octet-stream " ;
2017-05-11 16:47:34 +01:00
2017-01-28 13:41:01 +00:00
# define DNS_PORT 53
2017-10-18 17:22:34 +01:00
enum HttpOptions { HTTP_OFF , HTTP_USER , HTTP_ADMIN , HTTP_MANAGER } ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
DNSServer * DnsServer ;
ESP8266WebServer * WebServer ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
boolean remove_duplicate_access_points = true ;
int minimum_signal_quality = - 1 ;
uint8_t webserver_state = HTTP_OFF ;
uint8_t upload_error = 0 ;
uint8_t upload_file_type ;
uint8_t upload_progress_dot_count ;
2018-05-01 17:02:45 +01:00
uint8_t config_block_count = 0 ;
uint8_t config_xor_on = 0 ;
2018-05-06 17:35:31 +01:00
uint8_t config_xor_on_set = CONFIG_FILE_XOR ;
2017-01-28 13:41:01 +00:00
2018-01-30 13:14:55 +00:00
// Helper function to avoid code duplication (saves 4k Flash)
static void WebGetArg ( const char * arg , char * out , size_t max )
{
String s = WebServer - > arg ( arg ) ;
strncpy ( out , s . c_str ( ) , max ) ;
out [ max - 1 ] = ' \0 ' ; // Ensure terminating NUL
}
2018-05-28 14:52:42 +01:00
void ShowWebSource ( int source )
{
if ( ( source > 0 ) & & ( source < SRC_MAX ) ) {
char stemp1 [ 20 ] ;
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " SRC: %s from %s " ) , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , source , kCommandSource ) , WebServer - > client ( ) . remoteIP ( ) . toString ( ) . c_str ( ) ) ;
AddLog ( LOG_LEVEL_DEBUG ) ;
}
}
void ExecuteWebCommand ( char * svalue , int source )
{
ShowWebSource ( source ) ;
ExecuteCommand ( svalue , SRC_IGNORE ) ;
}
2017-10-18 17:22:34 +01:00
void StartWebserver ( int type , IPAddress ipweb )
2017-01-28 13:41:01 +00:00
{
2017-10-18 17:22:34 +01:00
if ( ! webserver_state ) {
if ( ! WebServer ) {
WebServer = new ESP8266WebServer ( ( HTTP_MANAGER = = type ) ? 80 : WEB_PORT ) ;
WebServer - > on ( " / " , HandleRoot ) ;
2018-07-06 17:00:50 +01:00
WebServer - > on ( " /up " , HandleUpgradeFirmware ) ;
WebServer - > on ( " /u1 " , HandleUpgradeFirmwareStart ) ; // OTA
WebServer - > on ( " /u2 " , HTTP_POST , HandleUploadDone , HandleUploadLoop ) ;
WebServer - > on ( " /cs " , HandleConsole ) ;
WebServer - > on ( " /ax " , HandleAjaxConsoleRefresh ) ;
WebServer - > on ( " /ay " , HandleAjaxStatusRefresh ) ;
WebServer - > on ( " /rb " , HandleRestart ) ;
# ifndef BE_MINIMAL
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /cn " , HandleConfiguration ) ;
WebServer - > on ( " /md " , HandleModuleConfiguration ) ;
2018-04-11 09:11:20 +01:00
# if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
2018-03-28 17:01:38 +01:00
WebServer - > on ( " /tm " , HandleTimerConfiguration ) ;
2018-04-11 09:11:20 +01:00
# endif // USE_TIMERS and USE_TIMERS_WEB
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /w1 " , HandleWifiConfigurationWithScan ) ;
WebServer - > on ( " /w0 " , HandleWifiConfiguration ) ;
if ( Settings . flag . mqtt_enabled ) {
WebServer - > on ( " /mq " , HandleMqttConfiguration ) ;
2017-01-28 13:41:01 +00:00
# ifdef USE_DOMOTICZ
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /dm " , HandleDomoticzConfiguration ) ;
2017-01-28 13:41:01 +00:00
# endif // USE_DOMOTICZ
}
2018-04-17 14:34:18 +01:00
# ifdef USE_KNX
WebServer - > on ( " /kn " , HandleKNXConfiguration ) ;
# endif // USE_KNX
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /lg " , HandleLoggingConfiguration ) ;
WebServer - > on ( " /co " , HandleOtherConfiguration ) ;
WebServer - > on ( " /dl " , HandleBackupConfiguration ) ;
WebServer - > on ( " /sv " , HandleSaveSettings ) ;
WebServer - > on ( " /rs " , HandleRestoreConfiguration ) ;
WebServer - > on ( " /rt " , HandleResetConfiguration ) ;
2018-02-16 16:35:51 +00:00
WebServer - > on ( " /u2 " , HTTP_OPTIONS , HandlePreflightRequest ) ;
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /cm " , HandleHttpCommand ) ;
WebServer - > on ( " /in " , HandleInformation ) ;
2017-01-29 20:36:12 +00:00
# ifdef USE_EMULATION
2017-11-11 11:33:30 +00:00
if ( EMUL_WEMO = = Settings . flag2 . emulation ) {
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /upnp/control/basicevent1 " , HTTP_POST , HandleUpnpEvent ) ;
WebServer - > on ( " /eventservice.xml " , HandleUpnpService ) ;
2018-01-02 15:08:27 +00:00
WebServer - > on ( " /metainfoservice.xml " , HandleUpnpMetaService ) ;
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /setup.xml " , HandleUpnpSetupWemo ) ;
2017-01-29 20:36:12 +00:00
}
2017-11-11 11:33:30 +00:00
if ( EMUL_HUE = = Settings . flag2 . emulation ) {
2017-10-18 17:22:34 +01:00
WebServer - > on ( " /description.xml " , HandleUpnpSetupHue ) ;
2017-02-21 17:14:33 +00:00
}
2017-01-29 20:36:12 +00:00
# endif // USE_EMULATION
2018-07-06 17:00:50 +01:00
# endif // Not BE_MINIMAL
WebServer - > on ( " /fwlink " , HandleRoot ) ; // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
2017-10-18 17:22:34 +01:00
WebServer - > onNotFound ( HandleNotFound ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
reset_web_log_flag = 0 ;
WebServer - > begin ( ) ; // Web server start
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
if ( webserver_state ! = type ) {
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s " ) ,
2017-10-18 17:22:34 +01:00
my_hostname , ( mdns_begun ) ? " .local " : " " , ipweb . toString ( ) . c_str ( ) ) ;
AddLog ( LOG_LEVEL_INFO ) ;
}
2018-04-20 13:31:09 +01:00
if ( type ) { webserver_state = type ; }
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void StopWebserver ( )
2017-01-28 13:41:01 +00:00
{
2017-10-18 17:22:34 +01:00
if ( webserver_state ) {
WebServer - > close ( ) ;
webserver_state = HTTP_OFF ;
AddLog_P ( LOG_LEVEL_INFO , PSTR ( D_LOG_HTTP D_WEBSERVER_STOPPED ) ) ;
2017-01-28 13:41:01 +00:00
}
}
2017-10-18 17:22:34 +01:00
void WifiManagerBegin ( )
2017-01-28 13:41:01 +00:00
{
// setup AP
2017-04-25 17:24:42 +01:00
if ( ( WL_CONNECTED = = WiFi . status ( ) ) & & ( static_cast < uint32_t > ( WiFi . localIP ( ) ) ! = 0 ) ) {
2017-01-28 13:41:01 +00:00
WiFi . mode ( WIFI_AP_STA ) ;
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION ) ) ;
2017-01-28 13:41:01 +00:00
} else {
WiFi . mode ( WIFI_AP ) ;
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_WIFIMANAGER_SET_ACCESSPOINT ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
StopWebserver ( ) ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
DnsServer = new DNSServer ( ) ;
WiFi . softAP ( my_hostname ) ;
2017-01-28 13:41:01 +00:00
delay ( 500 ) ; // Without delay I've seen the IP address blank
/* Setup the DNS server redirecting all the domains to the apIP */
2017-10-18 17:22:34 +01:00
DnsServer - > setErrorReplyCode ( DNSReplyCode : : NoError ) ;
DnsServer - > start ( DNS_PORT , " * " , WiFi . softAPIP ( ) ) ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
StartWebserver ( HTTP_MANAGER , WiFi . softAPIP ( ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void PollDnsWebserver ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( DnsServer ) { DnsServer - > processNextRequest ( ) ; }
if ( WebServer ) { WebServer - > handleClient ( ) ; }
2017-01-28 13:41:01 +00:00
}
2018-01-26 14:21:57 +00:00
/*********************************************************************************************/
2017-10-18 17:22:34 +01:00
void SetHeader ( )
2017-07-15 14:07:30 +01:00
{
2017-10-18 17:22:34 +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 " ) ) ;
2018-01-13 14:53:02 +00:00
# ifndef ARDUINO_ESP8266_RELEASE_2_3_0
WebServer - > sendHeader ( F ( " Access-Control-Allow-Origin " ) , F ( " * " ) ) ;
# endif
2017-07-15 14:07:30 +01:00
}
2018-01-20 14:57:11 +00:00
void ShowPage ( String & page , bool auth )
2017-01-28 13:41:01 +00:00
{
2018-01-20 11:12:39 +00:00
if ( auth & & ( Settings . web_password [ 0 ] ! = 0 ) & & ! WebServer - > authenticate ( WEB_USERNAME , Settings . web_password ) ) {
2017-10-18 17:22:34 +01:00
return WebServer - > requestAuthentication ( ) ;
2017-02-21 17:14:33 +00:00
}
2018-01-20 11:12:39 +00:00
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {ha " ) , my_module . name ) ;
2017-10-18 17:22:34 +01:00
page . replace ( F ( " {h} " ) , Settings . friendlyname [ 0 ] ) ;
if ( HTTP_MANAGER = = webserver_state ) {
if ( WifiConfigCounter ( ) ) {
2017-05-10 13:19:36 +01:00
page . replace ( F ( " <body> " ) , F ( " <body onload='u()'> " ) ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_COUNTER ) ;
}
}
page + = FPSTR ( HTTP_END ) ;
2018-01-10 13:10:25 +00:00
page . replace ( F ( " {mv " ) , my_version ) ;
2017-10-18 17:22:34 +01:00
SetHeader ( ) ;
2018-06-28 11:25:50 +01:00
ShowFreeMem ( PSTR ( " ShowPage " ) ) ;
2017-10-18 17:22:34 +01:00
WebServer - > send ( 200 , FPSTR ( HDR_CTYPE_HTML ) , page ) ;
2018-01-20 11:12:39 +00:00
}
2018-01-20 14:57:11 +00:00
void ShowPage ( String & page )
{
ShowPage ( page , true ) ;
}
2018-01-24 16:31:20 +00:00
/*********************************************************************************************/
2018-01-20 11:12:39 +00:00
void HandleWifiLogin ( )
{
String page = FPSTR ( HTTP_HEAD ) ;
page . replace ( F ( " {v} " ) , FPSTR ( D_CONFIGURE_WIFI ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2018-01-20 11:12:39 +00:00
page + = FPSTR ( HTTP_FORM_LOGIN ) ;
ShowPage ( page , false ) ; // false means show page no matter if the client has or has not credentials
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleRoot ( )
2017-01-28 13:41:01 +00:00
{
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_MAIN_MENU ) ;
2017-01-28 13:41:01 +00:00
2018-04-20 13:31:09 +01:00
if ( CaptivePortal ( ) ) { return ; } // If captive portal redirect instead of displaying the page.
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
if ( HTTP_MANAGER = = webserver_state ) {
2018-07-06 17:00:50 +01:00
# ifndef BE_MINIMAL
2018-01-20 11:12:39 +00:00
if ( ( Settings . web_password [ 0 ] ! = 0 ) & & ! ( WebServer - > hasArg ( " USER1 " ) ) & & ! ( WebServer - > hasArg ( " PASS1 " ) ) ) {
HandleWifiLogin ( ) ;
} else {
2018-01-30 13:14:55 +00:00
/*
char tmp1 [ 100 ] ;
WebGetArg ( " USER1 " , tmp1 , sizeof ( tmp1 ) ) ;
char tmp2 [ 100 ] ;
WebGetArg ( " PASS1 " , tmp2 , sizeof ( tmp2 ) ) ;
if ( ! ( Settings . web_password [ 0 ] ! = 0 ) | | ( ! ( ! strcmp ( tmp1 , WEB_USERNAME ) & & ! strcmp ( tmp2 , Settings . web_password ) ) ) ) {
*/
2018-01-20 11:12:39 +00:00
if ( ! ( Settings . web_password [ 0 ] ! = 0 ) | | ( ( WebServer - > arg ( " USER1 " ) = = WEB_USERNAME ) & & ( WebServer - > arg ( " PASS1 " ) = = Settings . web_password ) ) ) {
HandleWifiConfiguration ( ) ;
} else {
// wrong user and pass
HandleWifiLogin ( ) ;
}
}
2018-07-06 17:00:50 +01:00
# endif // Not BE_MINIMAL
2017-01-28 13:41:01 +00:00
} else {
2017-09-14 13:20:27 +01:00
char stemp [ 10 ] ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_MAIN_MENU ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-05-10 13:19:36 +01:00
page . replace ( F ( " <body> " ) , F ( " <body onload='la()'> " ) ) ;
2017-01-28 13:41:01 +00:00
2017-02-24 17:17:48 +00:00
page + = F ( " <div id='l1' name='l1'></div> " ) ;
2017-10-18 17:22:34 +01:00
if ( devices_present ) {
if ( light_type ) {
2017-10-25 13:27:30 +01:00
if ( ( LST_COLDWARM = = ( light_type & 7 ) ) | | ( LST_RGBWC = = ( light_type & 7 ) ) ) {
2018-01-26 14:21:57 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_MSG_SLIDER1 , LightGetColorTemp ( ) ) ;
page + = mqtt_data ;
2017-08-16 16:05:36 +01:00
}
2018-01-26 14:21:57 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_MSG_SLIDER2 , Settings . light_dimmer ) ;
page + = mqtt_data ;
2017-03-08 15:20:45 +00:00
}
2017-04-03 15:38:15 +01:00
page + = FPSTR ( HTTP_TABLE100 ) ;
page + = F ( " <tr> " ) ;
2018-07-01 14:06:44 +01:00
if ( SONOFF_IFAN02 = = Settings . module ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_DEVICE_CONTROL , 36 , 1 , D_BUTTON_TOGGLE , " " ) ;
2018-01-26 14:21:57 +00:00
page + = mqtt_data ;
2018-07-01 14:06:44 +01:00
for ( byte i = 0 ; i < 4 ; i + + ) {
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , i ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_DEVICE_CONTROL , 16 , i + 2 , stemp , " " ) ;
page + = mqtt_data ;
}
} else {
for ( byte idx = 1 ; idx < = devices_present ; idx + + ) {
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " %d " ) , idx ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_DEVICE_CONTROL ,
100 / devices_present , idx , ( devices_present < 5 ) ? D_BUTTON_TOGGLE : " " , ( devices_present > 1 ) ? stemp : " " ) ;
page + = mqtt_data ;
}
2017-01-28 13:41:01 +00:00
}
2017-02-24 17:17:48 +00:00
page + = F ( " </tr></table> " ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
if ( SONOFF_BRIDGE = = Settings . module ) {
2017-07-30 16:55:37 +01:00
page + = FPSTR ( HTTP_TABLE100 ) ;
page + = F ( " <tr> " ) ;
byte idx = 0 ;
for ( byte i = 0 ; i < 4 ; i + + ) {
2018-04-20 13:31:09 +01:00
if ( idx > 0 ) { page + = F ( " </tr><tr> " ) ; }
2017-07-30 16:55:37 +01:00
for ( byte j = 0 ; j < 4 ; j + + ) {
idx + + ;
2018-01-26 14:21:57 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " <td style='width:25%'><button onclick='la( \" ?k=%d \" );'>%d</button></td> " ) , idx , idx ) ;
page + = mqtt_data ;
2017-07-30 16:55:37 +01:00
}
}
page + = F ( " </tr></table> " ) ;
}
2017-09-02 13:37:02 +01:00
2017-10-18 17:22:34 +01:00
if ( HTTP_ADMIN = = webserver_state ) {
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_BTN_MENU1 ) ;
page + = FPSTR ( HTTP_BTN_RSTRT ) ;
}
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-02-24 17:17:48 +00:00
}
}
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
void HandleAjaxStatusRefresh ( )
2017-02-24 17:17:48 +00:00
{
2017-10-18 17:22:34 +01:00
char svalue [ 80 ] ;
2018-01-30 13:14:55 +00:00
char tmp [ 100 ] ;
2017-09-02 13:37:02 +01:00
2018-01-30 13:14:55 +00:00
WebGetArg ( " o " , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) {
2018-05-28 14:52:42 +01:00
ShowWebSource ( SRC_WEBGUI ) ;
2018-07-01 14:06:44 +01:00
uint8_t device = atoi ( tmp ) ;
if ( SONOFF_IFAN02 = = Settings . module ) {
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 ) ;
}
2018-06-30 18:09:48 +01:00
} else {
2018-07-01 14:06:44 +01:00
ExecuteCommandPower ( device , POWER_TOGGLE , SRC_IGNORE ) ;
2018-06-30 18:09:48 +01:00
}
2017-04-25 17:24:42 +01:00
}
2018-01-30 13:14:55 +00:00
WebGetArg ( " d " , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_DIMMER " %s " ) , tmp ) ;
2018-05-28 14:52:42 +01:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
2017-03-08 15:20:45 +00:00
}
2018-01-30 13:14:55 +00:00
WebGetArg ( " t " , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_COLORTEMPERATURE " %s " ) , tmp ) ;
2018-05-28 14:52:42 +01:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
2017-08-16 16:05:36 +01:00
}
2018-01-30 13:14:55 +00:00
WebGetArg ( " k " , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_RFKEY " %s " ) , tmp ) ;
2018-05-28 14:52:42 +01:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
2017-07-30 16:55:37 +01:00
}
2018-01-30 13:14:55 +00:00
2018-01-27 16:52:48 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " {t} " ) ) ;
XsnsCall ( FUNC_WEB_APPEND ) ;
if ( D_DECIMAL_SEPARATOR [ 0 ] ! = ' . ' ) {
2018-02-03 22:25:05 +00:00
for ( uint16_t i = 0 ; i < strlen ( mqtt_data ) ; i + + ) {
2018-01-27 16:52:48 +00:00
if ( ' . ' = = mqtt_data [ i ] ) {
mqtt_data [ i ] = D_DECIMAL_SEPARATOR [ 0 ] ;
}
}
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s</table> " ) , mqtt_data ) ;
if ( devices_present ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s{t}<tr> " ) , mqtt_data ) ;
uint8_t fsize = ( devices_present < 5 ) ? 70 - ( devices_present * 8 ) : 32 ;
2018-07-01 14:06:44 +01:00
if ( SONOFF_IFAN02 = = Settings . module ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_DEVICE_STATE ,
mqtt_data , 36 , ( bitRead ( power , 0 ) ) ? " bold " : " normal " , 54 , GetStateText ( bitRead ( power , 0 ) ) ) ;
uint8_t fanspeed = GetFanspeed ( ) ;
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %d " ) , fanspeed ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_DEVICE_STATE ,
mqtt_data , 64 , ( fanspeed ) ? " bold " : " normal " , 54 , ( fanspeed ) ? svalue : GetStateText ( 0 ) ) ;
} else {
for ( byte idx = 1 ; idx < = devices_present ; idx + + ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %d " ) , bitRead ( power , idx - 1 ) ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_DEVICE_STATE ,
mqtt_data , 100 / devices_present , ( bitRead ( power , idx - 1 ) ) ? " bold " : " normal " , fsize , ( devices_present < 5 ) ? GetStateText ( bitRead ( power , idx - 1 ) ) : svalue ) ;
}
2018-01-27 16:52:48 +00:00
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s</tr></table> " ) , mqtt_data ) ;
}
WebServer - > send ( 200 , FPSTR ( HDR_CTYPE_HTML ) , mqtt_data ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
boolean HttpUser ( )
2017-02-10 16:03:34 +00:00
{
2017-10-18 17:22:34 +01:00
boolean status = ( HTTP_USER = = webserver_state ) ;
2018-04-20 13:31:09 +01:00
if ( status ) { HandleRoot ( ) ; }
2017-02-10 16:03:34 +00:00
return status ;
}
2018-07-06 17:00:50 +01:00
# ifndef BE_MINIMAL
2017-10-18 17:22:34 +01:00
void HandleConfiguration ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURATION ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_CONFIGURATION ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2018-03-31 16:29:00 +01:00
page + = FPSTR ( HTTP_BTN_MENU_MODULE ) ;
2018-04-11 09:11:20 +01:00
# if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
2018-04-25 16:27:40 +01:00
# ifdef USE_RULES
page + = FPSTR ( HTTP_BTN_MENU_TIMER ) ;
# else
2018-04-20 13:31:09 +01:00
if ( devices_present ) { page + = FPSTR ( HTTP_BTN_MENU_TIMER ) ; }
2018-04-25 16:27:40 +01:00
# endif // USE_RULES
2018-04-11 09:11:20 +01:00
# endif // USE_TIMERS and USE_TIMERS_WEB
2018-03-31 16:29:00 +01:00
page + = FPSTR ( HTTP_BTN_MENU_WIFI ) ;
2018-04-20 13:31:09 +01:00
if ( Settings . flag . mqtt_enabled ) { page + = FPSTR ( HTTP_BTN_MENU_MQTT ) ; }
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_BTN_MENU4 ) ;
page + = FPSTR ( HTTP_BTN_MAIN ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleModuleConfiguration ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-08-18 17:04:49 +01:00
char stemp [ 20 ] ;
uint8_t midx ;
2017-09-02 13:37:02 +01:00
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_MODULE ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_CONFIGURE_MODULE ) ) ;
2018-01-26 14:21:57 +00:00
page + = FPSTR ( HTTP_SCRIPT_MODULE1 ) ;
2017-08-18 17:04:49 +01:00
for ( byte i = 0 ; i < MAXMODULE ; i + + ) {
2017-10-18 17:22:34 +01:00
midx = pgm_read_byte ( kNiceList + i ) ;
snprintf_P ( stemp , sizeof ( stemp ) , kModules [ midx ] . name ) ;
2018-01-26 14:21:57 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_SCRIPT_MODULE2 , midx , midx + 1 , stemp ) ;
page + = mqtt_data ;
2017-01-28 13:41:01 +00:00
}
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_SCRIPT_MODULE3 ) ;
2018-01-26 14:21:57 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " sk(%d,99);o0= \" " ) , Settings . module ) ; // g99
page + = mqtt_data ;
2018-01-24 16:31:20 +00:00
mytmplt cmodule ;
memcpy_P ( & cmodule , & kModules [ Settings . module ] , sizeof ( cmodule ) ) ;
2018-01-26 14:21:57 +00:00
2017-03-25 16:24:11 +00:00
for ( byte j = 0 ; j < GPIO_SENSOR_END ; j + + ) {
2017-10-18 17:22:34 +01:00
if ( ! GetUsedInModule ( j , cmodule . gp . io ) ) {
2018-02-01 15:18:00 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , HTTP_SCRIPT_MODULE2 , j , j , GetTextIndexed ( stemp , sizeof ( stemp ) , j , kSensorNames ) ) ;
2018-01-26 14:21:57 +00:00
page + = mqtt_data ;
2017-03-29 17:42:05 +01:00
}
2017-03-25 16:24:11 +00:00
}
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_SCRIPT_MODULE3 ) ;
2017-10-14 10:26:49 +01:00
2018-01-27 16:52:48 +00:00
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
if ( GPIO_USER = = cmodule . gp . io [ i ] ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " sk(%d,%d); " ) , my_module . gp . io [ i ] , i ) ; // g0 - g16
page + = mqtt_data ;
}
}
page + = F ( " } " ) ;
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
page . replace ( F ( " <body> " ) , F ( " <body onload='sl()'> " ) ) ;
page + = FPSTR ( HTTP_FORM_MODULE ) ;
2018-01-24 16:31:20 +00:00
snprintf_P ( stemp , sizeof ( stemp ) , kModules [ MODULE ] . name ) ;
2018-01-27 16:52:48 +00:00
page . replace ( F ( " {mt " ) , stemp ) ;
page + = F ( " <br/><table> " ) ;
2017-01-28 13:41:01 +00:00
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
2017-04-25 17:24:42 +01:00
if ( GPIO_USER = = cmodule . gp . io [ i ] ) {
2017-10-14 10:26:49 +01:00
snprintf_P ( stemp , 3 , PINS_WEMOS + i * 2 ) ;
2018-05-11 13:44:00 +01:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " <tr><td style='width:190px'>%s <b> " D_GPIO " %d</b> %s</td><td style='width:146px'><select id='g%d' name='g%d'></select></td></tr> " ) ,
2017-10-18 17:22:34 +01:00
( WEMOS = = Settings . module ) ? stemp : " " , i , ( 0 = = i ) ? D_SENSOR_BUTTON " 1 " : ( 1 = = i ) ? D_SERIAL_OUT : ( 3 = = i ) ? D_SERIAL_IN : ( 12 = = i ) ? D_SENSOR_RELAY " 1 " : ( 13 = = i ) ? D_SENSOR_LED " 1i " : ( 14 = = i ) ? D_SENSOR : " " , i , i ) ;
2018-01-26 14:21:57 +00:00
page + = mqtt_data ;
2017-01-28 13:41:01 +00:00
}
}
2018-01-24 16:31:20 +00:00
page + = F ( " </table> " ) ;
2018-01-26 14:21:57 +00:00
page + = FPSTR ( HTTP_FORM_END ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_BTN_CONF ) ;
2018-01-26 14:21:57 +00:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleWifiConfigurationWithScan ( )
2017-01-28 13:41:01 +00:00
{
2017-10-18 17:22:34 +01:00
HandleWifi ( true ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleWifiConfiguration ( )
2017-01-28 13:41:01 +00:00
{
2017-10-18 17:22:34 +01:00
HandleWifi ( false ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleWifi ( boolean scan )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_WIFI ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_CONFIGURE_WIFI ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-01-28 13:41:01 +00:00
if ( scan ) {
2017-01-29 20:36:12 +00:00
# ifdef USE_EMULATION
2017-10-18 17:22:34 +01:00
UdpDisconnect ( ) ;
2017-01-29 20:36:12 +00:00
# endif // USE_EMULATION
2017-01-28 13:41:01 +00:00
int n = WiFi . scanNetworks ( ) ;
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_SCAN_DONE ) ) ;
2017-01-28 13:41:01 +00:00
2017-04-25 17:24:42 +01:00
if ( 0 = = n ) {
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_WIFI , S_NO_NETWORKS_FOUND ) ;
2017-09-06 16:37:41 +01:00
page + = FPSTR ( S_NO_NETWORKS_FOUND ) ;
2017-09-02 13:37:02 +01:00
page + = F ( " . " D_REFRESH_TO_SCAN_AGAIN " . " ) ;
2017-01-28 13:41:01 +00:00
} else {
//sort networks
int indices [ n ] ;
for ( int i = 0 ; i < n ; i + + ) {
indices [ i ] = i ;
}
// RSSI SORT
for ( int i = 0 ; i < n ; i + + ) {
for ( int j = i + 1 ; j < n ; j + + ) {
if ( WiFi . RSSI ( indices [ j ] ) > WiFi . RSSI ( indices [ i ] ) ) {
std : : swap ( indices [ i ] , indices [ j ] ) ;
}
}
}
// remove duplicates ( must be RSSI sorted )
2017-10-18 17:22:34 +01:00
if ( remove_duplicate_access_points ) {
2017-01-28 13:41:01 +00:00
String cssid ;
for ( int i = 0 ; i < n ; i + + ) {
2018-04-20 13:31:09 +01:00
if ( - 1 = = indices [ i ] ) { continue ; }
2017-01-28 13:41:01 +00:00
cssid = WiFi . SSID ( indices [ i ] ) ;
for ( int j = i + 1 ; j < n ; j + + ) {
if ( cssid = = WiFi . SSID ( indices [ j ] ) ) {
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_WIFI D_DUPLICATE_ACCESSPOINT " %s " ) , WiFi . SSID ( indices [ j ] ) . c_str ( ) ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
2018-04-20 13:31:09 +01:00
indices [ j ] = - 1 ; // set dup aps to index -1
2017-01-28 13:41:01 +00:00
}
}
}
}
//display networks in page
for ( int i = 0 ; i < n ; i + + ) {
2018-04-20 13:31:09 +01:00
if ( - 1 = = indices [ i ] ) { continue ; } // skip dups
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_WIFI D_SSID " %s, " D_RSSI " %d " ) , WiFi . SSID ( indices [ i ] ) . c_str ( ) , WiFi . RSSI ( indices [ i ] ) ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
int quality = WifiGetRssiAsQuality ( WiFi . RSSI ( indices [ i ] ) ) ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
if ( minimum_signal_quality = = - 1 | | minimum_signal_quality < quality ) {
2017-01-28 13:41:01 +00:00
String item = FPSTR ( HTTP_LNK_ITEM ) ;
String rssiQ ;
rssiQ + = quality ;
2017-05-10 13:19:36 +01:00
item . replace ( F ( " {v} " ) , WiFi . SSID ( indices [ i ] ) ) ;
item . replace ( F ( " {r} " ) , rssiQ ) ;
2017-06-04 16:40:27 +01:00
uint8_t auth = WiFi . encryptionType ( indices [ i ] ) ;
2017-09-02 13:37:02 +01:00
item . replace ( F ( " {i} " ) , ( ENC_TYPE_WEP = = auth ) ? F ( D_WEP ) : ( ENC_TYPE_TKIP = = auth ) ? F ( D_WPA_PSK ) : ( ENC_TYPE_CCMP = = auth ) ? F ( D_WPA2_PSK ) : ( ENC_TYPE_AUTO = = auth ) ? F ( D_AUTO ) : F ( " " ) ) ;
2017-01-28 13:41:01 +00:00
page + = item ;
delay ( 0 ) ;
} else {
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_WIFI D_SKIPPING_LOW_QUALITY ) ) ;
2017-01-28 13:41:01 +00:00
}
}
page + = " <br/> " ;
}
} else {
page + = FPSTR ( HTTP_LNK_SCAN ) ;
}
page + = FPSTR ( HTTP_FORM_WIFI ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {h1 " ) , Settings . hostname ) ;
page . replace ( F ( " {s1 " ) , Settings . sta_ssid [ 0 ] ) ;
page . replace ( F ( " {s2 " ) , Settings . sta_ssid [ 1 ] ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_END ) ;
2017-10-18 17:22:34 +01:00
if ( HTTP_MANAGER = = webserver_state ) {
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_BTN_RSTRT ) ;
} else {
page + = FPSTR ( HTTP_BTN_CONF ) ;
}
2018-01-20 11:12:39 +00:00
// ShowPage(page);
ShowPage ( page , ! ( HTTP_MANAGER = = webserver_state ) ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleMqttConfiguration ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_MQTT ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_CONFIGURE_MQTT ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_MQTT ) ;
2017-10-18 17:22:34 +01:00
char str [ sizeof ( Settings . mqtt_client ) ] ;
2018-03-29 12:03:13 +01:00
page . replace ( F ( " {m0 " ) , Format ( str , MQTT_CLIENT_ID , sizeof ( Settings . mqtt_client ) ) ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {m1 " ) , Settings . mqtt_host ) ;
page . replace ( F ( " {m2 " ) , String ( Settings . mqtt_port ) ) ;
page . replace ( F ( " {m3 " ) , Settings . mqtt_client ) ;
page . replace ( F ( " {m4 " ) , ( Settings . mqtt_user [ 0 ] = = ' \0 ' ) ? " 0 " : Settings . mqtt_user ) ;
page . replace ( F ( " {m5 " ) , ( Settings . mqtt_pwd [ 0 ] = = ' \0 ' ) ? " 0 " : Settings . mqtt_pwd ) ;
page . replace ( F ( " {m6 " ) , Settings . mqtt_topic ) ;
page . replace ( F ( " {m7 " ) , Settings . mqtt_fulltopic ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_END ) ;
page + = FPSTR ( HTTP_BTN_CONF ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleLoggingConfiguration ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_LOGGING ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_CONFIGURE_LOGGING ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_LOG1 ) ;
for ( byte idx = 0 ; idx < 3 ; idx + + ) {
page + = FPSTR ( HTTP_FORM_LOG2 ) ;
switch ( idx ) {
case 0 :
2018-01-07 13:56:23 +00:00
page . replace ( F ( " {b0 " ) , F ( D_SERIAL_LOG_LEVEL ) ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {b1 " ) , STR ( SERIAL_LOG_LEVEL ) ) ;
page . replace ( F ( " {b2 " ) , F ( " ls " ) ) ;
2017-01-28 13:41:01 +00:00
for ( byte i = LOG_LEVEL_NONE ; i < LOG_LEVEL_ALL ; i + + ) {
2017-10-18 17:22:34 +01:00
page . replace ( " {a " + String ( i ) , ( i = = Settings . seriallog_level ) ? F ( " selected " ) : F ( " " ) ) ;
2017-01-28 13:41:01 +00:00
}
break ;
case 1 :
2018-01-07 13:56:23 +00:00
page . replace ( F ( " {b0 " ) , F ( D_WEB_LOG_LEVEL ) ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {b1 " ) , STR ( WEB_LOG_LEVEL ) ) ;
page . replace ( F ( " {b2 " ) , F ( " lw " ) ) ;
2017-01-28 13:41:01 +00:00
for ( byte i = LOG_LEVEL_NONE ; i < LOG_LEVEL_ALL ; i + + ) {
2017-10-18 17:22:34 +01:00
page . replace ( " {a " + String ( i ) , ( i = = Settings . weblog_level ) ? F ( " selected " ) : F ( " " ) ) ;
2017-01-28 13:41:01 +00:00
}
break ;
case 2 :
2018-01-07 13:56:23 +00:00
page . replace ( F ( " {b0 " ) , F ( D_SYS_LOG_LEVEL ) ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {b1 " ) , STR ( SYS_LOG_LEVEL ) ) ;
page . replace ( F ( " {b2 " ) , F ( " ll " ) ) ;
2017-01-28 13:41:01 +00:00
for ( byte i = LOG_LEVEL_NONE ; i < LOG_LEVEL_ALL ; i + + ) {
2017-10-18 17:22:34 +01:00
page . replace ( " {a " + String ( i ) , ( i = = Settings . syslog_level ) ? F ( " selected " ) : F ( " " ) ) ;
2017-01-28 13:41:01 +00:00
}
break ;
}
}
page + = FPSTR ( HTTP_FORM_LOG3 ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {l2 " ) , Settings . syslog_host ) ;
page . replace ( F ( " {l3 " ) , String ( Settings . syslog_port ) ) ;
page . replace ( F ( " {l4 " ) , String ( Settings . tele_period ) ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_END ) ;
page + = FPSTR ( HTTP_BTN_CONF ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleOtherConfiguration ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONFIGURE_OTHER ) ;
2017-01-29 20:36:12 +00:00
char stemp [ 40 ] ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_CONFIGURE_OTHER ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_OTHER ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {r1 " ) , ( Settings . flag . mqtt_enabled ) ? F ( " checked " ) : F ( " " ) ) ;
2018-02-10 14:13:27 +00:00
uint8_t maxfn = ( devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : ( ! devices_present ) ? 1 : devices_present ;
2018-07-01 14:18:50 +01:00
if ( SONOFF_IFAN02 = = Settings . module ) { maxfn = 1 ; }
2018-01-13 14:53:02 +00:00
for ( byte i = 0 ; i < maxfn ; i + + ) {
page + = FPSTR ( HTTP_FORM_OTHER2 ) ;
page . replace ( F ( " {1 " ) , String ( i + 1 ) ) ;
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( FRIENDLY_NAME " %d " ) , i + 1 ) ;
page . replace ( F ( " {2 " ) , ( i ) ? stemp : FRIENDLY_NAME ) ;
page . replace ( F ( " {3 " ) , Settings . friendlyname [ i ] ) ;
}
2017-01-29 20:36:12 +00:00
# ifdef USE_EMULATION
2017-06-04 16:40:27 +01:00
page + = FPSTR ( HTTP_FORM_OTHER3a ) ;
for ( byte i = 0 ; i < EMUL_MAX ; i + + ) {
page + = FPSTR ( HTTP_FORM_OTHER3b ) ;
page . replace ( F ( " {1 " ) , String ( i ) ) ;
2017-11-11 11:33:30 +00:00
page . replace ( F ( " {2 " ) , ( i = = Settings . flag2 . emulation ) ? F ( " checked " ) : F ( " " ) ) ;
2017-09-02 13:37:02 +01:00
page . replace ( F ( " {3 " ) , ( i = = EMUL_NONE ) ? F ( D_NONE ) : ( i = = EMUL_WEMO ) ? F ( D_BELKIN_WEMO ) : F ( D_HUE_BRIDGE ) ) ;
page . replace ( F ( " {4 " ) , ( i = = EMUL_NONE ) ? F ( " " ) : ( i = = EMUL_WEMO ) ? F ( " " D_SINGLE_DEVICE ) : F ( " " D_MULTI_DEVICE ) ) ;
2017-06-04 16:40:27 +01:00
}
2018-01-20 11:12:39 +00:00
page + = F ( " <br/> " ) ;
2017-01-29 20:36:12 +00:00
page + = F ( " <br/></fieldset> " ) ;
# endif // USE_EMULATION
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_END ) ;
page + = FPSTR ( HTTP_BTN_CONF ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleBackupConfiguration ( )
2017-02-10 16:03:34 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_BACKUP_CONFIGURATION ) ) ;
2017-02-10 16:03:34 +00:00
2018-05-24 13:25:52 +01:00
if ( ! SettingsBufferAlloc ( ) ) { return ; }
2017-02-10 16:03:34 +00:00
2017-10-18 17:22:34 +01:00
WiFiClient myClient = WebServer - > client ( ) ;
2018-05-24 13:25:52 +01:00
WebServer - > setContentLength ( sizeof ( Settings ) ) ;
2017-03-03 11:35:23 +00:00
char attachment [ 100 ] ;
2018-04-19 20:41:59 +01:00
char friendlyname [ sizeof ( Settings . friendlyname [ 0 ] ) ] ;
2018-04-20 16:43:20 +01:00
snprintf_P ( attachment , sizeof ( attachment ) , PSTR ( " attachment; filename=Config_%s_%s.dmp " ) , NoAlNumToUnderscore ( friendlyname , Settings . friendlyname [ 0 ] ) , my_version ) ;
2017-10-18 17:22:34 +01:00
WebServer - > sendHeader ( F ( " Content-Disposition " ) , attachment ) ;
2018-05-24 13:25:52 +01:00
2017-10-18 17:22:34 +01:00
WebServer - > send ( 200 , FPSTR ( HDR_CTYPE_STREAM ) , " " ) ;
2018-05-24 13:25:52 +01:00
memcpy ( settings_buffer , & Settings , sizeof ( Settings ) ) ;
2018-06-02 15:59:09 +01:00
if ( config_xor_on_set ) {
for ( uint16_t i = 2 ; i < sizeof ( Settings ) ; i + + ) {
settings_buffer [ i ] ^ = ( config_xor_on_set + i ) ;
}
}
2018-05-24 13:25:52 +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 ( ) ;
2017-02-10 16:03:34 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleSaveSettings ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-02-10 16:03:34 +00:00
2017-05-11 16:47:34 +01:00
char stemp [ TOPSZ ] ;
2017-05-13 12:02:10 +01:00
char stemp2 [ TOPSZ ] ;
2017-01-28 13:41:01 +00:00
String result = " " ;
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_SAVE_CONFIGURATION ) ;
2017-01-28 13:41:01 +00:00
2018-01-30 13:14:55 +00:00
char tmp [ 100 ] ;
2018-03-28 17:01:38 +01:00
WebGetArg ( " w " , tmp , sizeof ( tmp ) ) ; // Returns "5,1" where 5 is config type and 1 is restart flag
char * p = tmp ;
uint8_t what = strtol ( p , & p , 10 ) ;
p + + ; // Skip comma
uint8_t restart = strtol ( p , & p , 10 ) ;
2017-01-28 13:41:01 +00:00
switch ( what ) {
case 1 :
2018-01-30 13:14:55 +00:00
WebGetArg ( " h " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . hostname , ( ! strlen ( tmp ) ) ? WIFI_HOSTNAME : tmp , sizeof ( Settings . hostname ) ) ;
2017-10-18 17:22:34 +01:00
if ( strstr ( Settings . hostname , " % " ) ) {
strlcpy ( Settings . hostname , WIFI_HOSTNAME , sizeof ( Settings . hostname ) ) ;
2017-04-25 17:24:42 +01:00
}
2018-01-30 13:14:55 +00:00
WebGetArg ( " s1 " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . sta_ssid [ 0 ] , ( ! strlen ( tmp ) ) ? STA_SSID1 : tmp , sizeof ( Settings . sta_ssid [ 0 ] ) ) ;
WebGetArg ( " s2 " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . sta_ssid [ 1 ] , ( ! strlen ( tmp ) ) ? STA_SSID2 : tmp , sizeof ( Settings . sta_ssid [ 1 ] ) ) ;
// WebGetArg("s1", tmp, sizeof(tmp));
// strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[0]));
// WebGetArg("s2", tmp, sizeof(tmp));
// strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[1]));
WebGetArg ( " p1 " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . sta_pwd [ 0 ] , ( ! strlen ( tmp ) ) ? " " : ( strchr ( tmp , ' * ' ) ) ? Settings . sta_pwd [ 0 ] : tmp , sizeof ( Settings . sta_pwd [ 0 ] ) ) ;
WebGetArg ( " p2 " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . sta_pwd [ 1 ] , ( ! strlen ( tmp ) ) ? " " : ( strchr ( tmp , ' * ' ) ) ? Settings . sta_pwd [ 1 ] : tmp , sizeof ( Settings . sta_pwd [ 1 ] ) ) ;
2018-04-21 17:17:24 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID " 1 %s, " D_CMND_SSID " 2 %s " ) ,
Settings . hostname , Settings . sta_ssid [ 0 ] , Settings . sta_ssid [ 1 ] ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_INFO ) ;
2017-09-02 13:37:02 +01:00
result + = F ( " <br/> " D_TRYING_TO_CONNECT " <br/> " ) ;
2017-01-28 13:41:01 +00:00
break ;
case 2 :
2018-01-30 13:14:55 +00:00
WebGetArg ( " mt " , tmp , sizeof ( tmp ) ) ;
strlcpy ( stemp , ( ! strlen ( tmp ) ) ? MQTT_TOPIC : tmp , sizeof ( stemp ) ) ;
2017-10-18 17:22:34 +01:00
MakeValidMqtt ( 0 , stemp ) ;
2018-01-30 13:14:55 +00:00
WebGetArg ( " mf " , tmp , sizeof ( tmp ) ) ;
strlcpy ( stemp2 , ( ! strlen ( tmp ) ) ? MQTT_FULLTOPIC : tmp , sizeof ( stemp2 ) ) ;
2017-10-18 17:22:34 +01:00
MakeValidMqtt ( 1 , stemp2 ) ;
if ( ( strcmp ( stemp , Settings . mqtt_topic ) ) | | ( strcmp ( stemp2 , Settings . mqtt_fulltopic ) ) ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , ( Settings . flag . mqtt_offline ) ? S_OFFLINE : " " ) ;
2018-01-18 15:19:28 +00:00
MqttPublishPrefixTopic_P ( TELE , S_LWT , true ) ; // Offline or remove previous retained topic
2017-05-11 16:47:34 +01:00
}
2017-10-18 17:22:34 +01:00
strlcpy ( Settings . mqtt_topic , stemp , sizeof ( Settings . mqtt_topic ) ) ;
strlcpy ( Settings . mqtt_fulltopic , stemp2 , sizeof ( Settings . mqtt_fulltopic ) ) ;
2018-01-30 13:14:55 +00:00
WebGetArg ( " mh " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . mqtt_host , ( ! strlen ( tmp ) ) ? MQTT_HOST : ( ! strcmp ( tmp , " 0 " ) ) ? " " : tmp , sizeof ( Settings . mqtt_host ) ) ;
WebGetArg ( " ml " , tmp , sizeof ( tmp ) ) ;
Settings . mqtt_port = ( ! strlen ( tmp ) ) ? MQTT_PORT : atoi ( tmp ) ;
WebGetArg ( " mc " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . mqtt_client , ( ! strlen ( tmp ) ) ? MQTT_CLIENT_ID : tmp , sizeof ( Settings . mqtt_client ) ) ;
WebGetArg ( " mu " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . mqtt_user , ( ! strlen ( tmp ) ) ? MQTT_USER : ( ! strcmp ( tmp , " 0 " ) ) ? " " : tmp , sizeof ( Settings . mqtt_user ) ) ;
WebGetArg ( " mp " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . mqtt_pwd , ( ! strlen ( tmp ) ) ? MQTT_PASS : ( ! strcmp ( tmp , " 0 " ) ) ? " " : tmp , sizeof ( Settings . mqtt_pwd ) ) ;
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s " ) ,
2017-10-18 17:22:34 +01:00
Settings . mqtt_host , Settings . mqtt_port , Settings . mqtt_client , Settings . mqtt_user , Settings . mqtt_pwd , Settings . mqtt_topic , Settings . mqtt_fulltopic ) ;
AddLog ( LOG_LEVEL_INFO ) ;
2017-01-28 13:41:01 +00:00
break ;
case 3 :
2018-01-30 13:14:55 +00:00
WebGetArg ( " ls " , tmp , sizeof ( tmp ) ) ;
Settings . seriallog_level = ( ! strlen ( tmp ) ) ? SERIAL_LOG_LEVEL : atoi ( tmp ) ;
WebGetArg ( " lw " , tmp , sizeof ( tmp ) ) ;
Settings . weblog_level = ( ! strlen ( tmp ) ) ? WEB_LOG_LEVEL : atoi ( tmp ) ;
WebGetArg ( " ll " , tmp , sizeof ( tmp ) ) ;
Settings . syslog_level = ( ! strlen ( tmp ) ) ? SYS_LOG_LEVEL : atoi ( tmp ) ;
2017-10-18 17:22:34 +01:00
syslog_level = Settings . syslog_level ;
2017-01-28 13:41:01 +00:00
syslog_timer = 0 ;
2018-01-30 13:14:55 +00:00
WebGetArg ( " lh " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . syslog_host , ( ! strlen ( tmp ) ) ? SYS_LOG_HOST : tmp , sizeof ( Settings . syslog_host ) ) ;
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 ) ;
2017-10-23 11:18:15 +01:00
if ( ( Settings . tele_period > 0 ) & & ( Settings . tele_period < 10 ) ) {
Settings . tele_period = 10 ; // Do not allow periods < 10 seconds
}
2018-01-30 13:14:55 +00:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d " ) ,
2017-10-18 17:22:34 +01:00
Settings . seriallog_level , Settings . weblog_level , Settings . syslog_level , Settings . syslog_host , Settings . syslog_port , Settings . tele_period ) ;
AddLog ( LOG_LEVEL_INFO ) ;
2017-01-28 13:41:01 +00:00
break ;
2018-04-11 09:11:20 +01:00
# if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
2018-03-28 17:01:38 +01:00
case 7 :
TimerSaveSettings ( ) ;
break ;
2018-04-11 09:11:20 +01:00
# endif // USE_TIMERS and USE_TIMERS_WEB
2017-01-28 13:41:01 +00:00
# ifdef USE_DOMOTICZ
case 4 :
2017-10-18 17:22:34 +01:00
DomoticzSaveSettings ( ) ;
2017-01-28 13:41:01 +00:00
break ;
# endif // USE_DOMOTICZ
case 5 :
2018-01-30 13:14:55 +00:00
WebGetArg ( " p1 " , tmp , sizeof ( tmp ) ) ;
strlcpy ( Settings . web_password , ( ! strlen ( tmp ) ) ? " " : ( strchr ( tmp , ' * ' ) ) ? Settings . web_password : tmp , sizeof ( Settings . web_password ) ) ;
2017-10-18 17:22:34 +01:00
Settings . flag . mqtt_enabled = WebServer - > hasArg ( " b1 " ) ;
2017-01-29 20:36:12 +00:00
# ifdef USE_EMULATION
2018-01-30 13:14:55 +00:00
WebGetArg ( " b2 " , tmp , sizeof ( tmp ) ) ;
Settings . flag2 . emulation = ( ! strlen ( tmp ) ) ? 0 : atoi ( tmp ) ;
2017-01-29 20:36:12 +00:00
# endif // USE_EMULATION
2018-06-30 13:17:26 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME ) , GetStateText ( Settings . flag . mqtt_enabled ) , Settings . flag2 . emulation ) ;
for ( byte i = 0 ; i < MAX_FRIENDLYNAMES ; i + + ) {
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " a%d " ) , i + 1 ) ;
WebGetArg ( stemp , tmp , sizeof ( tmp ) ) ;
snprintf_P ( stemp2 , sizeof ( stemp2 ) , PSTR ( FRIENDLY_NAME " %d " ) , i + 1 ) ;
strlcpy ( Settings . friendlyname [ i ] , ( ! strlen ( tmp ) ) ? ( i ) ? stemp2 : FRIENDLY_NAME : tmp , sizeof ( Settings . friendlyname [ i ] ) ) ;
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " %s%s %s " ) , log_data , ( i ) ? " , " : " " , Settings . friendlyname [ i ] ) ;
}
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_INFO ) ;
2017-01-28 13:41:01 +00:00
break ;
case 6 :
2018-01-30 13:14:55 +00:00
WebGetArg ( " g99 " , tmp , sizeof ( tmp ) ) ;
byte new_module = ( ! strlen ( tmp ) ) ? MODULE : atoi ( tmp ) ;
2017-11-15 22:07:45 +00:00
Settings . last_module = Settings . module ;
2017-10-18 17:22:34 +01:00
Settings . module = new_module ;
2017-01-28 13:41:01 +00:00
mytmplt cmodule ;
2017-10-18 17:22:34 +01:00
memcpy_P ( & cmodule , & kModules [ Settings . module ] , sizeof ( cmodule ) ) ;
2017-01-28 13:41:01 +00:00
String gpios = " " ;
for ( byte i = 0 ; i < MAX_GPIO_PIN ; i + + ) {
2017-11-15 22:07:45 +00:00
if ( Settings . last_module ! = new_module ) {
2017-10-18 17:22:34 +01:00
Settings . my_gp . io [ i ] = 0 ;
2017-10-01 13:32:36 +01:00
} else {
if ( GPIO_USER = = cmodule . gp . io [ i ] ) {
snprintf_P ( stemp , sizeof ( stemp ) , PSTR ( " g%d " ) , i ) ;
2018-01-30 13:14:55 +00:00
WebGetArg ( stemp , tmp , sizeof ( tmp ) ) ;
Settings . my_gp . io [ i ] = ( ! strlen ( tmp ) ) ? 0 : atoi ( tmp ) ;
2017-10-18 17:22:34 +01:00
gpios + = F ( " , " D_GPIO ) ; gpios + = String ( i ) ; gpios + = F ( " " ) ; gpios + = String ( Settings . my_gp . io [ i ] ) ;
2017-10-01 13:32:36 +01:00
}
2017-01-28 13:41:01 +00:00
}
}
2017-10-18 17:22:34 +01:00
snprintf_P ( stemp , sizeof ( stemp ) , kModules [ Settings . module ] . name ) ;
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_MODULE " %s " D_CMND_MODULE " %s " ) , stemp , gpios . c_str ( ) ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_INFO ) ;
2017-01-28 13:41:01 +00:00
break ;
}
if ( restart ) {
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_SAVE_CONFIGURATION ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-09-02 13:37:02 +01:00
page + = F ( " <div style='text-align:center;'><b> " D_CONFIGURATION_SAVED " </b><br/> " ) ;
2017-01-28 13:41:01 +00:00
page + = result ;
page + = F ( " </div> " ) ;
page + = FPSTR ( HTTP_MSG_RSTRT ) ;
2017-10-18 17:22:34 +01:00
if ( HTTP_MANAGER = = webserver_state ) {
webserver_state = HTTP_ADMIN ;
2017-01-28 13:41:01 +00:00
} else {
page + = FPSTR ( HTTP_BTN_MAIN ) ;
}
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
2018-05-28 14:52:42 +01:00
ShowWebSource ( SRC_WEBGUI ) ;
2017-10-18 17:22:34 +01:00
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
} else {
2017-10-18 17:22:34 +01:00
HandleConfiguration ( ) ;
2017-01-28 13:41:01 +00:00
}
}
2017-10-18 17:22:34 +01:00
void HandleResetConfiguration ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-02-10 16:03:34 +00:00
2018-01-13 14:53:02 +00:00
char svalue [ 33 ] ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_RESET_CONFIGURATION ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_RESET_CONFIGURATION ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-09-02 13:37:02 +01:00
page + = F ( " <div style='text-align:center;'> " D_CONFIGURATION_RESET " </div> " ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_MSG_RSTRT ) ;
page + = FPSTR ( HTTP_BTN_MAIN ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
2017-09-02 13:37:02 +01:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_RESET " 1 " ) ) ;
2018-05-28 14:52:42 +01:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleRestoreConfiguration ( )
2017-02-10 16:03:34 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_RESTORE_CONFIGURATION ) ;
2017-02-10 16:03:34 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_RESTORE_CONFIGURATION ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-02-10 16:03:34 +00:00
page + = FPSTR ( HTTP_FORM_RST ) ;
2017-05-13 12:02:10 +01:00
page + = FPSTR ( HTTP_FORM_RST_UPG ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {r1 " ) , F ( D_RESTORE ) ) ;
2017-02-10 16:03:34 +00:00
page + = FPSTR ( HTTP_BTN_CONF ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-02-10 16:03:34 +00:00
2017-10-18 17:22:34 +01:00
upload_error = 0 ;
2018-06-04 17:10:38 +01:00
upload_file_type = UPL_SETTINGS ;
2017-02-10 16:03:34 +00:00
}
2018-07-06 17:00:50 +01:00
void HandleInformation ( )
{
if ( HttpUser ( ) ) { return ; }
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_INFORMATION ) ;
char stopic [ TOPSZ ] ;
int freeMem = ESP . getFreeHeap ( ) ;
String page = FPSTR ( HTTP_HEAD ) ;
page . replace ( F ( " {v} " ) , FPSTR ( S_INFORMATION ) ) ;
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
// page += F("<fieldset><legend><b> Information </b></legend>");
page + = F ( " <style>td{padding:0px 5px;}</style> " ) ;
page + = F ( " <div id='i' name='i'></div> " ) ;
// Save 1k of code space replacing table html with javascript replace codes
// }1 = </td></tr><tr><th>
// }2 = </th><td>
String func = FPSTR ( HTTP_SCRIPT_INFO_BEGIN ) ;
func + = F ( " <table style='width:100%'><tr><th> " ) ;
func + = F ( D_PROGRAM_VERSION " }2 " ) ; func + = my_version ;
func + = F ( " }1 " D_BUILD_DATE_AND_TIME " }2 " ) ; func + = GetBuildDateAndTime ( ) ;
func + = F ( " }1 " D_CORE_AND_SDK_VERSION " }2 " ARDUINO_ESP8266_RELEASE " / " ) ; func + = String ( ESP . getSdkVersion ( ) ) ;
func + = F ( " }1 " D_UPTIME " }2 " ) ; func + = GetDateAndTime ( DT_UPTIME ) ;
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( " at %X " ) , GetSettingsAddress ( ) ) ;
func + = F ( " }1 " D_FLASH_WRITE_COUNT " }2 " ) ; func + = String ( Settings . save_flag ) ; func + = stopic ;
func + = F ( " }1 " D_BOOT_COUNT " }2 " ) ; func + = String ( Settings . bootcount ) ;
func + = F ( " }1 " D_RESTART_REASON " }2 " ) ; func + = GetResetReason ( ) ;
uint8_t maxfn = ( devices_present > MAX_FRIENDLYNAMES ) ? MAX_FRIENDLYNAMES : devices_present ;
if ( SONOFF_IFAN02 = = Settings . module ) { maxfn = 1 ; }
for ( byte i = 0 ; i < maxfn ; i + + ) {
func + = F ( " }1 " D_FRIENDLY_NAME " " ) ; func + = i + 1 ; func + = F ( " }2 " ) ; func + = Settings . friendlyname [ i ] ;
}
func + = F ( " }1}2 " ) ; // Empty line
func + = F ( " }1 " D_AP ) ; func + = String ( Settings . sta_active + 1 ) ;
func + = F ( " " D_SSID " ( " D_RSSI " )}2 " ) ; func + = Settings . sta_ssid [ Settings . sta_active ] ; func + = F ( " ( " ) ; func + = WifiGetRssiAsQuality ( WiFi . RSSI ( ) ) ; func + = F ( " %) " ) ;
func + = F ( " }1 " D_HOSTNAME " }2 " ) ; func + = my_hostname ;
if ( static_cast < uint32_t > ( WiFi . localIP ( ) ) ! = 0 ) {
func + = F ( " }1 " D_IP_ADDRESS " }2 " ) ; func + = WiFi . localIP ( ) . toString ( ) ;
func + = F ( " }1 " D_GATEWAY " }2 " ) ; func + = IPAddress ( Settings . ip_address [ 1 ] ) . toString ( ) ;
func + = F ( " }1 " D_SUBNET_MASK " }2 " ) ; func + = IPAddress ( Settings . ip_address [ 2 ] ) . toString ( ) ;
func + = F ( " }1 " D_DNS_SERVER " }2 " ) ; func + = IPAddress ( Settings . ip_address [ 3 ] ) . toString ( ) ;
func + = F ( " }1 " D_MAC_ADDRESS " }2 " ) ; func + = WiFi . macAddress ( ) ;
}
if ( static_cast < uint32_t > ( WiFi . softAPIP ( ) ) ! = 0 ) {
func + = F ( " }1 " D_AP " " D_IP_ADDRESS " }2 " ) ; func + = WiFi . softAPIP ( ) . toString ( ) ;
func + = F ( " }1 " D_AP " " D_GATEWAY " }2 " ) ; func + = WiFi . softAPIP ( ) . toString ( ) ;
func + = F ( " }1 " D_AP " " D_MAC_ADDRESS " }2 " ) ; func + = WiFi . softAPmacAddress ( ) ;
}
func + = F ( " }1}2 " ) ; // Empty line
if ( Settings . flag . mqtt_enabled ) {
func + = F ( " }1 " D_MQTT_HOST " }2 " ) ; func + = Settings . mqtt_host ;
func + = F ( " }1 " D_MQTT_PORT " }2 " ) ; func + = String ( Settings . mqtt_port ) ;
func + = F ( " }1 " D_MQTT_CLIENT " &<br/> " D_FALLBACK_TOPIC " }2 " ) ; func + = mqtt_client ;
func + = F ( " }1 " D_MQTT_USER " }2 " ) ; func + = Settings . mqtt_user ;
func + = F ( " }1 " D_MQTT_TOPIC " }2 " ) ; func + = Settings . mqtt_topic ;
func + = F ( " }1 " D_MQTT_GROUP_TOPIC " }2 " ) ; func + = Settings . mqtt_grptopic ;
GetTopic_P ( stopic , CMND , mqtt_topic , " " ) ;
func + = F ( " }1 " D_MQTT_FULL_TOPIC " }2 " ) ; func + = stopic ;
} else {
func + = F ( " }1 " D_MQTT " }2 " D_DISABLED ) ;
}
func + = F ( " }1}2 " ) ; // Empty line
func + = F ( " }1 " D_EMULATION " }2 " ) ;
# ifdef USE_EMULATION
if ( EMUL_WEMO = = Settings . flag2 . emulation ) {
func + = F ( D_BELKIN_WEMO ) ;
}
else if ( EMUL_HUE = = Settings . flag2 . emulation ) {
func + = F ( D_HUE_BRIDGE ) ;
}
else {
func + = F ( D_NONE ) ;
}
# else
func + = F ( D_DISABLED ) ;
# endif // USE_EMULATION
func + = F ( " }1 " D_MDNS_DISCOVERY " }2 " ) ;
# ifdef USE_DISCOVERY
func + = F ( D_ENABLED ) ;
func + = F ( " }1 " D_MDNS_ADVERTISE " }2 " ) ;
# ifdef WEBSERVER_ADVERTISE
func + = F ( D_WEB_SERVER ) ;
# else
func + = F ( D_DISABLED ) ;
# endif // WEBSERVER_ADVERTISE
# else
func + = F ( D_DISABLED ) ;
# endif // USE_DISCOVERY
func + = F ( " }1}2 " ) ; // Empty line
func + = F ( " }1 " D_ESP_CHIP_ID " }2 " ) ; func + = String ( ESP . getChipId ( ) ) ;
func + = F ( " }1 " D_FLASH_CHIP_ID " }2 " ) ; func + = String ( ESP . getFlashChipId ( ) ) ;
func + = F ( " }1 " D_FLASH_CHIP_SIZE " }2 " ) ; func + = String ( ESP . getFlashChipRealSize ( ) / 1024 ) ; func + = F ( " kB " ) ;
func + = F ( " }1 " D_PROGRAM_FLASH_SIZE " }2 " ) ; func + = String ( ESP . getFlashChipSize ( ) / 1024 ) ; func + = F ( " kB " ) ;
func + = F ( " }1 " D_PROGRAM_SIZE " }2 " ) ; func + = String ( ESP . getSketchSize ( ) / 1024 ) ; func + = F ( " kB " ) ;
func + = F ( " }1 " D_FREE_PROGRAM_SPACE " }2 " ) ; func + = String ( ESP . getFreeSketchSpace ( ) / 1024 ) ; func + = F ( " kB " ) ;
func + = F ( " }1 " D_FREE_MEMORY " }2 " ) ; func + = String ( freeMem / 1024 ) ; func + = F ( " kB " ) ;
func + = F ( " </td></tr></table> " ) ;
func + = FPSTR ( HTTP_SCRIPT_INFO_END ) ;
page . replace ( F ( " </script> " ) , func ) ;
page . replace ( F ( " <body> " ) , F ( " <body onload='i()'> " ) ) ;
// page += F("</fieldset>");
page + = FPSTR ( HTTP_BTN_MAIN ) ;
ShowPage ( page ) ;
}
# endif // Not BE_MINIMAL
2017-10-18 17:22:34 +01:00
void HandleUpgradeFirmware ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_FIRMWARE_UPGRADE ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_FIRMWARE_UPGRADE ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_UPG ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {o1 " ) , Settings . ota_url ) ;
2017-05-13 12:02:10 +01:00
page + = FPSTR ( HTTP_FORM_RST_UPG ) ;
2017-10-25 13:27:30 +01:00
page . replace ( F ( " {r1 " ) , F ( D_UPGRADE ) ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_BTN_MAIN ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
upload_error = 0 ;
2018-06-04 17:10:38 +01:00
upload_file_type = UPL_TASMOTA ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleUpgradeFirmwareStart ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-09-14 13:20:27 +01:00
char svalue [ 100 ] ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_UPGRADE_STARTED ) ) ;
WifiConfigCounter ( ) ;
2017-01-28 13:41:01 +00:00
2018-01-30 13:14:55 +00:00
char tmp [ 100 ] ;
WebGetArg ( " o " , tmp , sizeof ( tmp ) ) ;
if ( strlen ( tmp ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_OTAURL " %s " ) , tmp ) ;
2018-05-28 14:52:42 +01:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
2017-01-28 13:41:01 +00:00
}
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_INFORMATION ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-09-02 13:37:02 +01:00
page + = F ( " <div style='text-align:center;'><b> " D_UPGRADE_STARTED " ...</b></div> " ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_MSG_RSTRT ) ;
page + = FPSTR ( HTTP_BTN_MAIN ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
2017-09-02 13:37:02 +01:00
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( D_CMND_UPGRADE " 1 " ) ) ;
2018-05-28 14:52:42 +01:00
ExecuteWebCommand ( svalue , SRC_WEBGUI ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleUploadDone ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_UPLOAD_DONE ) ) ;
2017-01-28 13:41:01 +00:00
2017-09-02 13:37:02 +01:00
char error [ 100 ] ;
2017-10-18 17:22:34 +01:00
WifiConfigCounter ( ) ;
restart_flag = 0 ;
2018-02-27 13:59:46 +00:00
MqttRetryCounter ( 0 ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_INFORMATION ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-09-02 13:37:02 +01:00
page + = F ( " <div style='text-align:center;'><b> " D_UPLOAD " <font color=' " ) ;
2017-10-18 17:22:34 +01:00
if ( upload_error ) {
2017-09-02 13:37:02 +01:00
page + = F ( " red'> " D_FAILED " </font></b><br/><br/> " ) ;
2017-10-18 17:22:34 +01:00
switch ( upload_error ) {
2017-09-06 16:37:41 +01:00
case 1 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_1 ) , sizeof ( error ) ) ; break ;
case 2 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_2 ) , sizeof ( error ) ) ; break ;
case 3 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_3 ) , sizeof ( error ) ) ; break ;
case 4 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_4 ) , sizeof ( error ) ) ; break ;
case 5 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_5 ) , sizeof ( error ) ) ; break ;
case 6 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_6 ) , sizeof ( error ) ) ; break ;
case 7 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_7 ) , sizeof ( error ) ) ; break ;
case 8 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_8 ) , sizeof ( error ) ) ; break ;
case 9 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_9 ) , sizeof ( error ) ) ; break ;
2018-06-04 17:10:38 +01:00
# ifdef USE_RF_FLASH
case 10 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_10 ) , sizeof ( error ) ) ; break ;
case 11 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_11 ) , sizeof ( error ) ) ; break ;
case 12 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_12 ) , sizeof ( error ) ) ; break ;
case 13 : strncpy_P ( error , PSTR ( D_UPLOAD_ERR_13 ) , sizeof ( error ) ) ; break ;
# endif
2017-06-16 13:33:49 +01:00
default :
2017-10-18 17:22:34 +01:00
snprintf_P ( error , sizeof ( error ) , PSTR ( D_UPLOAD_ERROR_CODE " %d " ) , upload_error ) ;
2017-01-28 13:41:01 +00:00
}
2017-02-10 16:03:34 +00:00
page + = error ;
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_UPLOAD " : %s " ) , error ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_DEBUG ) ;
stop_flash_rotate = Settings . flag . stop_flash_rotate ;
2017-01-28 13:41:01 +00:00
} else {
2017-09-02 13:37:02 +01:00
page + = F ( " green'> " D_SUCCESSFUL " </font></b><br/> " ) ;
page + = FPSTR ( HTTP_MSG_RSTRT ) ;
2018-05-28 14:52:42 +01:00
ShowWebSource ( SRC_WEBGUI ) ;
2018-06-04 17:10:38 +01:00
restart_flag = 2 ; // Always restart to re-enable disabled features during update
2017-01-28 13:41:01 +00:00
}
2018-05-24 13:25:52 +01:00
SettingsBufferFree ( ) ;
2017-01-28 13:41:01 +00:00
page + = F ( " </div><br/> " ) ;
page + = FPSTR ( HTTP_BTN_MAIN ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleUploadLoop ( )
2017-01-28 13:41:01 +00:00
{
// Based on ESP8266HTTPUpdateServer.cpp uses ESP8266WebServer Parsing.cpp and Cores Updater.cpp (Update)
boolean _serialoutput = ( LOG_LEVEL_DEBUG < = seriallog_level ) ;
2018-04-20 13:31:09 +01:00
if ( HTTP_USER = = webserver_state ) { return ; }
2017-10-18 17:22:34 +01:00
if ( upload_error ) {
2018-06-04 17:10:38 +01:00
if ( UPL_TASMOTA = = upload_file_type ) { Update . end ( ) ; }
2017-01-28 13:41:01 +00:00
return ;
}
2017-10-18 17:22:34 +01:00
HTTPUpload & upload = WebServer - > upload ( ) ;
2017-01-28 13:41:01 +00:00
2017-04-25 17:24:42 +01:00
if ( UPLOAD_FILE_START = = upload . status ) {
2017-10-18 17:22:34 +01:00
restart_flag = 60 ;
2017-04-25 17:24:42 +01:00
if ( 0 = = upload . filename . c_str ( ) [ 0 ] ) {
2018-06-02 15:59:09 +01:00
upload_error = 1 ; // No file selected
2017-01-28 13:41:01 +00:00
return ;
}
2017-10-18 17:22:34 +01:00
SettingsSave ( 1 ) ; // Free flash for upload
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_UPLOAD D_FILE " %s ... " ) , upload . filename . c_str ( ) ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_INFO ) ;
2018-06-04 17:10:38 +01:00
if ( UPL_SETTINGS = = upload_file_type ) {
2018-05-24 13:25:52 +01:00
if ( ! SettingsBufferAlloc ( ) ) {
2018-06-02 15:59:09 +01:00
upload_error = 2 ; // Not enough space
2018-05-06 17:35:31 +01:00
return ;
}
} else {
2018-02-27 13:59:46 +00:00
MqttRetryCounter ( 60 ) ;
2017-02-10 16:03:34 +00:00
# ifdef USE_EMULATION
2017-10-18 17:22:34 +01:00
UdpDisconnect ( ) ;
2017-02-10 16:03:34 +00:00
# endif // USE_EMULATION
2018-02-07 16:50:02 +00:00
# ifdef USE_ARILUX_RF
AriluxRfDisable ( ) ; // Prevent restart exception on Arilux Interrupt routine
# endif // USE_ARILUX_RF
2018-02-27 13:59:46 +00:00
if ( Settings . flag . mqtt_enabled ) MqttDisconnect ( ) ;
2017-02-10 16:03:34 +00:00
uint32_t maxSketchSpace = ( ESP . getFreeSketchSpace ( ) - 0x1000 ) & 0xFFFFF000 ;
if ( ! Update . begin ( maxSketchSpace ) ) { //start with max available size
2018-06-04 17:10:38 +01:00
// if (_serialoutput) Update.printError(Serial);
// if (Update.getError() == UPDATE_ERROR_BOOTSTRAP) {
// if (_serialoutput) Serial.println("Device still in UART update mode, perform powercycle");
// }
2018-06-02 15:59:09 +01:00
upload_error = 2 ; // Not enough space
2017-02-10 16:03:34 +00:00
return ;
}
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
upload_progress_dot_count = 0 ;
} else if ( ! upload_error & & ( UPLOAD_FILE_WRITE = = upload . status ) ) {
2018-05-01 17:02:45 +01:00
if ( 0 = = upload . totalSize ) {
2018-06-04 17:10:38 +01:00
if ( UPL_SETTINGS = = upload_file_type ) {
2018-05-01 17:02:45 +01:00
config_block_count = 0 ;
2018-06-04 17:10:38 +01:00
}
else {
# ifdef USE_RF_FLASH
if ( ( SONOFF_BRIDGE = = Settings . module ) & & ( upload . buf [ 0 ] = = ' : ' ) ) { // Check if this is a RF bridge FW file
Update . end ( ) ; // End esp8266 update session
upload_file_type = UPL_EFM8BB1 ;
upload_error = SnfBrUpdateInit ( ) ;
if ( upload_error ! = 0 ) { return ; }
} else
# endif // USE_RF_FLASH
{
if ( upload . buf [ 0 ] ! = 0xE9 ) {
upload_error = 3 ; // Magic byte is not 0xE9
return ;
}
uint32_t bin_flash_size = ESP . magicFlashChipSize ( ( upload . buf [ 3 ] & 0xf0 ) > > 4 ) ;
if ( bin_flash_size > ESP . getFlashChipRealSize ( ) ) {
upload_error = 4 ; // Program flash size is larger than real flash size
return ;
}
upload . buf [ 2 ] = 3 ; // Force DOUT - ESP8285
2017-02-10 16:03:34 +00:00
}
2017-01-28 13:41:01 +00:00
}
2017-02-10 16:03:34 +00:00
}
2018-06-04 17:10:38 +01:00
if ( UPL_SETTINGS = = upload_file_type ) {
2017-10-18 17:22:34 +01:00
if ( ! upload_error ) {
2018-05-01 17:02:45 +01:00
if ( upload . currentSize > ( sizeof ( Settings ) - ( config_block_count * HTTP_UPLOAD_BUFLEN ) ) ) {
2018-06-02 15:59:09 +01:00
upload_error = 9 ; // File too large
2018-05-01 17:02:45 +01:00
return ;
}
2018-05-24 13:25:52 +01:00
memcpy ( settings_buffer + ( config_block_count * HTTP_UPLOAD_BUFLEN ) , upload . buf , upload . currentSize ) ;
2018-05-01 17:02:45 +01:00
config_block_count + + ;
2017-02-10 16:03:34 +00:00
}
2018-06-04 17:10:38 +01:00
}
# ifdef USE_RF_FLASH
else if ( UPL_EFM8BB1 = = upload_file_type ) {
if ( efm8bb1_update ! = NULL ) { // We have carry over data since last write, i. e. a start but not an end
ssize_t result = rf_glue_remnant_with_new_data_and_write ( efm8bb1_update , upload . buf , upload . currentSize ) ;
free ( efm8bb1_update ) ;
efm8bb1_update = NULL ;
if ( result ! = 0 ) {
upload_error = abs ( result ) ; // 2 = Not enough space, 8 = File invalid
return ;
}
}
ssize_t result = rf_search_and_write ( upload . buf , upload . currentSize ) ;
if ( result < 0 ) {
upload_error = abs ( result ) ;
return ;
} else if ( result > 0 ) {
if ( result > upload . currentSize ) {
// Offset is larger than the buffer supplied, this should not happen
upload_error = 9 ; // File too large - Failed to decode RF firmware
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 ) ;
if ( efm8bb1_update = = NULL ) {
upload_error = 2 ; // Not enough space - Unable to allocate memory to store new RF firmware
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
else { // firmware
2017-10-18 17:22:34 +01:00
if ( ! upload_error & & ( Update . write ( upload . buf , upload . currentSize ) ! = upload . currentSize ) ) {
2018-06-02 15:59:09 +01:00
upload_error = 5 ; // Upload buffer miscompare
2017-01-28 13:41:01 +00:00
return ;
}
2017-02-10 16:03:34 +00:00
if ( _serialoutput ) {
Serial . printf ( " . " ) ;
2017-10-18 17:22:34 +01:00
upload_progress_dot_count + + ;
2018-04-20 13:31:09 +01:00
if ( ! ( upload_progress_dot_count % 80 ) ) { Serial . println ( ) ; }
2017-01-28 13:41:01 +00:00
}
}
2017-10-18 17:22:34 +01:00
} else if ( ! upload_error & & ( UPLOAD_FILE_END = = upload . status ) ) {
if ( _serialoutput & & ( upload_progress_dot_count % 80 ) ) {
2017-04-25 17:24:42 +01:00
Serial . println ( ) ;
}
2018-06-04 17:10:38 +01:00
if ( UPL_SETTINGS = = upload_file_type ) {
2018-06-02 15:59:09 +01:00
if ( config_xor_on_set ) {
2018-05-06 17:35:31 +01:00
for ( uint16_t i = 2 ; i < sizeof ( Settings ) ; i + + ) {
2018-05-24 13:25:52 +01:00
settings_buffer [ i ] ^ = ( config_xor_on_set + i ) ;
2018-05-06 17:35:31 +01:00
}
}
2018-06-02 15:59:09 +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 ) {
uint16_t buffer_size = settings_buffer [ 3 ] < < 8 | settings_buffer [ 2 ] ;
uint16_t buffer_crc = settings_buffer [ 15 ] < < 8 | settings_buffer [ 14 ] ;
uint16_t crc = 0 ;
for ( uint16_t i = 0 ; i < buffer_size ; i + + ) {
if ( ( i < 14 ) | | ( i > 15 ) ) { crc + = settings_buffer [ i ] * ( i + 1 ) ; } // Skip crc
}
valid_settings = ( buffer_crc = = crc ) ;
} else {
valid_settings = ( settings_buffer [ 0 ] = = CONFIG_FILE_SIGN ) ;
}
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 {
upload_error = 8 ; // File invalid
return ;
}
2018-06-04 17:10:38 +01:00
}
# ifdef USE_RF_FLASH
else if ( UPL_EFM8BB1 = = upload_file_type ) {
// RF FW flash done
upload_file_type = UPL_TASMOTA ;
}
# endif // USE_RF_FLASH
else {
2017-02-10 16:03:34 +00:00
if ( ! Update . end ( true ) ) { // true to set the size to the current progress
2018-04-20 13:31:09 +01:00
if ( _serialoutput ) { Update . printError ( Serial ) ; }
2018-06-02 15:59:09 +01:00
upload_error = 6 ; // Upload failed. Enable logging 3
2017-02-10 16:03:34 +00:00
return ;
}
}
2017-10-18 17:22:34 +01:00
if ( ! upload_error ) {
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_UPLOAD D_SUCCESSFUL " %u bytes. " D_RESTARTING ) , upload . totalSize ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_INFO ) ;
2017-01-28 13:41:01 +00:00
}
2017-04-25 17:24:42 +01:00
} else if ( UPLOAD_FILE_ABORTED = = upload . status ) {
2017-10-18 17:22:34 +01:00
restart_flag = 0 ;
2018-02-27 13:59:46 +00:00
MqttRetryCounter ( 0 ) ;
2018-06-02 15:59:09 +01:00
upload_error = 7 ; // Upload aborted
2018-06-04 17:10:38 +01:00
if ( UPL_TASMOTA = = upload_file_type ) { Update . end ( ) ; }
2017-01-28 13:41:01 +00:00
}
delay ( 0 ) ;
}
2018-02-16 16:35:51 +00:00
void HandlePreflightRequest ( )
{
WebServer - > sendHeader ( F ( " Access-Control-Allow-Origin " ) , F ( " * " ) ) ;
WebServer - > sendHeader ( F ( " Access-Control-Allow-Methods " ) , F ( " GET, POST " ) ) ;
WebServer - > sendHeader ( F ( " Access-Control-Allow-Headers " ) , F ( " authorization " ) ) ;
WebServer - > send ( 200 , FPSTR ( HDR_CTYPE_HTML ) , " " ) ;
}
2017-10-18 17:22:34 +01:00
void HandleHttpCommand ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2018-05-06 15:07:42 +01:00
char svalue [ INPUT_BUFFER_SIZE ] ; // Large to serve Backlog
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_COMMAND ) ) ;
2017-01-28 13:41:01 +00:00
2017-02-21 17:14:33 +00:00
uint8_t valid = 1 ;
2017-10-18 17:22:34 +01:00
if ( Settings . web_password [ 0 ] ! = 0 ) {
2018-01-30 13:14:55 +00:00
char tmp1 [ 100 ] ;
WebGetArg ( " user " , tmp1 , sizeof ( tmp1 ) ) ;
char tmp2 [ 100 ] ;
WebGetArg ( " password " , tmp2 , sizeof ( tmp2 ) ) ;
2018-05-28 14:52:42 +01:00
if ( ! ( ! strcmp ( tmp1 , WEB_USERNAME ) & & ! strcmp ( tmp2 , Settings . web_password ) ) ) { valid = 0 ; }
2017-01-28 13:41:01 +00:00
}
2017-12-17 15:01:30 +00:00
String message = F ( " { \" " D_RSLT_WARNING " \" : \" " ) ;
2017-02-21 17:14:33 +00:00
if ( valid ) {
2017-10-18 17:22:34 +01:00
byte curridx = web_log_index ;
2018-02-08 11:45:26 +00:00
WebGetArg ( " cmnd " , svalue , sizeof ( svalue ) ) ;
2018-05-28 14:52:42 +01:00
if ( strlen ( svalue ) ) {
ExecuteWebCommand ( svalue , SRC_WEBCOMMAND ) ;
}
2017-02-21 17:14:33 +00:00
2017-10-18 17:22:34 +01:00
if ( web_log_index ! = curridx ) {
2017-02-21 17:14:33 +00:00
byte counter = curridx ;
2017-12-17 15:01:30 +00:00
message = F ( " { " ) ;
2017-02-21 17:14:33 +00:00
do {
2018-01-30 13:14:55 +00:00
char * tmp ;
size_t len ;
GetLog ( counter , & tmp , & len ) ;
if ( len ) {
2017-12-17 15:01:30 +00:00
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
2018-01-30 13:14:55 +00:00
char * JSON = ( char * ) memchr ( tmp , ' { ' , len ) ;
if ( JSON ) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
2018-04-20 13:31:09 +01:00
if ( message . length ( ) > 1 ) { message + = F ( " , " ) ; }
2018-01-30 13:14:55 +00:00
size_t JSONlen = len - ( JSON - tmp ) ;
strlcpy ( mqtt_data , JSON + 1 , JSONlen - 2 ) ;
message + = mqtt_data ;
2017-02-21 17:14:33 +00:00
}
2017-01-28 13:41:01 +00:00
}
2017-02-21 17:14:33 +00:00
counter + + ;
2018-01-30 13:14:55 +00:00
if ( ! counter ) counter + + ; // Skip 0 as it is not allowed
2017-10-18 17:22:34 +01:00
} while ( counter ! = web_log_index ) ;
2017-12-17 15:01:30 +00:00
message + = F ( " } " ) ;
2017-02-21 17:14:33 +00:00
} else {
2017-12-17 15:01:30 +00:00
message + = F ( D_ENABLE_WEBLOG_FOR_RESPONSE " \" } " ) ;
2017-02-21 17:14:33 +00:00
}
2017-01-28 13:41:01 +00:00
} else {
2017-12-17 15:01:30 +00:00
message + = F ( D_NEED_USER_AND_PASSWORD " \" } " ) ;
2017-01-28 13:41:01 +00:00
}
2018-01-13 14:53:02 +00:00
SetHeader ( ) ;
2017-12-17 15:01:30 +00:00
WebServer - > send ( 200 , FPSTR ( HDR_CTYPE_JSON ) , message ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleConsole ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_CONSOLE ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_CONSOLE ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-05-10 13:19:36 +01:00
page . replace ( F ( " </script> " ) , FPSTR ( HTTP_SCRIPT_CONSOL ) ) ;
page . replace ( F ( " <body> " ) , F ( " <body onload='l()'> " ) ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_FORM_CMND ) ;
page + = FPSTR ( HTTP_BTN_MAIN ) ;
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleAjaxConsoleRefresh ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2018-05-06 15:07:42 +01:00
char svalue [ INPUT_BUFFER_SIZE ] ; // Large to serve Backlog
2017-04-25 17:24:42 +01:00
byte cflg = 1 ;
2018-01-30 13:14:55 +00:00
byte counter = 0 ; // Initial start, should never be 0 again
2017-02-24 17:17:48 +00:00
2018-02-08 11:45:26 +00:00
WebGetArg ( " c1 " , svalue , sizeof ( svalue ) ) ;
if ( strlen ( svalue ) ) {
2017-09-13 13:19:34 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( D_LOG_COMMAND " %s " ) , svalue ) ;
2017-10-18 17:22:34 +01:00
AddLog ( LOG_LEVEL_INFO ) ;
2018-05-28 14:52:42 +01:00
ExecuteWebCommand ( svalue , SRC_WEBCONSOLE ) ;
2017-02-24 17:17:48 +00:00
}
2017-09-02 13:37:02 +01:00
2018-02-08 11:45:26 +00:00
WebGetArg ( " c2 " , svalue , sizeof ( svalue ) ) ;
2018-04-20 13:31:09 +01:00
if ( strlen ( svalue ) ) { counter = atoi ( svalue ) ; }
2017-02-24 17:17:48 +00:00
2018-01-30 13:14:55 +00:00
byte last_reset_web_log_flag = reset_web_log_flag ;
2018-01-26 14:21:57 +00:00
String message = F ( " }9 " ) ; // Cannot load mqtt_data here as <> will be encoded by replacements below
2017-10-18 17:22:34 +01:00
if ( ! reset_web_log_flag ) {
2018-01-30 13:14:55 +00:00
counter = 0 ;
2017-10-18 17:22:34 +01:00
reset_web_log_flag = 1 ;
2017-02-24 17:17:48 +00:00
}
2017-10-18 17:22:34 +01:00
if ( counter ! = web_log_index ) {
2018-01-30 13:14:55 +00:00
if ( ! counter ) {
2017-10-18 17:22:34 +01:00
counter = web_log_index ;
2017-02-28 15:01:48 +00:00
cflg = 0 ;
}
2017-02-24 17:17:48 +00:00
do {
2018-01-30 13:14:55 +00:00
char * tmp ;
size_t len ;
GetLog ( counter , & tmp , & len ) ;
if ( len ) {
2017-04-25 17:24:42 +01:00
if ( cflg ) {
2018-01-26 14:21:57 +00:00
message + = F ( " \n " ) ;
2017-04-25 17:24:42 +01:00
} else {
cflg = 1 ;
}
2018-01-30 13:14:55 +00:00
strlcpy ( mqtt_data , tmp , len ) ;
message + = mqtt_data ;
2017-02-24 17:17:48 +00:00
}
counter + + ;
2018-04-20 13:31:09 +01:00
if ( ! counter ) { counter + + ; } // Skip 0 as it is not allowed
2017-10-18 17:22:34 +01:00
} while ( counter ! = web_log_index ) ;
2018-01-30 13:14:55 +00:00
// XML encoding to fix blank console log in concert with javascript decodeURIComponent
message . replace ( F ( " % " ) , F ( " %25 " ) ) ; // Needs to be done first as otherwise the % in %26 will also be converted
2018-01-26 14:21:57 +00:00
message . replace ( F ( " & " ) , F ( " %26 " ) ) ;
2018-01-30 13:14:55 +00:00
message . replace ( F ( " < " ) , F ( " %3C " ) ) ;
message . replace ( F ( " > " ) , F ( " %3E " ) ) ;
2017-02-24 17:17:48 +00:00
}
2018-01-30 13:14:55 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " <r><i>%d</i><j>%d</j><l> " ) , web_log_index , last_reset_web_log_flag ) ;
2018-01-26 14:21:57 +00:00
message . replace ( F ( " }9 " ) , mqtt_data ) ; // Save to load here
message + = F ( " </l></r> " ) ;
WebServer - > send ( 200 , FPSTR ( HDR_CTYPE_XML ) , message ) ;
2017-01-28 13:41:01 +00:00
}
2017-10-18 17:22:34 +01:00
void HandleRestart ( )
2017-01-28 13:41:01 +00:00
{
2018-04-20 13:31:09 +01:00
if ( HttpUser ( ) ) { return ; }
2017-10-18 17:22:34 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , S_LOG_HTTP , S_RESTART ) ;
2017-01-28 13:41:01 +00:00
String page = FPSTR ( HTTP_HEAD ) ;
2017-09-06 16:37:41 +01:00
page . replace ( F ( " {v} " ) , FPSTR ( S_RESTART ) ) ;
2018-01-24 16:31:20 +00:00
page + = FPSTR ( HTTP_HEAD_STYLE ) ;
2017-01-28 13:41:01 +00:00
page + = FPSTR ( HTTP_MSG_RSTRT ) ;
2017-10-18 17:22:34 +01:00
if ( HTTP_MANAGER = = webserver_state ) {
webserver_state = HTTP_ADMIN ;
2017-01-28 13:41:01 +00:00
} else {
page + = FPSTR ( HTTP_BTN_MAIN ) ;
}
2017-10-18 17:22:34 +01:00
ShowPage ( page ) ;
2017-01-28 13:41:01 +00:00
2018-05-28 14:52:42 +01:00
ShowWebSource ( SRC_WEBGUI ) ;
2017-10-18 17:22:34 +01:00
restart_flag = 2 ;
2017-01-28 13:41:01 +00:00
}
/********************************************************************************************/
2017-10-18 17:22:34 +01:00
void HandleNotFound ( )
2017-01-28 13:41:01 +00:00
{
2018-01-02 15:08:27 +00:00
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_HTTP "Not fount (%s)"), WebServer->uri().c_str());
// AddLog(LOG_LEVEL_DEBUG);
2018-04-20 13:31:09 +01:00
if ( CaptivePortal ( ) ) { return ; } // If captive portal redirect instead of displaying the error page.
2017-01-28 13:41:01 +00:00
2017-09-02 13:37:02 +01:00
# ifdef USE_EMULATION
2017-10-18 17:22:34 +01:00
String path = WebServer - > uri ( ) ;
2017-11-11 11:33:30 +00:00
if ( ( EMUL_HUE = = Settings . flag2 . emulation ) & & ( path . startsWith ( " /api " ) ) ) {
2017-10-18 17:22:34 +01:00
HandleHueApi ( & path ) ;
2017-01-29 20:36:12 +00:00
} else
# endif // USE_EMULATION
{
2018-01-24 16:31:20 +00:00
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , 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 ( uint8_t i = 0 ; i < WebServer - > args ( ) ; i + + ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , PSTR ( " %s %s: %s \n " ) , mqtt_data , WebServer - > argName ( i ) . c_str ( ) , WebServer - > arg ( i ) . c_str ( ) ) ;
2017-01-29 20:36:12 +00:00
}
2017-10-18 17:22:34 +01:00
SetHeader ( ) ;
2018-01-24 16:31:20 +00:00
WebServer - > send ( 404 , FPSTR ( HDR_CTYPE_PLAIN ) , mqtt_data ) ;
2017-01-28 13:41:01 +00: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. */
2017-10-18 17:22:34 +01:00
boolean CaptivePortal ( )
2017-01-28 13:41:01 +00:00
{
2017-10-18 17:22:34 +01:00
if ( ( HTTP_MANAGER = = webserver_state ) & & ! ValidIpAddress ( WebServer - > hostHeader ( ) ) ) {
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( D_LOG_HTTP D_REDIRECTED ) ) ;
2017-01-28 13:41:01 +00:00
2017-10-18 17:22:34 +01:00
WebServer - > sendHeader ( F ( " Location " ) , String ( " http:// " ) + WebServer - > client ( ) . localIP ( ) . toString ( ) , true ) ;
2018-01-30 13:14:55 +00:00
WebServer - > send ( 302 , FPSTR ( HDR_CTYPE_PLAIN ) , " " ) ; // Empty content inhibits Content-length header so we have to close the socket ourselves.
WebServer - > client ( ) . stop ( ) ; // Stop is needed because we sent no content length
2017-01-28 13:41:01 +00:00
return true ;
}
return false ;
}
/** Is this an IP? */
2017-10-18 17:22:34 +01:00
boolean ValidIpAddress ( String str )
2017-01-28 13:41:01 +00:00
{
for ( uint16_t i = 0 ; i < str . length ( ) ; i + + ) {
int c = str . charAt ( i ) ;
2018-04-20 13:31:09 +01:00
if ( c ! = ' . ' & & ( c < ' 0 ' | | c > ' 9 ' ) ) { return false ; }
2017-01-28 13:41:01 +00:00
}
return true ;
}
2018-05-28 10:35:23 +01:00
/*********************************************************************************************/
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 ] ;
}
*/
if ( ' ' = = decodedChar ) {
encoded + = ' % ' ;
encoded + = hex [ decodedChar > > 4 ] ;
encoded + = hex [ decodedChar & 0xF ] ;
} else {
encoded + = decodedChar ;
}
}
return encoded ;
}
int WebSend ( char * buffer )
{
// http://192.168.178.86:80/cm?user=admin&password=joker&cmnd=POWER1 ON
// http://192.168.178.86:80/cm?cmnd=POWER1 ON
// [192.168.178.86:80,admin:joker] POWER1 ON
char * host ;
char * port ;
char * user ;
char * password ;
char * command ;
uint16_t nport = 80 ;
int status = 1 ; // Wrong parameters
host = strtok_r ( buffer , " ] " , & command ) ; // buffer = [192.168.178.86:80,admin:joker] POWER1 ON
if ( host & & command ) {
host = LTrim ( host ) ;
host + + ; // Skip [
host = strtok_r ( host , " , " , & user ) ; // host = 192.168.178.86:80,admin:joker > 192.168.178.86:80
host = strtok_r ( host , " : " , & port ) ; // host = 192.168.178.86:80 > 192.168.178.86
if ( user ) {
user = strtok_r ( user , " : " , & password ) ; // user = admin:joker > admin
}
//snprintf_P(log_data, sizeof(log_data), PSTR("DBG: Buffer |%X|, Host |%X|, Port |%X|, User |%X|, Password |%X|, Command |%X|"), buffer, host, port, user, password, command);
//AddLog(LOG_LEVEL_DEBUG);
if ( port ) { nport = atoi ( port ) ; }
String nuri = " " ;
if ( user & & password ) {
nuri + = F ( " user= " ) ;
nuri + = user ;
nuri + = F ( " &password= " ) ;
nuri + = password ;
nuri + = F ( " & " ) ;
}
nuri + = F ( " cmnd= " ) ;
nuri + = LTrim ( command ) ;
String uri = UrlEncode ( nuri ) ;
IPAddress host_ip ;
if ( WiFi . hostByName ( host , host_ip ) ) {
WiFiClient client ;
bool connected = false ;
byte retry = 2 ;
while ( ( retry > 0 ) & & ! connected ) {
- - retry ;
connected = client . connect ( host_ip , nport ) ;
if ( connected ) break ;
}
if ( connected ) {
String url = F ( " GET /cm? " ) ;
url + = uri ;
url + = F ( " HTTP/1.1 \r \n Host: " ) ;
url + = IPAddress ( host_ip ) . toString ( ) ;
if ( port ) {
url + = F ( " \r \n Port: " ) ;
url + = port ;
}
url + = F ( " \r \n Connection: close \r \n \r \n " ) ;
//snprintf_P(log_data, sizeof(log_data), PSTR("DBG: Url |%s|"), url.c_str());
//AddLog(LOG_LEVEL_DEBUG);
client . print ( url . c_str ( ) ) ;
client . flush ( ) ;
client . stop ( ) ;
status = 0 ; // No error - Done
} else {
status = 2 ; // Connection failed
}
} else {
status = 3 ; // Host not found
}
}
return status ;
}
/*********************************************************************************************/
enum WebCommands { CMND_WEBSERVER , CMND_WEBPASSWORD , CMND_WEBLOG , CMND_WEBSEND , CMND_EMULATION } ;
const char kWebCommands [ ] PROGMEM = D_CMND_WEBSERVER " | " D_CMND_WEBPASSWORD " | " D_CMND_WEBLOG " | " D_CMND_WEBSEND " | " D_CMND_EMULATION ;
const char kWebSendStatus [ ] PROGMEM = D_JSON_DONE " | " D_JSON_WRONG_PARAMETERS " | " D_JSON_CONNECT_FAILED " | " D_JSON_HOST_NOT_FOUND ;
bool WebCommand ( )
{
char command [ CMDSZ ] ;
bool serviced = true ;
int command_code = GetCommandCode ( command , sizeof ( command ) , XdrvMailbox . topic , kWebCommands ) ;
if ( - 1 = = command_code ) {
serviced = false ; // Unknown command
}
if ( CMND_WEBSERVER = = command_code ) {
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 2 ) ) { Settings . webserver = XdrvMailbox . payload ; }
if ( Settings . webserver ) {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , 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 {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , GetStateText ( 0 ) ) ;
}
}
else if ( CMND_WEBPASSWORD = = command_code ) {
if ( ( XdrvMailbox . data_len > 0 ) & & ( XdrvMailbox . data_len < sizeof ( Settings . web_password ) ) ) {
strlcpy ( Settings . web_password , ( ! strcmp ( XdrvMailbox . data , " 0 " ) ) ? " " : ( 1 = = XdrvMailbox . payload ) ? WEB_PASSWORD : XdrvMailbox . data , sizeof ( Settings . web_password ) ) ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , Settings . web_password ) ;
} else {
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_ASTERIX , command ) ;
}
}
else if ( CMND_WEBLOG = = command_code ) {
if ( ( XdrvMailbox . payload > = LOG_LEVEL_NONE ) & & ( XdrvMailbox . payload < = LOG_LEVEL_ALL ) ) { Settings . weblog_level = XdrvMailbox . payload ; }
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . weblog_level ) ;
}
else if ( CMND_WEBSEND = = command_code ) {
if ( XdrvMailbox . data_len > 0 ) {
uint8_t result = WebSend ( XdrvMailbox . data ) ;
char stemp1 [ 20 ] ;
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_SVALUE , command , GetTextIndexed ( stemp1 , sizeof ( stemp1 ) , result , kWebSendStatus ) ) ;
}
}
# ifdef USE_EMULATION
else if ( CMND_EMULATION = = command_code ) {
if ( ( XdrvMailbox . payload > = EMUL_NONE ) & & ( XdrvMailbox . payload < EMUL_MAX ) ) {
Settings . flag2 . emulation = XdrvMailbox . payload ;
restart_flag = 2 ;
}
snprintf_P ( mqtt_data , sizeof ( mqtt_data ) , S_JSON_COMMAND_NVALUE , command , Settings . flag2 . emulation ) ;
}
# endif // USE_EMULATION
else serviced = false ; // Unknown command
return serviced ;
}
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define XDRV_02
boolean Xdrv02 ( byte function )
{
boolean result = false ;
switch ( function ) {
case FUNC_LOOP :
PollDnsWebserver ( ) ;
# ifdef USE_EMULATION
if ( Settings . flag2 . emulation ) PollUdp ( ) ;
# endif // USE_EMULATION
break ;
case FUNC_COMMAND :
result = WebCommand ( ) ;
break ;
}
return result ;
}
2017-08-08 15:08:08 +01:00
# endif // USE_WEBSERVER