2018-11-26 11:58:15 +00:00
/*
* This file is part of the " bluetoothheater " distribution
* ( https : //gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright ( C ) 2018 Ray Jones < ray @ mrjones . id . au >
* Copyright ( C ) 2018 James Clark
*
* 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 < https : //www.gnu.org/licenses/>.
*
*/
2019-05-30 10:31:34 +00:00
# define USE_EMBEDDED_WEBUPDATECODE
2018-11-07 04:07:11 +00:00
2019-07-07 07:18:38 +00:00
# include <Arduino.h>
# include "BTCWifi.h"
2018-11-07 04:07:11 +00:00
# include "BTCWebServer.h"
2019-07-09 12:19:21 +00:00
# include "BTCota.h"
2018-12-16 07:34:39 +00:00
# include "../Utility/DebugPort.h"
# include "../Protocol/TxManage.h"
2019-06-15 23:09:29 +00:00
# include "../Utility/helpers.h"
2018-12-16 07:34:39 +00:00
# include "../cfg/pins.h"
2019-05-18 08:49:22 +00:00
# include "../cfg/BTCConfig.h"
2018-12-16 07:34:39 +00:00
# include "../Utility/BTC_JSON.h"
# include "../Utility/Moderator.h"
2019-07-25 07:40:23 +00:00
# include "../../lib/WiFiManager-dev/WiFiManager.h"
2019-01-20 10:14:45 +00:00
# include <SPIFFS.h>
2019-05-16 11:12:29 +00:00
# include "../Utility/NVStorage.h"
2019-07-07 07:18:38 +00:00
# include <WiFiClient.h>
# include <WebServer.h>
# include <ESPmDNS.h>
2019-07-18 12:28:40 +00:00
# include "BrowserUpload.h"
2019-07-07 07:18:38 +00:00
# include <Update.h>
2019-01-11 08:50:27 +00:00
extern WiFiManager wm ;
2019-07-06 13:46:20 +00:00
extern const char * stdHeader ;
extern const char * formatIndex ;
extern const char * updateIndex ;
extern const char * formatDoneContent ;
2019-07-15 09:56:36 +00:00
extern const char * rebootIndex ;
2018-11-07 04:07:11 +00:00
2019-07-18 12:28:40 +00:00
sBrowserUpload BrowserUpload ;
2018-11-07 04:07:11 +00:00
WebServer server ( 80 ) ;
2018-11-26 10:26:38 +00:00
WebSocketsServer webSocket = WebSocketsServer ( 81 ) ;
2018-12-12 09:03:44 +00:00
bool bRxWebData = false ; // flags for OLED animation
2018-12-01 18:25:10 +00:00
bool bTxWebData = false ;
2019-05-14 11:29:35 +00:00
bool bUpdateAccessed = false ; // flag used to ensure web update always starts via /update. direct accesses to /updatenow will FAIL
2019-07-06 13:46:20 +00:00
bool bFormatAccessed = false ;
2019-07-11 08:55:31 +00:00
bool bFormatPerformed = false ;
2019-05-22 20:35:09 +00:00
long _SuppliedFileSize = 0 ;
2018-11-07 04:07:11 +00:00
2019-07-07 07:18:38 +00:00
void webSocketEvent ( uint8_t num , WStype_t type , uint8_t * payload , size_t length ) ;
2019-06-30 00:37:24 +00:00
bool checkFile ( File & file ) ;
2019-07-06 13:46:20 +00:00
void addTableData ( String & HTML , String dta ) ;
void rootRedirect ( ) ;
String getContentType ( String filename ) ;
bool handleFileRead ( String path ) ;
2019-07-07 07:18:38 +00:00
void onNotFound ( ) ;
void onErase ( ) ;
2019-07-06 13:46:20 +00:00
void onFormatSPIFFS ( ) ;
void onFormatNow ( ) ;
void onFormatDone ( ) ;
2019-07-15 09:56:36 +00:00
void onReboot ( ) ;
void onDoReboot ( ) ;
2019-07-06 13:46:20 +00:00
void onWMConfig ( ) ;
2019-07-07 07:18:38 +00:00
void onResetWifi ( ) ;
2019-07-06 13:46:20 +00:00
void onUploadBegin ( ) ;
void onUploadCompletion ( ) ;
void onUploadProgression ( ) ;
2019-07-15 09:56:36 +00:00
void onRename ( ) ;
2019-07-06 13:46:20 +00:00
void build404Response ( String & content , String file ) ;
void build500Response ( String & content , String file ) ;
void initWebServer ( void ) {
if ( MDNS . begin ( " Afterburner " ) ) {
DebugPort . println ( " MDNS responder started " ) ;
}
server . on ( " /wmconfig " , onWMConfig ) ;
2019-07-07 07:18:38 +00:00
server . on ( " /resetwifi " , onResetWifi ) ;
server . on ( " /erase " , HTTP_POST , onErase ) ; // erase file from SPIFFS
2019-07-06 13:46:20 +00:00
// Magical code originally shamelessly lifted from Arduino WebUpdate example, then greatly modified
// This allows pushing new firmware to the ESP from a WEB BROWSER!
// Added authentication and a sequencing flag to ensure this is not bypassed
// You can also upload files to SPIFFS via this same portal
//
// Initial launch page
server . on ( " /update " , HTTP_GET , onUploadBegin ) ;
// handle attempts to browse the /updatenow path - force redirect to root
server . on ( " /updatenow " , HTTP_GET , [ ] ( ) {
DebugPort . println ( " WEB: GET /updatenow - ILLEGAL - root redirect " ) ;
rootRedirect ( ) ;
} ) ;
// valid upload attempts must use post, AND they must have also passed thru /update (bUpdateAccessed = true)
server . on ( " /updatenow " , HTTP_POST , onUploadCompletion , onUploadProgression ) ;
2018-11-07 04:07:11 +00:00
2019-07-06 13:46:20 +00:00
// SPIFFS formatting
server . on ( " /formatspiffs " , HTTP_GET , onFormatSPIFFS ) ;
server . on ( " /formatnow " , HTTP_GET , [ ] ( ) { // deny browse access
DebugPort . println ( " WEB: GET /formatnow - ILLEGAL - root redirect " ) ;
rootRedirect ( ) ;
} ) ;
server . on ( " /formatnow " , HTTP_POST , onFormatNow ) ; // access via POST is legal, but only if bFormatAccess == true
2019-07-15 09:56:36 +00:00
server . on ( " /reboot " , HTTP_GET , onReboot ) ; // access via POST is legal, but only if bFormatAccess == true
server . on ( " /reboot " , HTTP_POST , onDoReboot ) ; // access via POST is legal, but only if bFormatAccess == true
server . on ( " /rename " , HTTP_POST , onRename ) ; // access via POST is legal, but only if bFormatAccess == true
// NOTE: this serves the default home page, and favicon.ico
2019-07-06 13:46:20 +00:00
server . onNotFound ( [ ] ( )
{ // If the client requests any URI
if ( ! handleFileRead ( server . uri ( ) ) ) { // send it if it exists
2019-07-07 07:18:38 +00:00
onNotFound ( ) ;
2019-07-06 13:46:20 +00:00
}
} ) ;
server . begin ( ) ;
webSocket . begin ( ) ;
webSocket . onEvent ( webSocketEvent ) ;
DebugPort . println ( " HTTP server started " ) ;
}
// called by main sketch loop()
bool doWebServer ( void )
{
webSocket . loop ( ) ;
server . handleClient ( ) ;
return true ;
}
2019-01-20 10:14:45 +00:00
String getContentType ( String filename ) { // convert the file extension to the MIME type
if ( filename . endsWith ( " .html " ) ) return " text/html " ;
else if ( filename . endsWith ( " .css " ) ) return " text/css " ;
else if ( filename . endsWith ( " .js " ) ) return " application/javascript " ;
else if ( filename . endsWith ( " .ico " ) ) return " image/x-icon " ;
2019-05-21 12:01:42 +00:00
else if ( filename . endsWith ( " .bin " ) ) return " application/octet-stream " ;
2019-07-15 09:56:36 +00:00
else if ( filename . endsWith ( " .zip " ) ) return " application/x-zip " ;
else if ( filename . endsWith ( " .gz " ) ) return " application/x-gzip " ;
2019-01-20 10:14:45 +00:00
return " text/plain " ;
}
bool handleFileRead ( String path ) { // send the right file to the client (if it exists)
DebugPort . println ( " handleFileRead: " + path ) ;
if ( path . endsWith ( " / " ) ) path + = " index.html " ; // If a folder is requested, send the index file
String contentType = getContentType ( path ) ; // Get the MIME type
2019-07-15 09:56:36 +00:00
String pathWithGz = path + " .gz " ;
if ( SPIFFS . exists ( pathWithGz ) | | SPIFFS . exists ( path ) ) { // If the file exists as a compressed archive, or normal
if ( SPIFFS . exists ( pathWithGz ) ) // If the compressed file exists
path + = " .gz " ;
2019-01-20 10:14:45 +00:00
File file = SPIFFS . open ( path , " r " ) ; // Open it
2019-06-30 00:37:24 +00:00
if ( ! checkFile ( file ) ) { // check it is readable
2019-07-06 13:46:20 +00:00
file . close ( ) ; // if not, close the file
2019-06-30 00:37:24 +00:00
}
if ( ! file ) {
2019-07-06 13:46:20 +00:00
DebugPort . println ( " \t File exists, but could not be read? " ) ; // dodgy file - throw error back to client
String content ;
build500Response ( content , path ) ;
server . send ( 500 , " text/html " , content ) ;
return false ; // If the file is broken, return false
2019-06-30 00:37:24 +00:00
}
else {
2019-07-06 13:46:20 +00:00
server . streamFile ( file , contentType ) ; // File good, send it to the client
file . close ( ) ; // Then close the file
return true ;
2019-06-30 00:37:24 +00:00
}
2019-01-20 10:14:45 +00:00
}
DebugPort . println ( " \t File Not Found " ) ;
return false ; // If the file doesn't exist, return false
}
2019-07-06 13:46:20 +00:00
const char * stdHeader = R " =====(
< ! DOCTYPE html >
< html lang = " en " >
< head >
< meta charset = " utf-8 " / >
< meta http - equiv = " Pragma " content = " no-cache " >
< meta http - equiv = " Expires " content = " -1 " >
< meta http - equiv = " CACHE-CONTROL " content = " NO-CACHE " >
< style >
2019-07-11 08:55:31 +00:00
body {
font - family : Arial , Helvetica , sans - serif ;
zoom : 200 % ;
}
button {
background - color : # 016 ABC ;
color : # fff ;
border - radius : 25 px ;
2019-07-15 09:56:36 +00:00
height : 30 px ;
2019-07-11 08:55:31 +00:00
}
. del {
color : white ;
font - weight : bold ;
background - color : red ;
border - radius : 50 % ;
height : 30 px ;
width : 30 px ;
}
2019-07-15 09:56:36 +00:00
. redbutton {
2019-07-11 08:55:31 +00:00
color : white ;
font - weight : bold ;
background - color : red ;
}
th {
text - align : left ;
}
. throb {
animation : throbber 1 s linear infinite ;
}
@ keyframes throbber {
50 % {
opacity : 0 ;
}
}
2019-07-06 13:46:20 +00:00
< / style >
2019-07-15 09:56:36 +00:00
< script >
function _ ( el ) {
return document . getElementById ( el ) ;
}
< / script >
2019-07-06 13:46:20 +00:00
) = = = = = " ;
const char * updateIndex = R " =====(
2019-07-11 08:55:31 +00:00
< style >
body {
background - color : yellowgreen ;
}
. inputfile {
width : 0.1 px ;
height : 0.1 px ;
opacity : 0 ;
overflow : hidden ;
position : absolute ;
z - index : - 1 ;
}
. inputfile + label {
color : # fff ;
background - color : # 016 ABC ;
display : inline - block ;
border - style : solid ;
border - radius : 25 px ;
border - width : medium ;
border - top - color : # E3E3E3 ;
border - left - color : # E3E3E3 ;
border - right - color : # 979797 ;
border - bottom - color : # 979797 ;
}
# filename {
font - weight : bold ;
font - style : italic ;
}
# upload {
font - weight : bold ;
font - style : italic ;
}
< / style >
2019-07-06 13:46:20 +00:00
< script >
// globals
var sendSize ;
var ws ;
2019-07-11 08:55:31 +00:00
var timeDown ;
var timeUp ;
2019-07-17 09:35:34 +00:00
var ajax ;
var uploadErr ;
2019-07-06 13:46:20 +00:00
function onWebSocket ( event ) {
var response = JSON . parse ( event . data ) ;
var key ;
for ( key in response ) {
switch ( key ) {
2019-07-17 09:35:34 +00:00
case ' progress ' :
2019-07-06 13:46:20 +00:00
// actual data bytes received as fed back via web socket
2019-07-18 12:28:40 +00:00
var progress = response [ key ] ;
if ( progress > = 0 ) {
2019-07-17 09:35:34 +00:00
// normal progression
2019-07-18 12:28:40 +00:00
_ ( ' loaded_n_total ' ) . innerHTML = ' Uploaded ' + progress + ' bytes of ' + sendSize ;
var percent = Math . round ( 100 * ( progress / sendSize ) ) ;
2019-07-17 09:35:34 +00:00
_ ( ' progressBar ' ) . value = percent ;
_ ( ' status ' ) . innerHTML = percent + ' % uploaded . . please wait ' ;
uploadErr = ' ' ;
}
else {
// upload failure
_ ( ' progressBar ' ) . value = 0 ;
2019-07-18 12:28:40 +00:00
switch ( progress ) {
case - 1 : uploadErr = ' File too large - SPIFFS upload ABORTED ' ; break ;
case - 2 : uploadErr = ' Write error - SPIFFS upload ABORTED ' ; break ;
case - 3 : uploadErr = ' Update error - Firmware upload ABORTED ' ; break ;
case - 4 : uploadErr = ' Invalid file - Firmware upload ABORTED ' ; break ;
}
2019-07-17 09:35:34 +00:00
ajax . abort ( ) ;
}
2019-07-06 13:46:20 +00:00
break ;
}
}
}
function init ( ) {
ws = new WebSocket ( ' ws : //' + window.location.hostname + ':81/');
ws . onmessage = onWebSocket ;
}
function uploadFile ( ) {
2019-07-18 12:28:40 +00:00
_ ( ' upload_form ' ) . hidden = true ;
2019-07-17 09:35:34 +00:00
_ ( ' cancel ' ) . hidden = true ;
_ ( ' upload ' ) . hidden = true ;
_ ( ' progressBar ' ) . hidden = false ;
var file = _ ( ' file1 ' ) . files [ 0 ] ;
2019-07-06 13:46:20 +00:00
sendSize = file . size ;
2019-07-11 08:55:31 +00:00
console . log ( file ) ;
2019-07-06 13:46:20 +00:00
var JSONmsg = { } ;
JSONmsg [ ' UploadSize ' ] = sendSize ;
var str = JSON . stringify ( JSONmsg ) ;
2019-07-17 09:35:34 +00:00
console . log ( ' JSON Tx : ' , str ) ;
2019-07-06 13:46:20 +00:00
ws . send ( str ) ;
var formdata = new FormData ( ) ;
2019-07-17 09:35:34 +00:00
formdata . append ( ' update ' , file ) ;
ajax = new XMLHttpRequest ( ) ;
// progress feedback is handled via websocket JSON sent from controller
2019-07-06 13:46:20 +00:00
// using server side progress only shows the buffer filling, not actual delivery.
2019-07-17 09:35:34 +00:00
ajax . addEventListener ( ' load ' , completeHandler , false ) ;
ajax . addEventListener ( ' error ' , errorHandler , false ) ;
ajax . addEventListener ( ' abort ' , abortHandler , false ) ;
ajax . open ( ' POST ' , ' / updatenow ' ) ;
2019-07-06 13:46:20 +00:00
ajax . send ( formdata ) ;
}
function completeHandler ( event ) {
2019-07-17 09:35:34 +00:00
_ ( ' status ' ) . innerHTML = event . target . responseText ;
_ ( ' progressBar ' ) . hidden = true ;
_ ( ' progressBar ' ) . value = 0 ;
_ ( ' loaded_n_total ' ) . innerHTML = ' Uploaded ' + sendSize + ' bytes of ' + sendSize ;
var file = _ ( ' file1 ' ) . files [ 0 ] ;
if ( file . name . endsWith ( ' . bin ' ) ) {
2019-07-23 11:11:29 +00:00
_ ( ' status ' ) . innerHTML = ' Rebooting NOW ' ;
setTimeout ( function ( ) { _ ( ' status ' ) . innerHTML = ' Rebooted ' ; } , 2000 ) ;
setTimeout ( function ( ) { _ ( ' status ' ) . innerHTML = ' Initialising . . . ' ; } , 4000 ) ;
2019-07-23 12:56:04 +00:00
setTimeout ( function ( ) { _ ( ' status ' ) . innerHTML = ' Loading / index . html . . . ' ; location . assign ( ' / ' ) ; } , 7500 ) ;
2019-07-06 13:46:20 +00:00
}
else {
setTimeout ( function ( ) { location . assign ( ' / update ' ) ; } , 500 ) ;
}
}
function errorHandler ( event ) {
2019-07-17 09:35:34 +00:00
console . log ( ' Error Handler ' ) ;
_ ( ' status ' ) . innerHTML = ' Upload Error ? ' ;
_ ( ' status ' ) . style . color = ' red ' ;
setTimeout ( function ( ) { location . reload ( ) ; } , 2000 ) ;
2019-07-06 13:46:20 +00:00
}
function abortHandler ( event ) {
2019-07-17 09:35:34 +00:00
console . log ( ' Abort Handler ' + event ) ;
_ ( ' status ' ) . innerHTML = uploadErr ;
_ ( ' status ' ) . style . color = ' red ' ;
setTimeout ( function ( ) { location . reload ( ) ; } , 2000 ) ;
2019-07-06 13:46:20 +00:00
}
function onErase ( fn ) {
if ( confirm ( ' Do you really want to erase ' + fn + ' ? ' ) ) {
var formdata = new FormData ( ) ;
2019-07-17 09:35:34 +00:00
formdata . append ( ' filename ' , fn ) ;
2019-07-06 13:46:20 +00:00
var ajax = new XMLHttpRequest ( ) ;
2019-07-17 09:35:34 +00:00
ajax . open ( ' POST ' , ' / erase ' ) ;
2019-07-06 13:46:20 +00:00
ajax . send ( formdata ) ;
setTimeout ( function ( ) { location . reload ( ) ; } , 500 ) ;
}
}
2019-07-15 09:56:36 +00:00
function onRename ( fn ) {
2019-07-17 09:35:34 +00:00
var newname = prompt ( ' Enter new file name ' , fn ) ;
if ( newname ! = null & & newname ! = ' ' ) {
2019-07-15 09:56:36 +00:00
var formdata = new FormData ( ) ;
2019-07-17 09:35:34 +00:00
formdata . append ( ' oldname ' , fn ) ;
formdata . append ( ' newname ' , newname ) ;
2019-07-15 09:56:36 +00:00
var ajax = new XMLHttpRequest ( ) ;
2019-07-17 09:35:34 +00:00
ajax . open ( ' POST ' , ' / rename ' ) ;
2019-07-15 09:56:36 +00:00
ajax . send ( formdata ) ;
setTimeout ( function ( ) { location . reload ( ) ; } , 500 ) ;
}
}
2019-07-06 13:46:20 +00:00
function onBrowseChange ( ) {
2019-07-17 09:35:34 +00:00
_ ( ' uploaddiv ' ) . hidden = false ;
_ ( ' upload ' ) . hidden = false ;
_ ( ' status ' ) . hidden = false ;
_ ( ' loaded_n_total ' ) . hidden = false ;
_ ( ' spacer ' ) . hidden = false ;
var file = _ ( ' file1 ' ) . files [ 0 ] ;
2019-07-15 09:56:36 +00:00
_ ( ' filename ' ) . innerHTML = file . name ;
2019-07-11 08:55:31 +00:00
}
function onformatClick ( ) {
2019-07-17 09:35:34 +00:00
location . assign ( ' / formatspiffs ' ) ;
2019-07-06 13:46:20 +00:00
}
2019-07-11 08:55:31 +00:00
2019-07-06 13:46:20 +00:00
< / script >
< title > Afterburner update < / title >
2019-07-11 08:55:31 +00:00
< / head >
2019-07-17 09:35:34 +00:00
< body onload = ' javascript : init ( ) ' >
2019-07-06 13:46:20 +00:00
< h1 > Afterburner update < / h1 >
2019-07-11 08:55:31 +00:00
< form id = ' upload_form ' method = ' POST ' enctype = ' multipart / form - data ' autocomplete = ' off ' >
< input type = ' file ' name = ' file1 ' id = ' file1 ' class = ' inputfile ' onchange = ' onBrowseChange ( ) ' / >
< label for = ' file1 ' > & nbsp ; & nbsp ; Select a file to upload & nbsp ; & nbsp ; < / label >
2019-07-06 13:46:20 +00:00
< / form >
2019-07-11 08:55:31 +00:00
< p >
2019-07-17 09:35:34 +00:00
< div id = ' uploaddiv ' hidden > < span id = ' filename ' > < / span > & nbsp ; < button id = ' upload ' class = ' throb ' onclick = ' uploadFile ( ) ' hidden > Upload < / button >
2019-07-11 08:55:31 +00:00
< progress id = ' progressBar ' value = ' 0 ' max = ' 100 ' style = ' width : 300 px ; ' hidden > < / progress > < p > < / div >
< p id = ' spacer ' hidden > < / p >
2019-07-17 09:35:34 +00:00
< div > < button onclick = location . assign ( ' / ' ) id = ' cancel ' > Cancel < / button > < / div >
2019-07-11 08:55:31 +00:00
< h3 id = ' status ' hidden > < / h3 >
< div id = ' loaded_n_total ' hidden > < / div >
2019-07-06 13:46:20 +00:00
) = = = = = " ;
void onWMConfig ( )
2019-06-30 00:37:24 +00:00
{
2019-05-22 11:08:38 +00:00
DebugPort . println ( " WEB: GET /wmconfig " ) ;
2019-01-16 09:22:17 +00:00
server . send ( 200 , " text/plain " , " Start Config Portal - Retaining credential " ) ;
2019-01-11 08:28:22 +00:00
DebugPort . println ( " Starting web portal for wifi config " ) ;
2019-01-16 09:22:17 +00:00
delay ( 500 ) ;
wifiEnterConfigPortal ( true , false , 3000 ) ;
2019-01-11 08:28:22 +00:00
}
2019-01-13 19:59:32 +00:00
2019-07-07 07:18:38 +00:00
void onResetWifi ( )
2019-06-30 00:37:24 +00:00
{
2019-05-22 11:08:38 +00:00
DebugPort . println ( " WEB: GET /resetwifi " ) ;
2019-01-16 09:22:17 +00:00
server . send ( 200 , " text/plain " , " Start Config Portal - Resetting Wifi credentials! " ) ;
2019-01-12 21:32:13 +00:00
DebugPort . println ( " diconnecting client and wifi, then rebooting " ) ;
2019-01-16 09:22:17 +00:00
delay ( 500 ) ;
wifiEnterConfigPortal ( true , true , 3000 ) ;
2019-01-11 08:28:22 +00:00
}
2019-02-11 08:34:11 +00:00
2019-07-07 07:18:38 +00:00
void onNotFound ( )
2019-06-30 00:37:24 +00:00
{
String path = server . uri ( ) ;
if ( path . endsWith ( " / " ) ) path + = " index.html " ; // If a folder is requested, send the index file
2019-07-06 13:46:20 +00:00
String message ;
build404Response ( message , path ) ;
2019-06-30 00:37:24 +00:00
server . send ( 404 , " text/html " , message ) ;
2018-11-07 04:07:11 +00:00
}
2019-05-16 11:12:29 +00:00
void rootRedirect ( )
{
2019-05-22 11:08:38 +00:00
server . sendHeader ( " Location " , " / " ) ; // reselect the update page
server . send ( 303 ) ;
2019-05-16 11:12:29 +00:00
}
2019-07-07 07:18:38 +00:00
bool sendWebSocketString ( const char * Str )
2018-12-19 12:07:51 +00:00
{
2019-07-17 09:35:34 +00:00
# ifdef WEBTIMES
CProfile profile ;
# endif
2018-12-19 12:07:51 +00:00
if ( webSocket . connectedClients ( ) ) {
2019-07-17 09:35:34 +00:00
# ifdef WEBTIMES
unsigned long tCon = profile . elapsed ( true ) ;
# endif
2018-12-19 12:07:51 +00:00
bTxWebData = true ; // OLED tx data animation flag
webSocket . broadcastTXT ( Str ) ;
2019-07-17 09:35:34 +00:00
# ifdef WEBTIMES
unsigned long tWeb = profile . elapsed ( true ) ;
DebugPort . printf ( " Websend times : %ld,%ld \r \n " , tCon , tWeb ) ;
# endif
2018-12-01 18:25:10 +00:00
return true ;
}
return false ;
2018-11-07 04:07:11 +00:00
}
2018-12-19 12:07:51 +00:00
2019-06-02 20:34:45 +00:00
void webSocketEvent ( uint8_t num , WStype_t type , uint8_t * payload , size_t length )
{
2018-11-26 10:26:38 +00:00
if ( type = = WStype_TEXT ) {
2018-12-11 10:19:02 +00:00
bRxWebData = true ;
char cmd [ 256 ] ;
memset ( cmd , 0 , 256 ) ;
for ( int i = 0 ; i < length & & i < 256 ; i + + ) {
2018-11-26 10:26:38 +00:00
cmd [ i ] = payload [ i ] ;
}
2018-12-11 10:19:02 +00:00
interpretJsonCommand ( cmd ) ; // send to the main heater controller decode routine
2018-12-01 18:25:10 +00:00
}
}
2019-07-07 07:18:38 +00:00
bool isWebSocketClientChange ( )
{
static int prevNumClients = - 1 ;
int numClients = webSocket . connectedClients ( ) ;
if ( numClients ! = prevNumClients ) {
prevNumClients = numClients ;
DebugPort . println ( " Changed number of web clients, should reset JSON moderator " ) ;
return true ;
}
return false ;
}
2018-12-01 18:25:10 +00:00
bool hasWebClientSpoken ( bool reset )
{
bool retval = bRxWebData ;
if ( reset )
bRxWebData = false ;
return retval ;
}
bool hasWebServerSpoken ( bool reset )
{
bool retval = bTxWebData ;
if ( reset )
bTxWebData = false ;
return retval ;
2018-11-26 10:26:38 +00:00
}
2018-12-11 10:19:02 +00:00
2019-05-22 20:35:09 +00:00
void setUploadSize ( long val )
{
_SuppliedFileSize = val ;
} ;
2019-06-30 00:37:24 +00:00
// Sometimes SPIFFS gets corrupted (WTF?)
// When this happens, you can see the files exist, but you cannot read them
// This routine checks the file is readable.
// Typical failure mechanism is read returns 0, and the WifiClient upload never progresses
// The software watchdog then steps in after 15 seconds of that nonsense
bool checkFile ( File & file )
{
uint8_t buf [ 128 ] ;
bool bOK = true ;
size_t available = file . available ( ) ;
while ( available ) {
int toRead = ( available > 128 ) ? 128 : available ;
int Read = file . read ( buf , toRead ) ;
if ( Read ! = toRead ) {
bOK = false ;
DebugPort . printf ( " SPIFFS precautionary file check failed for %s \r \n " , file . name ( ) ) ;
break ;
}
available = file . available ( ) ;
}
file . seek ( 0 ) ;
return bOK ;
}
2019-07-07 07:18:38 +00:00
void listSPIFFS ( const char * dirname , uint8_t levels , String & HTMLreport , int withHTMLanchors )
2019-06-30 00:37:24 +00:00
{
char msg [ 128 ] ;
2019-07-07 07:18:38 +00:00
File root = SPIFFS . open ( dirname ) ;
2019-06-30 00:37:24 +00:00
if ( ! root ) {
sprintf ( msg , " Failed to open directory \" %s \" " , dirname ) ;
DebugPort . println ( msg ) ;
HTMLreport + = msg ; HTMLreport + = " <br> " ;
return ;
}
if ( ! root . isDirectory ( ) ) {
sprintf ( msg , " \" %s \" is not a directory " , dirname ) ;
DebugPort . println ( msg ) ;
HTMLreport + = msg ; HTMLreport + = " <br> " ;
return ;
}
2019-07-06 13:46:20 +00:00
HTMLreport + = " <hr><h3>Current SPIFFS contents:</h3> " ;
// create HTML table header
HTMLreport + = R " =====(<table>
< tr >
< th > < / th >
< th style = " width:200px " > Name < / th >
< th style = " width:60px " > Size < / th >
< th > < / th >
2019-07-15 09:56:36 +00:00
< th > < / th >
2019-07-06 13:46:20 +00:00
< / tr >
) = = = = = " ;
2019-06-30 00:37:24 +00:00
File file = root . openNextFile ( ) ;
while ( file ) {
2019-07-06 13:46:20 +00:00
HTMLreport + = " <tr> \n " ;
2019-06-30 00:37:24 +00:00
if ( file . isDirectory ( ) ) {
2019-07-06 13:46:20 +00:00
addTableData ( HTMLreport , " DIR " ) ;
addTableData ( HTMLreport , file . name ( ) ) ;
addTableData ( HTMLreport , " " ) ;
addTableData ( HTMLreport , " " ) ;
2019-07-15 09:56:36 +00:00
addTableData ( HTMLreport , " " ) ;
2019-07-06 13:46:20 +00:00
2019-06-30 00:37:24 +00:00
sprintf ( msg , " DIR : %s " , file . name ( ) ) ;
DebugPort . println ( msg ) ;
2019-07-06 13:46:20 +00:00
2019-06-30 00:37:24 +00:00
if ( levels ) {
2019-07-07 07:18:38 +00:00
listSPIFFS ( file . name ( ) , levels - 1 , HTMLreport ) ;
2019-06-30 00:37:24 +00:00
}
} else {
String fn = file . name ( ) ;
2019-07-06 13:46:20 +00:00
String ers ;
2019-07-15 09:56:36 +00:00
String rename ;
if ( withHTMLanchors = = 2 ) {
rename = " <button class='rename' onClick=onRename(' " + fn + " ')>Rename</button> " ;
2019-07-11 08:55:31 +00:00
ers = " <input class='del' type='button' value='X' onClick=onErase(' " + fn + " ')> " ;
2019-07-15 09:56:36 +00:00
}
2019-06-30 00:37:24 +00:00
if ( withHTMLanchors ) {
2019-07-15 09:56:36 +00:00
String fn2 ;
2019-07-17 09:35:34 +00:00
if ( fn . endsWith ( " .html " ) ) {
2019-07-15 20:29:23 +00:00
// can hyperlink .html files
2019-07-15 09:56:36 +00:00
fn2 = fn ;
}
2019-07-17 09:35:34 +00:00
else if ( fn . endsWith ( " .html.gz " ) ) {
// we can hyperlink .html.gz files but we must strip .gz extension for
2019-07-15 20:29:23 +00:00
// the hyperlink otherwise you get asked if you want to download the .gz, not view web page!
fn2 = fn ;
fn2 . remove ( fn2 . length ( ) - 3 , 3 ) ; // strip trailing ".gz"
2019-07-15 09:56:36 +00:00
}
if ( fn2 . length ( ) ! = 0 ) {
2019-07-15 20:29:23 +00:00
// create hyperlink if web page file
2019-07-15 09:56:36 +00:00
fn = " <a href= \" " + fn2 + " \" > " + file . name ( ) + " </a> " ;
2019-06-30 00:37:24 +00:00
}
}
2019-07-15 20:29:23 +00:00
String sz ( int ( file . size ( ) ) ) ;
2019-07-06 13:46:20 +00:00
addTableData ( HTMLreport , " " ) ;
addTableData ( HTMLreport , fn ) ;
addTableData ( HTMLreport , sz ) ;
2019-07-15 09:56:36 +00:00
addTableData ( HTMLreport , rename ) ;
2019-07-06 13:46:20 +00:00
addTableData ( HTMLreport , ers ) ;
sprintf ( msg , " FILE: %s SIZE: %d " , fn . c_str ( ) , file . size ( ) ) ;
2019-06-30 00:37:24 +00:00
DebugPort . println ( msg ) ;
}
2019-07-06 13:46:20 +00:00
HTMLreport + = " </tr> \n " ;
2019-06-30 00:37:24 +00:00
file = root . openNextFile ( ) ;
}
2019-07-06 13:46:20 +00:00
HTMLreport + = " </table> \n " ;
if ( withHTMLanchors ) {
char usage [ 128 ] ;
int used = SPIFFS . usedBytes ( ) ;
int total = SPIFFS . totalBytes ( ) ;
float percent = used * 100. / total ;
2019-07-07 07:18:38 +00:00
sprintf ( usage , " <p><b>Usage</b><br> %d / %d bytes (%.1f%%) \n <p> " , used , total , percent ) ;
2019-07-06 13:46:20 +00:00
HTMLreport + = usage ;
}
2019-06-30 00:37:24 +00:00
}
2019-07-06 13:46:20 +00:00
void addTableData ( String & HTML , String dta )
{
HTML + = " <td> " ;
HTML + = dta ;
HTML + = " </td> \n " ;
}
// erase a file from SPIFFS partition
2019-07-07 07:18:38 +00:00
void onErase ( )
2019-07-06 13:46:20 +00:00
{
String filename = server . arg ( " filename " ) ; // get request argument value by name
if ( filename . length ( ) ! = 0 ) {
2019-07-07 07:18:38 +00:00
DebugPort . printf ( " onErase: %s " , filename . c_str ( ) ) ;
2019-07-06 13:46:20 +00:00
if ( SPIFFS . exists ( filename . c_str ( ) ) ) {
SPIFFS . remove ( filename . c_str ( ) ) ;
DebugPort . println ( " ERASED \r \n " ) ;
}
else
DebugPort . println ( " NOT FOUND \r \n " ) ;
}
}
// function called upon completion of file (form) upload
void onUploadCompletion ( )
{
2019-07-09 12:19:21 +00:00
_SuppliedFileSize = 0 ;
2019-07-06 13:46:20 +00:00
DebugPort . println ( " WEB: POST /updatenow completion " ) ;
// completion functionality
2019-07-18 12:28:40 +00:00
if ( BrowserUpload . isSPIFFSupload ( ) ) {
if ( BrowserUpload . isOK ( ) ) {
2019-07-06 13:46:20 +00:00
DebugPort . println ( " WEB: SPIFFS OK " ) ;
server . send ( 200 , " text/plain " , " OK - File uploaded to SPIFFS " ) ;
// javascript reselects the /update page!
}
else {
DebugPort . println ( " WEB: SPIFFS FAIL " ) ;
server . send ( 500 , " text/plain " , " 500: couldn't create file " ) ;
}
2019-07-18 12:28:40 +00:00
BrowserUpload . reset ( ) ;
2019-07-06 13:46:20 +00:00
}
else {
2019-07-18 12:28:40 +00:00
if ( BrowserUpload . isOK ( ) ) {
DebugPort . println ( " WEB: FIRMWARE UPDATE OK " ) ;
server . send ( 200 , " text/plain " , " OK - Afterburner will reboot shortly " ) ;
2019-07-06 13:46:20 +00:00
}
else {
2019-07-18 12:28:40 +00:00
DebugPort . println ( " WEB: FIRMWARE UPDATE FAIL " ) ;
server . send ( 200 , " text/plain " , " FAIL - Afterburner will reboot shortly " ) ;
2019-07-06 13:46:20 +00:00
}
2019-07-25 11:27:57 +00:00
forceBootInit ( ) ;
2019-07-06 13:46:20 +00:00
delay ( 1000 ) ;
// javascript redirects to root page so we go there after reboot!
ESP . restart ( ) ; // reboot
}
}
void onUploadBegin ( )
{
DebugPort . println ( " WEB: GET /update " ) ;
sCredentials creds = NVstore . getCredentials ( ) ;
if ( ! server . authenticate ( creds . webUpdateUsername , creds . webUpdatePassword ) ) {
return server . requestAuthentication ( ) ;
}
bUpdateAccessed = true ;
bFormatAccessed = false ;
2019-07-11 08:55:31 +00:00
bFormatPerformed = false ;
2019-07-06 13:46:20 +00:00
# ifdef USE_EMBEDDED_WEBUPDATECODE
String SPIFFSinfo ;
2019-07-07 07:18:38 +00:00
listSPIFFS ( " / " , 2 , SPIFFSinfo , 2 ) ;
2019-07-06 13:46:20 +00:00
String content = stdHeader ;
content + = updateIndex + SPIFFSinfo ;
2019-07-15 09:56:36 +00:00
content + = " <p><button class='redbutton' onclick='onformatClick()'>Format SPIFFS</button> " ;
2019-07-06 13:46:20 +00:00
content + = " </body></html> " ;
server . send ( 200 , " text/html " , content ) ;
# else
handleFileRead ( " /uploadfirmware.html " ) ;
# endif
}
void onUploadProgression ( )
{
2019-07-18 12:28:40 +00:00
char JSON [ 64 ] ;
2019-07-06 13:46:20 +00:00
if ( bUpdateAccessed ) { // only allow progression via /update, attempts to directly access /updatenow will fail
HTTPUpload & upload = server . upload ( ) ;
2019-07-17 09:35:34 +00:00
String filename = upload . filename ;
if ( ! filename . startsWith ( " / " ) ) filename = " / " + filename ;
2019-07-09 12:19:21 +00:00
2019-07-17 09:35:34 +00:00
if ( upload . status = = UPLOAD_FILE_START ) {
2019-07-18 12:28:40 +00:00
int sts = BrowserUpload . begin ( filename , _SuppliedFileSize ) ;
sprintf ( JSON , " { \" progress \" :%d} " , sts ) ;
sendWebSocketString ( JSON ) ; // feedback proper byte count of update to browser via websocket
2019-07-06 13:46:20 +00:00
}
2019-07-18 12:28:40 +00:00
// handle file fragments of form upload
2019-07-06 13:46:20 +00:00
else if ( upload . status = = UPLOAD_FILE_WRITE ) {
# if USE_SW_WATCHDOG == 1
feedWatchdog ( ) ; // we get stuck here for a while, don't let the watchdog bite!
# endif
2019-07-18 12:28:40 +00:00
int sts = BrowserUpload . fragment ( upload ) ;
if ( sts < 0 ) {
sprintf ( JSON , " { \" progress \" :%d} " , sts ) ;
sendWebSocketString ( JSON ) ; // feedback -ve byte count of update to browser via websocket - write error
2019-07-06 13:46:20 +00:00
}
else {
2019-07-18 12:28:40 +00:00
// upload still in progress?
if ( BrowserUpload . bUploadActive ) { // show progress unless a write error has occured
DebugPort . print ( " . " ) ;
if ( upload . totalSize ) {
// feed back bytes received over web socket for progressbar update on browser (via javascript)
sprintf ( JSON , " { \" progress \" :%d} " , upload . totalSize ) ;
sendWebSocketString ( JSON ) ; // feedback proper byte count of update to browser via websocket
}
// show percentage on OLED
int percent = 0 ;
if ( _SuppliedFileSize )
percent = 100 * upload . totalSize / _SuppliedFileSize ;
ShowOTAScreen ( percent , eOTAbrowser ) ; // browser update
2019-07-06 13:46:20 +00:00
}
}
}
// handle end of upload
else if ( upload . status = = UPLOAD_FILE_END ) {
2019-07-18 12:28:40 +00:00
int sts = BrowserUpload . end ( upload ) ;
sprintf ( JSON , " { \" progress \" :%d} " , sts ) ;
sendWebSocketString ( JSON ) ; // feedback proper byte count of update to browser via websocket
2019-07-17 09:35:34 +00:00
delay ( 2000 ) ;
bUpdateAccessed = false ; // close gate on POST to /updatenow
2019-07-06 13:46:20 +00:00
} else {
DebugPort . printf ( " Update Failed Unexpectedly (likely broken connection): status=%d \r \n " , upload . status ) ;
2019-07-17 09:35:34 +00:00
bUpdateAccessed = false ; // close gate on POST to /updatenow
2019-07-06 13:46:20 +00:00
}
}
else {
// attempt to POST without using /update - forced redirect to root
DebugPort . println ( " WEB: POST /updatenow forbidden entry " ) ;
rootRedirect ( ) ;
}
}
/***************************************************************************************
* FORMAT SPIFFS HANDLING
*
* User must first access / formatspiffs .
* If not already authenticated , an Username / Password challenge is presented
* If that passes , bFormatAccessed is set , unlocking access to the / formatnow path
* The presneted web page offers Format and Cancel button .
* Cancel will immediatly return to the file upload path ' / update '
* Format will then present a confirmation dialog , user must press Yes to proceed .
*
* Assuming Yes was pressed , a HTTP POST to / format now with the payload ' confirm ' = ' yes ' is performed
* The / formatnow handler will check that confirm does equal yes , and that bFormatAccessed was set
* If all good SPIFFS is re - formatted - no response is set .
* The javascript though from the / formatspiffs page performs a reload shortly after the post ( 200 ms timeout )
*
* As bFormatAccessed is still set , a confimration page is the presented advising files now need to be uploaded
* A button allows direct access to / update
*/
void onFormatSPIFFS ( )
{
DebugPort . println ( " WEB: GET /formatspiffs " ) ;
bUpdateAccessed = false ;
String content = stdHeader ;
2019-07-11 08:55:31 +00:00
if ( ! bFormatPerformed ) {
2019-07-06 13:46:20 +00:00
sCredentials creds = NVstore . getCredentials ( ) ;
if ( ! server . authenticate ( creds . webUpdateUsername , creds . webUpdatePassword ) ) {
return server . requestAuthentication ( ) ;
}
bFormatAccessed = true ; // only set after we pass authentication
content + = formatIndex ;
}
else {
bFormatAccessed = false ;
2019-07-11 08:55:31 +00:00
bFormatPerformed = false ;
2019-07-06 13:46:20 +00:00
content + = formatDoneContent ;
}
server . send ( 200 , " text/html " , content ) ;
}
2019-07-11 08:55:31 +00:00
const char * formatDoneContent = R " =====(
< style >
body {
background - color : yellow ;
}
< / style >
< / head >
< body >
2019-07-06 13:46:20 +00:00
< h1 > SPIFFS partition has been formatted < / h1 >
< h3 > You must now upload the web content . < / h3 >
2019-07-11 08:55:31 +00:00
< p > Latest web content can be downloaded from < a href = ' http : //www.mrjones.id.au/afterburner/firmware.html' target='_blank'>http://www.mrjones.id.au/afterburner/firmware.html</a>
2019-07-06 13:46:20 +00:00
< h4 class = " throb " >Please ensure you unzip the web page content, then upload all the files contained.</h4>
2019-07-17 09:35:34 +00:00
< p > < button onclick = location . assign ( ' / update ' ) > Upload web content < / button >
2019-07-06 13:46:20 +00:00
< / body >
< / html >
) = = = = = " ;
const char * formatIndex = R " =====(
2019-07-11 08:55:31 +00:00
< style >
body {
background - color : orangered ;
}
< / style >
2019-07-06 13:46:20 +00:00
< script >
function init ( ) {
}
function onFormat ( ) {
var formdata = new FormData ( ) ;
if ( confirm ( ' Do you really want to reformat the SPIFFS partition ? ' ) ) {
2019-07-15 09:56:36 +00:00
_ ( ' throb ' ) . innerHTML = ' FORMATTING - Please wait ' ;
2019-07-11 08:55:31 +00:00
formdata . append ( ' confirm ' , ' yes ' ) ;
2019-07-06 13:46:20 +00:00
setTimeout ( function ( ) { location . reload ( ) ; } , 200 ) ;
}
else {
2019-07-11 08:55:31 +00:00
formdata . append ( ' confirm ' , ' no ' ) ;
setTimeout ( function ( ) { location . assign ( ' / update ' ) ; } , 20 ) ;
2019-07-06 13:46:20 +00:00
}
var ajax = new XMLHttpRequest ( ) ;
2019-07-17 09:35:34 +00:00
ajax . open ( ' POST ' , ' / formatnow ' ) ;
2019-07-06 13:46:20 +00:00
ajax . send ( formdata ) ;
}
< / script >
< title > Afterburner SPIFFS format < / title >
2019-07-11 08:55:31 +00:00
< / head >
2019-07-17 09:35:34 +00:00
< body onload = ' javascript : init ( ) ' >
2019-07-06 13:46:20 +00:00
< h1 > Format SPIFFS partition < / h1 >
2019-07-11 08:55:31 +00:00
< h3 class = ' throb ' id = ' throb ' > CAUTION ! This will erase all web content < / h1 >
2019-07-15 09:56:36 +00:00
< p > < button class = ' redbutton ' onClick = ' onFormat ( ) ' > Format < / button > < br >
2019-07-11 08:55:31 +00:00
< p > < a href = ' / update ' > < button > Cancel < / button > < / a >
2019-07-06 13:46:20 +00:00
< / body >
< / html >
) = = = = = " ;
void onFormatNow ( )
{
// HTTP POST handler, do not need to return a web page!
DebugPort . println ( " WEB: POST /formatnow " ) ;
String confirm = server . arg ( " confirm " ) ; // get request argument value by name
if ( confirm = = " yes " & & bFormatAccessed ) { // confirm user agrees, and we did pass thru /formatspiffs first
DebugPort . println ( " Formatting SPIFFS partition " ) ;
SPIFFS . format ( ) ; // re-format the SPIFFS partition
2019-07-11 08:55:31 +00:00
bFormatPerformed = true ;
2019-07-06 13:46:20 +00:00
}
else {
bFormatAccessed = false ; // user cancelled upon last confirm popup, or not authenticated access
2019-07-11 08:55:31 +00:00
bFormatPerformed = false ;
2019-07-06 13:46:20 +00:00
rootRedirect ( ) ;
}
}
2019-07-15 09:56:36 +00:00
void onReboot ( )
{
DebugPort . println ( " WEB: GET /reboot " ) ;
String content = stdHeader ;
content + = rebootIndex ;
server . send ( 200 , " text/html " , content ) ;
}
void onDoReboot ( )
{
// HTTP POST handler, do not need to return a web page!
DebugPort . println ( " WEB: POST /reboot " ) ;
String confirm = server . arg ( " reboot " ) ; // get request argument value by name
if ( confirm = = " yes " ) { // confirm user agrees, and we did pass thru /formatspiffs first
DebugPort . println ( " Rebooting via /reboot " ) ;
ESP . restart ( ) ;
}
}
const char * rebootIndex = R " =====(
< style >
body {
background - color : orangered ;
}
< / style >
< script >
function onReboot ( ) {
if ( confirm ( ' Do you really want to reboot the Afterburner ? ' ) ) {
2019-07-23 11:11:29 +00:00
_ ( ' info ' ) . innerHTML = ' Rebooting NOW ' ;
setTimeout ( function ( ) { _ ( ' info ' ) . innerHTML = ' Rebooted ' ; } , 2000 ) ;
setTimeout ( function ( ) { _ ( ' info ' ) . innerHTML = ' Initialising . . . ' ; } , 4000 ) ;
2019-07-23 12:56:04 +00:00
setTimeout ( function ( ) { _ ( ' info ' ) . innerHTML = ' Loading / index . html . . . ' ; location . assign ( ' / ' ) ; } , 7500 ) ;
2019-07-15 09:56:36 +00:00
var formdata = new FormData ( ) ;
formdata . append ( ' reboot ' , ' yes ' ) ;
var ajax = new XMLHttpRequest ( ) ;
2019-07-17 09:35:34 +00:00
ajax . open ( ' POST ' , ' / reboot ' ) ;
2019-07-15 09:56:36 +00:00
ajax . send ( formdata ) ;
_ ( ' info ' ) . hidden = false ;
}
else {
location . assign ( ' / ' ) ;
}
}
< / script >
< title > Afterburner Reboot < / title >
< / head >
< body >
< h1 > Reboot Afterburner < / h1 >
< p >
< h3 class = ' throb ' id = ' info ' hidden > Rebooting - will re - direct to root index < / h3 >
< button class = ' redbutton ' onClick = ' onReboot ( ) ' > Reboot < / button >
& nbsp ; & nbsp ; & nbsp ; & nbsp ; < a href = ' / ' > < button > Cancel < / button > < / a >
< / body >
< / html >
) = = = = = " ;
void onRename ( )
{
// HTTP POST handler, do not need to return a web page!
DebugPort . println ( " WEB: POST /reboot " ) ;
String oldname = server . arg ( " oldname " ) ; // get request argument value by name
String newname = server . arg ( " newname " ) ; // get request argument value by name
if ( oldname ! = " " & & newname ! = " " ) {
DebugPort . printf ( " Renaming %s to %s \r \n " , oldname . c_str ( ) , newname . c_str ( ) ) ;
SPIFFS . rename ( oldname . c_str ( ) , newname . c_str ( ) ) ;
}
}
2019-07-06 13:46:20 +00:00
/***************************************************************************************
* HTTP RESPONSE 404 - FILE NOT FOUND HANDLING
*/
void build404Response ( String & content , String file )
{
content + = stdHeader ;
2019-07-11 08:55:31 +00:00
content + = R " =====(</head>
< body >
2019-07-06 13:46:20 +00:00
< h1 > 404 : File Not Found < / h1 >
< p > URI : < b > < i > ) = = = = = " ;
content + = file ;
content + = R " =====(</i></b><br>
Method : ) = = = = = " ;
content + = ( server . method ( ) = = HTTP_GET ) ? " GET " : " POST " ;
content + = " <br>Arguments: " ;
for ( uint8_t i = 0 ; i < server . args ( ) ; i + + ) {
content + = " " + server . argName ( i ) + " : " + server . arg ( i ) + " <br> " ;
}
content + = R " =====(<hr>
< p > Please check the URL . < br >
If OK please try uploading the file from the web content .
< p > Latest web content can be downloaded from < a href = " http://www.mrjones.id.au/afterburner/firmware.html " target = " _blank " > http : //www.mrjones.id.au/afterburner/firmware.html</a>
< h4 class = " throb " >Please ensure you unzip the web page content, then upload all the files contained.</h4>
< p > < a href = " /update " > < button > Upload web content < / button > < / a > < br >
) = = = = = " ;
String SPIFFSinfo ;
2019-07-07 07:18:38 +00:00
listSPIFFS ( " / " , 2 , SPIFFSinfo , 1 ) ;
2019-07-06 13:46:20 +00:00
content + = SPIFFSinfo ;
content + = " </body> " ;
content + = " </html> " ;
}
/***************************************************************************************
* HTTP RESPONSE 500 - SERVER ERROR HANDLING
*/
void build500Response ( String & content , String file )
{
content = stdHeader ;
2019-07-11 08:55:31 +00:00
content + = R " =====(</head>
< body >
2019-07-06 13:46:20 +00:00
< h1 > 500 : Internal Server Error < / h1 >
< h3 class = " throb " >Sorry, cannot open file</h3>
< p > < b > < i > " )===== " ;
content + = file ;
content + = R " =====( " < / i > < / b > exists , but cannot be streamed ?
< hr >
< p > Recommended remedy is to re - format the SPIFFS partition , then reload the web content files .
< br > Latest web content can be downloaded from < a href = " http://www.mrjones.id.au/afterburner/firmware.html " target = " _blank " > http : //www.mrjones.id.au/afterburner/firmware.html</a> <i>(opens in new page)</i>.
2019-07-15 09:56:36 +00:00
< p > To format the SPIFFS partition , press < button class = ' redbutton ' onClick = location . assign ( ' / formatspiffs ' ) > Format SPIFFS < / button >
2019-07-06 13:46:20 +00:00
< p > You will then need to upload each file of the web content by using the subsequent " <b>Upload</b> " button .
< hr >
< h4 class = " throb " >Please ensure you unzip the web page content, then upload all the files contained.</h4>
< / body >
< / html >
) = = = = = " ;
}