2018-11-26 12:58:15 +01: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 12:31:34 +02:00
# define USE_EMBEDDED_WEBUPDATECODE
2018-11-07 05:07:11 +01:00
# include "BTCWebServer.h"
2018-12-16 08:34:39 +01:00
# include "../Utility/DebugPort.h"
# include "../Protocol/TxManage.h"
2019-06-16 01:09:29 +02:00
# include "../Utility/helpers.h"
2018-12-16 08:34:39 +01:00
# include "../cfg/pins.h"
2019-05-18 10:49:22 +02:00
# include "../cfg/BTCConfig.h"
2018-11-26 11:26:38 +01:00
# include "Index.h"
2018-12-16 08:34:39 +01:00
# include "../Utility/BTC_JSON.h"
# include "../Utility/Moderator.h"
2019-01-11 09:50:27 +01:00
# include <WiFiManager.h>
2019-05-21 14:01:42 +02:00
# include <FS.H>
2019-01-20 11:14:45 +01:00
# include <SPIFFS.h>
2019-05-16 13:12:29 +02:00
# include "../Utility/NVStorage.h"
2019-01-11 09:50:27 +01:00
extern WiFiManager wm ;
2018-11-07 05:07:11 +01:00
2019-05-21 14:01:42 +02:00
File fsUploadFile ; // a File object to temporarily store the received file
int SPIFFSupload = 0 ;
2018-11-07 05:07:11 +01:00
WebServer server ( 80 ) ;
2018-11-26 11:26:38 +01:00
WebSocketsServer webSocket = WebSocketsServer ( 81 ) ;
2018-12-12 10:03:44 +01:00
bool bRxWebData = false ; // flags for OLED animation
2018-12-01 19:25:10 +01:00
bool bTxWebData = false ;
2019-05-14 13:29:35 +02:00
bool bUpdateAccessed = false ; // flag used to ensure web update always starts via /update. direct accesses to /updatenow will FAIL
2019-05-22 22:35:09 +02:00
long _SuppliedFileSize = 0 ;
2018-11-07 05:07:11 +01:00
2019-06-30 02:37:24 +02:00
void handleBTCNotFound ( ) ;
bool checkFile ( File & file ) ;
2018-11-07 05:07:11 +01:00
2019-01-20 11:14:45 +01: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 14:01:42 +02:00
else if ( filename . endsWith ( " .bin " ) ) return " application/octet-stream " ;
2019-01-20 11:14:45 +01: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
if ( SPIFFS . exists ( path ) ) { // If the file exists
File file = SPIFFS . open ( path , " r " ) ; // Open it
2019-06-30 02:37:24 +02:00
if ( ! checkFile ( file ) ) { // check it is readable
file . close ( ) ; // Then close the file again
}
if ( ! file ) {
DebugPort . println ( " \t File exists, but could not be read? " ) ;
String SPIFFSfmtpath = " http:// " + server . client ( ) . localIP ( ) . toString ( ) + " /formatspiffs " ;
String Updatepath = " http:// " + server . client ( ) . localIP ( ) . toString ( ) + " /update " ;
String message = " <h1>Internal Server Error</h1> " ;
message + = " <h3>Sorry, cannot open file</h3> " ;
message + = " <p><b><i> " + path + " </i></b> exists, but cannot be opened?<br> " ;
message + = " Recommended remedy is to re-format SPIFFS, then reload the web content. " ;
message + = " <p><b>Use:<br><i><a href= \" " + SPIFFSfmtpath + " \" target= \" _blank \" > " + SPIFFSfmtpath + " </a></b></i> to format SPIFFS. " ;
message + = " <p><b>Then:<br><i> " + Updatepath + " </b></i> to upload each file of the web content.<br> " ;
message + = " <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> " ;
message + = " <p><b>Please ensure you unzip the web page content, then upload all the contained files.</b> " ;
server . send ( 500 , " text/html " , message ) ;
}
else {
server . streamFile ( file , contentType ) ; // And send it to the client
file . close ( ) ; // Then close the file again
}
2019-01-20 11:14:45 +01:00
return true ;
}
DebugPort . println ( " \t File Not Found " ) ;
return false ; // If the file doesn't exist, return false
}
2019-06-30 02:37:24 +02:00
void handleWMConfig ( )
{
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: GET /wmconfig " ) ;
2019-01-16 10:22:17 +01:00
server . send ( 200 , " text/plain " , " Start Config Portal - Retaining credential " ) ;
2019-01-11 09:28:22 +01:00
DebugPort . println ( " Starting web portal for wifi config " ) ;
2019-01-16 10:22:17 +01:00
delay ( 500 ) ;
wifiEnterConfigPortal ( true , false , 3000 ) ;
2019-01-11 09:28:22 +01:00
}
2019-01-13 20:59:32 +01:00
2019-06-30 02:37:24 +02:00
void handleReset ( )
{
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: GET /resetwifi " ) ;
2019-01-16 10:22:17 +01:00
server . send ( 200 , " text/plain " , " Start Config Portal - Resetting Wifi credentials! " ) ;
2019-01-12 22:32:13 +01:00
DebugPort . println ( " diconnecting client and wifi, then rebooting " ) ;
2019-01-16 10:22:17 +01:00
delay ( 500 ) ;
wifiEnterConfigPortal ( true , true , 3000 ) ;
2019-01-11 09:28:22 +01:00
}
2019-06-30 02:37:24 +02:00
void handleFormat ( )
{
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: GET /formatspiffs " ) ;
2019-06-30 02:37:24 +02:00
String Updatepath = " http:// " + server . client ( ) . localIP ( ) . toString ( ) + " /update " ;
String message = " <h1>SPIFFS partition formatted</h1> " ;
message + = " <h3>You must now upload the web content.</h3> " ;
message + = " <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> " ;
message + = " <p><b>Use:<br><i><a href= \" " + Updatepath + " \" > " + Updatepath + " </a></b></i> to then upload each file of the web content.<br> " ;
message + = " <p><b>Please ensure you unzip the web page content, then upload all the contained files.</b> " ;
server . send ( 200 , " text/html " , message ) ;
2019-02-11 09:34:11 +01:00
DebugPort . println ( " Formatting SPIFFS partition " ) ;
delay ( 500 ) ;
SPIFFS . format ( ) ;
}
2019-06-30 02:37:24 +02:00
void handleSpiffs ( )
{
String report ;
String message ;
listDir ( SPIFFS , " / " , 2 , report , true ) ;
char usage [ 128 ] ;
2019-06-30 14:39:40 +02:00
sprintf ( usage , " <p>Usage: %d/%d <p> " , SPIFFS . usedBytes ( ) , SPIFFS . totalBytes ( ) ) ;
message + = " <h1>Current SPIFFS contents:</h1> " ;
2019-06-30 02:37:24 +02:00
message + = report ;
2019-06-30 14:39:40 +02:00
message + = usage ;
2019-06-30 02:37:24 +02:00
message + = " <p><a href= \" /update \" >Add more files</a><br> " ;
message + = " <p><a href= \" /index.html \" >Home</a> " ;
server . send ( 200 , " text/html " , message ) ;
}
void handleBTCNotFound ( )
{
String path = server . uri ( ) ;
if ( path . endsWith ( " / " ) ) path + = " index.html " ; // If a folder is requested, send the index file
String Updatepath = " http:// " + server . client ( ) . localIP ( ) . toString ( ) + " /update " ;
String message = " <h1>404: File Not Found</h1> " ;
message + = " <p>URI: <b><i> " + path + " </i></b> " ;
message + = " <br>Method: " ;
2018-11-07 05:07:11 +01:00
message + = ( server . method ( ) = = HTTP_GET ) ? " GET " : " POST " ;
2019-06-30 02:37:24 +02:00
message + = " <br>Arguments: " ;
2018-11-07 05:07:11 +01:00
for ( uint8_t i = 0 ; i < server . args ( ) ; i + + ) {
2019-06-30 02:37:24 +02:00
message + = " " + server . argName ( i ) + " : " + server . arg ( i ) + " <br> " ;
2018-11-07 05:07:11 +01:00
}
2019-06-30 02:37:24 +02:00
message + = " <hr> " ;
message + = " <p>Please try uploading the file from the web content. " ;
message + = " <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> " ;
message + = " <p><b>Use:<br><i><a href= \" /update \" > " + Updatepath + " </a></b></i> to upload the web content.<br> " ;
message + = " <p><b>Please ensure you unzip the web page content, then upload all the contained files.</b> " ;
2019-06-30 14:39:40 +02:00
char usage [ 128 ] ;
sprintf ( usage , " <p>Usage: %d/%d<p> " , SPIFFS . usedBytes ( ) , SPIFFS . totalBytes ( ) ) ;
2019-06-30 02:37:24 +02:00
String report ;
listDir ( SPIFFS , " / " , 2 , report ) ;
message + = " <hr><h3>Current SPIFFS contents:</h3> " ;
message + = report ;
2019-06-30 14:39:40 +02:00
message + = usage ;
2019-06-30 02:37:24 +02:00
server . send ( 404 , " text/html " , message ) ;
2018-11-07 05:07:11 +01:00
}
2019-06-02 11:19:08 +02:00
// embedded HTML & Javascript to perform browser based updates of firmware or SPIFFS
2019-05-22 13:08:38 +02:00
const char * updateIndex = R " =====(
2019-05-21 14:01:42 +02:00
< ! DOCTYPE html >
< html lang = " en " >
< head >
< meta charset = " utf-8 " / >
2019-05-22 13:08:38 +02:00
< meta http - equiv = " Pragma " content = " no-cache " >
< meta http - equiv = " Expires " content = " -1 " >
< meta http - equiv = " CACHE-CONTROL " content = " NO-CACHE " >
2019-05-21 14:01:42 +02:00
< script >
// global variables
var sendSize ;
2019-05-22 22:35:09 +02:00
var ws ;
2019-05-21 14:01:42 +02:00
function _ ( el ) {
return document . getElementById ( el ) ;
}
function init ( ) {
2019-05-22 22:35:09 +02:00
ws = new WebSocket ( ' ws : //' + window.location.hostname + ':81/');
2019-05-30 12:31:34 +02:00
2019-05-22 22:35:09 +02:00
ws . onmessage = function ( event ) {
2019-05-21 14:01:42 +02:00
var response = JSON . parse ( event . data ) ;
var key ;
for ( key in response ) {
switch ( key ) {
case " progress " :
// actual data bytes received as fed back via web socket
var bytes = response [ key ] ;
_ ( " loaded_n_total " ) . innerHTML = " Uploaded " + bytes + " bytes of " + sendSize ;
var percent = Math . round ( 100 * ( bytes / sendSize ) ) ;
_ ( " progressBar " ) . value = percent ;
_ ( " status " ) . innerHTML = percent + " % uploaded.. please wait " ;
break ;
}
}
}
}
function uploadFile ( ) {
_ ( " cancel " ) . hidden = true ;
var file = _ ( " file1 " ) . files [ 0 ] ;
sendSize = file . size ;
2019-05-22 22:35:09 +02:00
var JSONmsg = { } ;
JSONmsg [ ' UploadSize ' ] = sendSize ;
2019-05-30 12:31:34 +02:00
var str = JSON . stringify ( JSONmsg ) ;
2019-05-22 22:35:09 +02:00
console . log ( " JSON Tx: " , str ) ;
ws . send ( str ) ;
2019-05-21 14:01:42 +02:00
var formdata = new FormData ( ) ;
formdata . append ( " update " , file ) ;
var ajax = new XMLHttpRequest ( ) ;
// progress is handled via websocket JSON sent from controller
// using server side progress only shows the buffer filling, not actual delivery.
ajax . addEventListener ( " load " , completeHandler , false ) ;
ajax . addEventListener ( " error " , errorHandler , false ) ;
ajax . addEventListener ( " abort " , abortHandler , false ) ;
ajax . open ( " POST " , " /updatenow " ) ;
ajax . send ( formdata ) ;
}
function completeHandler ( event ) {
_ ( " status " ) . innerHTML = event . target . responseText ;
_ ( " progressBar " ) . value = 0 ;
_ ( " loaded_n_total " ) . innerHTML = " Uploaded " + sendSize + " bytes of " + sendSize ;
2019-05-22 13:08:38 +02:00
var file = _ ( " file1 " ) . files [ 0 ] ;
if ( file . name . endsWith ( " .bin " ) ) {
setTimeout ( function ( ) {
window . location . assign ( " / " ) ;
2019-05-21 14:01:42 +02:00
} , 5000 ) ;
2019-05-22 13:08:38 +02:00
}
else {
setTimeout ( function ( ) {
window . location . reload ( ) ;
} , 1000 ) ;
}
2019-05-21 14:01:42 +02:00
}
function errorHandler ( event ) {
_ ( " status " ) . innerHTML = " Upload Failed " ;
}
function abortHandler ( event ) {
_ ( " status " ) . innerHTML = " Upload Aborted " ;
}
< / script >
< style >
body { font - family : Arial , Helvetica , sans - serif ; }
< / style >
< title > Afterburner firmware update < / title >
< / head >
< body onload = " javascript:init() " >
< h1 > Afterburner firmware update < / h1 >
2019-05-22 13:08:38 +02:00
< form id = " upload_form " method = " POST " enctype = " multipart/form-data " autocomplete = " off " >
< input type = " file " name = " file1 " id = " file1 " > < BR >
< input type = " button " value = " Update " onclick = " uploadFile() " >
2019-05-21 14:01:42 +02:00
< progress id = " progressBar " value = " 0 " max = " 100 " style = " width:300px; " > < / progress > < BR >
< h3 id = " status " > < / h3 >
< p id = " loaded_n_total " > < / p >
< BR >
2019-05-22 13:08:38 +02:00
< input type = " button " onclick = window . location . assign ( " / " ) value = " Cancel " id = " cancel " >
2019-05-21 14:01:42 +02:00
< / form >
< / body >
< / html >
2019-05-15 12:24:43 +02:00
) = = = = = " ;
2019-05-12 12:15:18 +02:00
2019-05-16 13:12:29 +02:00
void rootRedirect ( )
{
2019-05-22 13:08:38 +02:00
server . sendHeader ( " Location " , " / " ) ; // reselect the update page
server . send ( 303 ) ;
2019-05-16 13:12:29 +02:00
}
2018-11-07 05:07:11 +01:00
void initWebServer ( void ) {
2018-12-09 20:28:02 +01:00
2019-05-14 13:29:35 +02:00
Update
. onProgress ( [ ] ( unsigned int progress , unsigned int total ) {
int percent = ( progress / ( total / 100 ) ) ;
DebugPort . printf ( " Progress: %u%% \r " , percent ) ;
DebugPort . handle ( ) ; // keep telnet spy alive
2019-06-02 22:34:45 +02:00
ShowOTAScreen ( percent , eOTAWWW ) ; // WWW update in place
2019-05-20 14:09:59 +02:00
DebugPort . print ( " ^ " ) ;
2019-05-14 13:29:35 +02:00
} ) ;
2019-01-13 20:59:32 +01:00
2019-05-15 12:24:43 +02:00
if ( MDNS . begin ( " Afterburner " ) ) {
2018-11-07 05:07:11 +01:00
DebugPort . println ( " MDNS responder started " ) ;
}
2018-11-26 11:26:38 +01:00
2019-01-20 20:56:42 +01:00
server . on ( " /wmconfig " , handleWMConfig ) ;
2019-02-11 09:34:11 +01:00
server . on ( " /resetwifi " , handleReset ) ;
server . on ( " /formatspiffs " , handleFormat ) ;
2019-06-30 02:37:24 +02:00
server . on ( " /spiffs " , handleSpiffs ) ;
2019-05-12 12:15:18 +02:00
2019-05-14 13:29:35 +02:00
server . on ( " /tst " , HTTP_GET , [ ] ( ) {
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: GET /tst " ) ;
2019-05-21 14:01:42 +02:00
server . sendHeader ( " Location " , " / " ) ; // reselect the update page
server . send ( 303 ) ;
2019-05-14 13:29:35 +02:00
} ) ;
2019-05-20 14:09:59 +02:00
// Magical code originally shamelessly lifted from Arduino WebUpdate example, then 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
2019-05-12 12:15:18 +02:00
//
// Initial launch page
server . on ( " /update " , HTTP_GET , [ ] ( ) {
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: GET /update " ) ;
2019-05-16 13:12:29 +02:00
sCredentials creds = NVstore . getCredentials ( ) ;
if ( ! server . authenticate ( creds . webUpdateUsername , creds . webUpdatePassword ) ) {
2019-05-14 13:29:35 +02:00
return server . requestAuthentication ( ) ;
}
bUpdateAccessed = true ;
2019-05-22 13:08:38 +02:00
# ifdef USE_EMBEDDED_WEBUPDATECODE
server . send ( 200 , " text/html " , updateIndex ) ;
# else
handleFileRead ( " /uploadfirmware.html " ) ;
# endif
2019-05-12 12:15:18 +02:00
} ) ;
2019-05-22 13:08:38 +02:00
// handle attempts to just browse the /updatenow path - force redirect to root
server . on ( " /updatenow " , HTTP_GET , [ ] ( ) {
DebugPort . println ( " WEB: GET /updatenow - ILLEGAL - root redirect " ) ;
2019-05-16 13:12:29 +02:00
rootRedirect ( ) ;
2019-05-14 13:29:35 +02:00
} ) ;
2019-05-22 13:08:38 +02:00
2019-05-12 12:15:18 +02:00
// actual guts that manages the new firmware upload
server . on ( " /updatenow " , HTTP_POST , [ ] ( ) {
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: POST /updatenow completion " ) ;
2019-05-15 12:24:43 +02:00
// completion functionality
2019-05-21 14:01:42 +02:00
if ( SPIFFSupload ) {
if ( SPIFFSupload = = 1 ) {
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: SPIFFS OK " ) ;
2019-06-02 22:34:45 +02:00
server . send ( 200 , " text/plain " , " OK - File uploaded to SPIFFS " ) ;
2019-05-22 13:08:38 +02:00
// javascript reselects the /update page!
2019-05-21 14:01:42 +02:00
}
else {
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: SPIFFS FAIL " ) ;
2019-05-21 14:01:42 +02:00
server . send ( 500 , " text/plain " , " 500: couldn't create file " ) ;
}
SPIFFSupload = 0 ;
}
else {
2019-05-22 13:08:38 +02:00
if ( Update . hasError ( ) ) {
2019-06-29 10:08:37 +02:00
DebugPort . println ( " WEB: UPDATE FAIL " ) ;
2019-05-21 14:01:42 +02:00
server . send ( 200 , " text/plain " , " FAIL - Afterburner will reboot shortly " ) ;
2019-05-22 13:08:38 +02:00
}
else {
2019-06-29 10:08:37 +02:00
DebugPort . println ( " WEB: UPDATE OK " ) ;
2019-05-22 13:08:38 +02:00
server . send ( 200 , " text/plain " , " OK - Afterburner will reboot shortly " ) ;
}
2019-05-21 14:01:42 +02:00
delay ( 1000 ) ;
2019-05-22 13:08:38 +02:00
// javascript redirects to root page so we go there after reboot!
2019-06-29 10:08:37 +02:00
forceBootInit ( ) ;
2019-05-21 14:01:42 +02:00
ESP . restart ( ) ; // reboot
}
2019-05-12 12:15:18 +02:00
} , [ ] ( ) {
2019-05-16 13:12:29 +02:00
if ( bUpdateAccessed ) { // only allow progression via /update, attempts to directly access /updatenow will fail
2019-05-14 13:29:35 +02:00
HTTPUpload & upload = server . upload ( ) ;
if ( upload . status = = UPLOAD_FILE_START ) {
2019-05-21 14:01:42 +02:00
String filename = upload . filename ;
2019-05-14 13:29:35 +02:00
DebugPort . setDebugOutput ( true ) ;
2019-05-21 14:01:42 +02:00
if ( filename . endsWith ( " .bin " ) ) {
2019-05-22 22:35:09 +02:00
DebugPort . printf ( " Update: %s %d \r \n " , filename . c_str ( ) , upload . totalSize ) ;
2019-05-21 14:01:42 +02:00
if ( ! Update . begin ( ) ) { //start with max available size
Update . printError ( DebugPort ) ;
}
}
else {
if ( ! filename . startsWith ( " / " ) ) filename = " / " + filename ;
DebugPort . printf ( " handleFileUpload Name: %s \r \n " , filename . c_str ( ) ) ;
fsUploadFile = SPIFFS . open ( filename , " w " ) ; // Open the file for writing in SPIFFS (create if it doesn't exist)
SPIFFSupload = fsUploadFile ? 1 : 2 ;
//filename = String();
2019-05-14 13:29:35 +02:00
}
2019-06-02 22:34:45 +02:00
}
// handle file segments
else if ( upload . status = = UPLOAD_FILE_WRITE ) {
2019-05-18 10:49:22 +02:00
# if USE_SW_WATCHDOG == 1
2019-05-20 14:09:59 +02:00
feedWatchdog ( ) ; // we get stuck here for a while, don't let the watchdog bite!
2019-05-18 10:49:22 +02:00
# endif
if ( upload . totalSize ) {
char JSON [ 64 ] ;
sprintf ( JSON , " { \" progress \" :%d} " , upload . totalSize ) ;
2019-06-02 22:34:45 +02:00
sendWebServerString ( JSON ) ; // feedback proper byte count of update to browser via websocket
2019-05-18 10:49:22 +02:00
}
2019-05-22 22:35:09 +02:00
int percent = 0 ;
if ( _SuppliedFileSize )
percent = 100 * upload . totalSize / _SuppliedFileSize ;
2019-06-02 22:34:45 +02:00
ShowOTAScreen ( percent , eOTAbrowser ) ; // browser update
2019-05-22 22:35:09 +02:00
2019-05-15 12:24:43 +02:00
DebugPort . print ( " . " ) ;
2019-05-21 14:01:42 +02:00
if ( fsUploadFile ) {
fsUploadFile . write ( upload . buf , upload . currentSize ) ; // Write the received bytes to the file
}
else {
if ( Update . write ( upload . buf , upload . currentSize ) ! = upload . currentSize ) {
Update . printError ( DebugPort ) ;
}
2019-05-14 13:29:35 +02:00
}
2019-06-02 22:34:45 +02:00
}
// handle end of upload
else if ( upload . status = = UPLOAD_FILE_END ) {
2019-05-21 14:01:42 +02:00
if ( SPIFFSupload ) {
if ( fsUploadFile ) {
fsUploadFile . close ( ) ; // Close the file again
DebugPort . printf ( " handleFileUpload Size: %d \r \n " , upload . totalSize ) ;
}
}
else {
if ( Update . end ( true ) ) { //true to set the size to the current progress
DebugPort . printf ( " Update Success: %u \r \n Rebooting... \r \n " , upload . totalSize ) ;
} else {
Update . printError ( DebugPort ) ;
}
2019-05-14 13:29:35 +02:00
}
DebugPort . setDebugOutput ( false ) ;
bUpdateAccessed = false ;
2019-05-12 12:15:18 +02:00
} else {
2019-05-15 12:24:43 +02:00
DebugPort . printf ( " Update Failed Unexpectedly (likely broken connection): status=%d \r \n " , upload . status ) ;
2019-05-14 13:29:35 +02:00
bUpdateAccessed = false ;
2019-05-12 12:15:18 +02:00
}
2019-05-14 13:29:35 +02:00
}
else {
2019-05-20 14:09:59 +02:00
// attempt to POST without using /update - forced redirect to root
2019-05-22 13:08:38 +02:00
DebugPort . println ( " WEB: POST /updatenow forbidden entry " ) ;
2019-05-16 13:12:29 +02:00
rootRedirect ( ) ;
2019-05-12 12:15:18 +02:00
}
} ) ;
2019-01-23 20:03:29 +01:00
// NOTE: this serves the default home page, and favicon.ico
2019-01-20 11:14:45 +01:00
server . onNotFound ( [ ] ( )
2019-05-22 13:08:38 +02:00
{ // If the client requests any URI
if ( ! handleFileRead ( server . uri ( ) ) ) { // send it if it exists
2019-06-30 02:37:24 +02:00
handleBTCNotFound ( ) ;
2019-01-20 11:14:45 +01:00
}
2019-05-22 13:08:38 +02:00
} ) ;
2018-11-07 05:07:11 +01:00
server . begin ( ) ;
2019-06-30 02:37:24 +02:00
2018-11-26 11:26:38 +01:00
webSocket . begin ( ) ;
webSocket . onEvent ( webSocketEvent ) ;
2019-06-02 22:34:45 +02:00
2018-11-07 05:07:11 +01:00
DebugPort . println ( " HTTP server started " ) ;
2018-12-09 20:28:02 +01:00
2018-11-07 05:07:11 +01:00
}
2019-01-12 22:32:13 +01:00
2018-11-07 05:07:11 +01:00
2019-06-02 22:34:45 +02:00
// called by main sketch loop()
bool doWebServer ( void )
{
2018-11-26 11:26:38 +01:00
webSocket . loop ( ) ;
2018-11-07 05:07:11 +01:00
server . handleClient ( ) ;
2019-06-26 22:04:24 +02:00
return true ;
2018-12-19 13:07:51 +01:00
}
bool isWebServerClientChange ( )
{
static int prevNumClients = - 1 ;
2018-12-11 12:25:32 +01:00
2018-12-01 19:25:10 +01:00
int numClients = webSocket . connectedClients ( ) ;
2018-12-11 12:25:32 +01:00
if ( numClients ! = prevNumClients ) {
prevNumClients = numClients ;
2018-12-19 13:07:51 +01:00
DebugPort . println ( " Changed number of web clients, should reset JSON moderator " ) ;
return true ;
2018-12-11 12:25:32 +01:00
}
2018-12-19 13:07:51 +01:00
return false ;
}
2018-12-11 12:25:32 +01:00
2018-12-19 13:07:51 +01:00
bool sendWebServerString ( const char * Str )
{
2019-06-02 22:34:45 +02:00
CProfile profile ;
2018-12-19 13:07:51 +01:00
if ( webSocket . connectedClients ( ) ) {
2019-06-02 22:34:45 +02:00
unsigned long tCon = profile . elapsed ( true ) ;
2018-12-19 13:07:51 +01:00
bTxWebData = true ; // OLED tx data animation flag
webSocket . broadcastTXT ( Str ) ;
2019-06-02 22:34:45 +02:00
unsigned long tWeb = profile . elapsed ( true ) ;
DebugPort . printf ( " Websend times : %ld,%ld \r \n " , tCon , tWeb ) ;
2018-12-01 19:25:10 +01:00
return true ;
}
return false ;
2018-11-07 05:07:11 +01:00
}
2018-12-19 13:07:51 +01:00
2019-06-02 22:34:45 +02:00
void webSocketEvent ( uint8_t num , WStype_t type , uint8_t * payload , size_t length )
{
2018-11-26 11:26:38 +01:00
if ( type = = WStype_TEXT ) {
2018-12-11 11:19:02 +01:00
bRxWebData = true ;
char cmd [ 256 ] ;
memset ( cmd , 0 , 256 ) ;
for ( int i = 0 ; i < length & & i < 256 ; i + + ) {
2018-11-26 11:26:38 +01:00
cmd [ i ] = payload [ i ] ;
}
2018-12-11 11:19:02 +01:00
interpretJsonCommand ( cmd ) ; // send to the main heater controller decode routine
2018-12-01 19:25:10 +01: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 11:26:38 +01:00
}
2018-12-11 11:19:02 +01:00
2019-05-22 22:35:09 +02:00
void setUploadSize ( long val )
{
_SuppliedFileSize = val ;
} ;
2019-06-30 02:37:24 +02: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 ;
}
void listDir ( fs : : FS & fs , const char * dirname , uint8_t levels , String & HTMLreport , bool withHTMLanchors )
{
char msg [ 128 ] ;
File root = fs . open ( dirname ) ;
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 ;
}
File file = root . openNextFile ( ) ;
while ( file ) {
if ( file . isDirectory ( ) ) {
sprintf ( msg , " DIR : %s " , file . name ( ) ) ;
DebugPort . println ( msg ) ;
HTMLreport + = msg ; HTMLreport + = " <br> " ;
if ( levels ) {
listDir ( fs , file . name ( ) , levels - 1 , HTMLreport ) ;
}
} else {
String fn = file . name ( ) ;
if ( withHTMLanchors ) {
if ( fn . endsWith ( " .html " ) | | fn . endsWith ( " .htm " ) ) {
String fn2 ( fn ) ;
fn = " <a href= \" " + fn2 + " \" > " + fn2 + " </a> " ;
}
}
sprintf ( msg , " FILE: %s SIZE: %d " , fn . c_str ( ) , file . size ( ) ) ;
DebugPort . println ( msg ) ;
HTMLreport + = msg ; HTMLreport + = " <br> " ;
}
file = root . openNextFile ( ) ;
}
}