now the code-pieces, how i managed to serve .html (or .html.gz)-files from spiffs.
it was meant for testing, i am no real coder, but in my testcode it works stable and satisfactory good for me.
1. i assume SPIFFS was flashed to the ESP.
2. in the server-handle i snapped into the .onnotfound a search-routine for files on spiffs.
if found, serve them.
2.1 i have a file-page, to upload and delete files on spiffs. working
2.1 i have a test-page, which is served from spiffs. only buttons to click, and trigger functions on the esp.
3.0 the .html-files load microajax.js from spiffs and use this to grab the sensor-values from the esp.
3.1 the .hml-files load the bootstrap.css from spiffs (or cdn-internet). it makes easier to style the html-elements. and looks good.
(so i can easy edit only html-pages in webeditor, try, change, upload to esp. easy. ready. go
4. i installed a server-handle only to receive ajax-request (send to esp).
ajax makes the hmtl-page stay unchanged in browser window.
this handle/function takes post-values from forms or from GET-urls
and than set/fires what i want to do the esp, when somethin is clicked/changed on the webpage.
5. from here, one could think of a lot of other thinks.
This was the skeleteon.
i assembled a button-page for testing, which sends onclick the id-name pair to the ESP.
on the ESP i set some animation-modes from this values.
Thats it.
now the code pieces:
SERVER handles:
Code: Select all
httpServer.on("/files", handleFileList2 ); //Filelist-page. generated. (put?)
httpServer.onFileUpload( handleFileUpload ); //call upload function, // called several times from Parsing.cpp while upload
httpServer.on("/upload", HTTP_POST, handleFileList2 ); //after upload done, come here, to stay on the files-page. is there a possible alternative?
httpServer.on("/spiffs/delete_file", spiffsDeleteFile ); //delete selected file
httpServer.on( "/postdata", handlePostData ); //receive ajax-request, call functions on post-values
Functions:
Code: Select all
longer code. it was put in the attachment, vanished ....
i put here. i look, if i can put in on github...
***************
String uploadPath="";
/*********************************************************************************************/
void handleFileList2()
{
//if we have arguments in Query-string, send from the client-brower, we process them (delete file):
if ( httpServer.args() > 0 ) // get data from this page through POST/GET Fields
{
Serial.println("Deleting one SPIFFS File selected");
for ( uint8_t i = 0; i < httpServer.args(); i++ )
{ // Iterate through the fields
Serial.println("Deleting one SPIFFS File:");
if (httpServer.argName(i) == "file" ) //rename id to deletefile, also in javascript
{
String fileName = httpServer.arg(i);
Serial.printf("Deleting File: %s\n", fileName.c_str() );
SPIFFS.remove(fileName);
}//end-if
}//end-for
}//end-if
//(than, or otherwise) we sample and send a html-page to the client-browser
//String FileList = "File List:\n";
//String FileList = "";
//String FileName;
/*
webString = F("<!DOCTYPE HTML>");
webString = F("<html><head>");
webString = F("<link rel='stylesheet' href='style.css.gz' type='text/css' />");
webString = F("<meta name='author' content='tozett'>");
webString = F("</head><body>SPI-FlashFileSystem = SPIFFS.<br>");
*/
webString = F("<!DOCTYPE HTML>\r\n"); // html5 doct-type According to the HTML5 standard; the <html>, the <body>, and the <head> tag can be omitted, but on older browser (esp/or them) crashes.. */
webString += F("<html>") ;
webString += F("<head>") ;
webString += F("<title>FileList2</title>") ;
webString += F("<meta charset='utf-8' />") ;
webString += F("<link rel='stylesheet' href='style.css.gz' type='text/css' />") ;
webString += F("</head>") ;
webString += F("<body>") ;
//webString += F("<form action='/spiffs/delete_file' method='post'> <!--the achtion-? is html5confirm-->");
webString += F("<form action='?' method='post'> <!--the achtion-? is html5confirm-->");
webString += F("<table class='table table-condensed' border='0' cellspacing='0' cellpadding='3' style='widt_:410px' >");
//webString += F("<tr><td align='right'>MatrixMode 0-30:</td><td><input type='number' id='deletefile' name='deletefile' value=''><input style='margin-left: 10px;' type='submit' style='width:150px' value='Delete this'></td></tr> ");
webString += F("<tr><td align='right'>File:</td><td><input type='text' id='file' name='file' value=''>");
//webString += F("<a href='javascript:selFile()' style='border-style: solid; border-width: 2px; border-color: red; width: 150px' class='btn btn--m btn--blue'>Delete File</a>");
//webString += F("<a href='javascript:selFile()' style='border-style: solid; border-width: 2px; border-color: red; width: 150px'>Delete File</a>");
webString += F("<input style='margin-left: 10px;' type='submit' style='width:150px' value='Delete File'></td></tr>");
webString += F("</table></form>");
webString += F("<script>function selFile(value){document.getElementById('file').value = value;}</script>");
webString += F("<table border='0' cellspacing='0' cellpadding='3' class='table table-condensed' >");
webString += F("<tr bgcolor='#DDDDDD' ><td><strong>dir/Name</strong></td><td><strong>Size</strong></td><td><strong>kB</strong></td><tr>");
Dir dir = SPIFFS.openDir("/");
Serial.println("File List:");
while( dir.next() )
{
String FileName = dir.fileName();
//FileName = dir.fileName();
File f = dir.openFile("r");
String FileSize = String(f.size());
int whsp = 6-FileSize.length();
while(whsp-->0)
{
Serial.print(" ");
//FileName += " ";
}//end-while
//Serial.println(FileSize + " " + FileName);
Serial.println(FileName + ", " + FileSize + " kB");
//FileList += FileSize+" kB "+FileName+"\n";
//webString += FileName + " [" + FileSize + " kB] " + "\n";
webString += "<tr><td><a href='javascript:selFile(\"" + String(FileName) + "\")'>" + String(FileName) + "</a></td><td>" + " [" + FileSize + " kB] " + "</td></tr>";
//webString += "<tr><td><a href='javascript:selFile(\'" + String(FileName) + "\')'>" + String(FileName) + "</a></td><td>" + " [" + FileSize + " kB] " + "</td></tr>";
//Networks += "<tr><td><a href='javascript:selFile(\"" + String(WiFi.SSID(i)) + "\")'>" + String(WiFi.SSID(i)) + "</a></td><td>" + String(quality) + "%</td><td>" + String((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*") + "</td></tr>";
Serial.println( FileName );
}//end-while-dir-next
//webString += FileName;
webString += F("</table><hr>");
webString += F("<form method='POST' action='/upload' enctype='multipart/form-data'> ");
webString += F("<input type='text' id='uploadpath' name='uploadpath' value=''><br> ");
webString += F("<input style='border-style: solid; border-width: 2px; border-color: red;' type='file' name='File upload'> ");
webString += F("<input style='margin-left: 10px;' type='submit' value='UpLoad File to SPIFFS'></form><hr>");
//path
webString += F("<form action='?' method='post'> <!--the achtion-? is html5confirm-->");
webString += F("<table class='table table-condensed' border='0' cellspacing='0' cellpadding='3' style='widt_:410px' >");
webString += F("<tr><td align='right'>Path to store to:</td><td><input type='text' id='uploadpath2' name='uploadpath2' value=''>");
webString += F("<input style='margin-left: 10px;' type='submit' style='width:150px' value='Set Filepath'></td></tr>");
webString += F("</body></html>");
//Serial.print( "send: " );
//Serial.println( webString );
//debug spiffs files on serial:
spiffsListFiles();
//if ( httpServer.arg("switch") == "'..switch1_pin..'" )
if ( httpServer.arg("uploadpath2") != "" )
{
uploadPath = httpServer.arg("uploadpath2"); //store in global var
}
else
{
uploadPath =""; //clear upload path
}
Serial.print( "arg:uploadpath2: " );
Serial.println( httpServer.arg("uploadpath2") );
String reply = "";
if (httpServer.args() > 0 ) /* is this page called with parameters? = Are there any POST/GET Fields ? */
{
for ( uint8_t i = 0; i < httpServer.args(); i++ ) { // Iterate through the fields
//reply += httpServer.arg(i) ;
//reply += " NAME:" + httpServer.argName(i) + "\n VALUE:" + httpServer.arg(i) + "\n";
reply = "debug.argname= " + httpServer.argName(i) + " ist " + httpServer.arg(i) ;
Serial.println( reply );
} /* end-for */
} /* end-if*/
//Serial.println( reply );
//httpServer.sendHeader("Connection", "close");
//httpServer.sendHeader("Access-Control-Allow-Origin", "*");
//httpServer.send(200, "text/plain", webString);
httpServer.send(200, "text/html", webString);
}//end-fuction
File fsUploadFile; //must be global defined. otherwise filesize may zero. (maybe because httpuload-routine is called more than once from core-lib before upload is complete?)
/*********************************************************************************************/
void handleFileUpload()
{
//File fsUploadFile; //must be global defined. otherwise filesize may zero. (maybe because httpuload-routine is called more than once from core-lib before upload is complete?)
if(httpServer.uri() != "/upload") return; //url-path must be /upload, otherwise exit.
HTTPUpload& upload = httpServer.upload();
String filename = upload.filename;
//Serial.println( "handlefileUpload.show.uploadPath: " );
//Serial.println( uploadPath );
// no args on fileupload!!! -> One thing I figured out real quick is that the Webserver back-end code doesn't parse the Post parameters from a form when there's a file upload. (int server.args == 0) - See more at: http://www.esp8266.com/viewtopic.php?p=53882#sthash.qsKWNcHv.dpuf
// -> But it will parse URL parameters.
String reply = "";
if (httpServer.args() > 0 ) //tis this page called with parameters? = Are there any POST/GET Fields ?
{
for ( uint8_t i = 0; i < httpServer.args(); i++ ) { // Iterate through the fields
//reply += httpServer.arg(i) ;
//reply += " NAME:" + httpServer.argName(i) + "\n VALUE:" + httpServer.arg(i) + "\n";
reply = "debug.handleupld.argname= " + httpServer.argName(i) + " ist " + httpServer.arg(i) ;
Serial.println( reply );
} //* end-for
} //* end-if
if ( httpServer.arg("dir") != "" ) {uploadPath = httpServer.arg("dir"); }
if ( !filename.startsWith("/")) {filename = "/" + filename;} //root-dir-level, but there are no level on SPIFFS, https://github.com/esp8266/Arduino/issues/901
Serial.print("start...handleFileUpload check uploadpath: ");
Serial.println(uploadPath);
if ( uploadPath != " " ) {filename = uploadPath + filename; }
Serial.print("start...handleFileUpload - Name: ");
Serial.println(filename);
if ( upload.status == UPLOAD_FILE_START )
{
//String filename = upload.filename; //this is done one level above
/*
if ( !filename.startsWith("/")) {filename = "/" + filename;} //root-dir-level, but there are no level on SPIFFS, https://github.com/esp8266/Arduino/issues/901
if ( uploadPath != "" ) {filename = uploadPath + filename; }
Serial.print("start...handleFileUpload - Name: ");
Serial.println(filename);
*/
fsUploadFile = SPIFFS.open(filename, "w"); //create file (must be global defined?), make handle for receive data
filename = String(); //whats this? here also wrong? https://github.com/luc-github/ESP3D/blob/127213fcb4d105aae07a3cf7dee8f79f78b8344b/esp3d/webinterface.cpp#L2332
//create file succes?
if( fsUploadFile )
{
Serial.println("start...success. file created.");
}
else
{
Serial.println("start...error. file not created.");
}
}//end-if-upload-start
else if ( upload.status == UPLOAD_FILE_WRITE )
{
// no serial debug here?
//Serial.print("uploading...handleFileUpload - Data: ");
//Serial.println(upload.currentSize);
//fsUploadFile.write(upload.buf, upload.currentSize); //uploading in progress, show stats...
if( fsUploadFile )
{
fsUploadFile.write(upload.buf, upload.currentSize); //uploading in progress, show stats...
Serial.println("upload ongoing...");
Serial.print("handleFileUpload - Size: ");
Serial.println(upload.totalSize);
}
else
{
Serial.println("upload writing error. fsuploadFile is false...");
}
}//end-else-if-upload-write
else if( upload.status == UPLOAD_FILE_END )
{
if( fsUploadFile )
{
fsUploadFile.close();
Serial.print("END. handleFileUpload - Closed: ");
delay(0); //give some time?
spiffsListFiles();
}
//Serial.print("handleFileUpload - Size: ");
//Serial.println(upload.totalSize);
}//end-if-upload-end
delay(0); //give some time?
//debug spiffs files on serial:
//spiffsListFiles();
}//end-function
/*********************************************************************************************/
/*
String getContentType(String filename) {
if (httpServer.hasArg("download")) return "application/octet-stream";
else if (filename.endsWith(".htm")) return "text/html";
else 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(".json")) return "application/json";
else if (filename.endsWith(".png")) return "image/png";
else if (filename.endsWith(".gif")) return "image/gif";
else if (filename.endsWith(".jpg")) return "image/jpeg";
else if (filename.endsWith(".ico")) return "image/x-icon";
else if (filename.endsWith(".xml")) return "text/xml";
else if (filename.endsWith(".pdf")) return "application/x-pdf";
else if (filename.endsWith(".zip")) return "application/x-zip";
else if (filename.endsWith(".gz")) return "application/x-gzip";
return "text/plain";
}
*/
String getContentType(String filename) {
if (httpServer.hasArg("download")) return F("application/octet-stream");
else if (filename.endsWith(".htm")) return F("text/html");
else if (filename.endsWith(".html")) return F("text/html");
else if (filename.endsWith(".css")) return F("text/css");
else if (filename.endsWith(".js")) return F("application/javascript");
else if (filename.endsWith(".json")) return F("application/json");
else if (filename.endsWith(".png")) return F("image/png");
else if (filename.endsWith(".gif")) return F("image/gif");
else if (filename.endsWith(".jpg")) return F("image/jpeg");
else if (filename.endsWith(".ico")) return F("image/x-icon");
else if (filename.endsWith(".xml")) return F("text/xml");
else if (filename.endsWith(".pdf")) return F("application/x-pdf");
else if (filename.endsWith(".zip")) return F("application/x-zip");
else if(filename.endsWith(".otf")) return F("application/x-font-opentype");
else if(filename.endsWith(".eot")) return F("application/vnd.ms-fontobject");
else if(filename.endsWith(".svg")) return F("image/svg+xml");
else if(filename.endsWith(".woff")) return F("application/x-font-woff");
else if(filename.endsWith(".woff2")) return F("application/x-font-woff2");
else if(filename.endsWith(".ttf")) return F("application/x-font-ttf");
else if (filename.endsWith(".gz")) //gziped version of files exist, so send the coreesponding filetype for a .gz file-ending (i.e. of a font or css)
{
if (filename.indexOf(".htm.") >= 0 ) { return F("text/html"); }
else if (filename.indexOf(".html.") >= 0 ) { return F("text/html"); }
else if (filename.indexOf(".css.") >= 0 ) { return F("text/css"); }
else if (filename.indexOf(".js.") >= 0 ) { return F("application/javascript"); }
else if (filename.indexOf(".json.") >= 0 ) { return F("application/json"); }
else if (filename.indexOf(".png.") >= 0 ) { return F("image/png"); }
else if (filename.indexOf(".gif.") >= 0 ) { return F("image/gif"); }
else if (filename.indexOf(".jpg.") >= 0 ) { return F("image/jpeg"); }
else if (filename.indexOf(".ico.") >= 0 ) { return F("image/x-icon"); }
else if (filename.indexOf(".xml.") >= 0 ) { return F("text/xml"); }
else if (filename.indexOf(".pdf.") >= 0 ) { return F("application/x-pdf"); }
else if (filename.indexOf(".zip.") >= 0 ) { return F("application/x-zip"); }
else if(filename.indexOf(".otf") >= 0 ) { return F("application/x-font-opentype"); }
else if(filename.indexOf(".eot") >= 0 ) { return F("application/vnd.ms-fontobject"); }
else if(filename.indexOf(".svg") >= 0 ) { return F("image/svg+xml"); }
else if(filename.indexOf(".woff") >= 0 ) { return F("application/x-font-woff"); }
else if(filename.indexOf(".woff2") >= 0 ) { return F("application/x-font-woff2"); }
else if(filename.indexOf(".ttf") >= 0 ) { return F("application/x-font-ttf"); }
return "application/x-gzip";
}//end-else-normal-gzip
return "text/plain"; //default. if no type-extension
}//end-functions
/*******************************************************************************************/
void spiffsDeleteFile(void)
{
if ( httpServer.args() > 0 ) // get data from this page through POST/GET Fields
{
Serial.println("Deleting one SPIFFS File selected");
for ( uint8_t i = 0; i < httpServer.args(); i++ )
{ // Iterate through the fields
Serial.println("Deleting one SPIFFS File:");
if (httpServer.argName(i) == "file" ) //rename id to deletefile, also in javascript
{
String fileName = httpServer.arg(i);
fileName.replace("/",""); // remove directory-part ?
if(!SPIFFS.exists(fileName))
{
Serial.println("File does not exists!");
Serial.printf("No File to delete: %s\n", fileName.c_str() );
}
else
{
Serial.printf("Deleting File: %s\n", fileName.c_str() );
SPIFFS.remove(fileName);
}//end-else
}//end-if-arg-name
}//end-for
}//end-if
}//end-function
/*******************************************************************************************/
String FNformatBytes(size_t bytes)
{
if (bytes < 1024)
{
return String(bytes)+"B";
}
else if (bytes < (1024 * 1024))
{
return String(bytes/1024.0)+"KB";
}
else if(bytes < (1024 * 1024 * 1024))
{
return String(bytes/1024.0/1024.0)+"MB";
}
else
{
return String(bytes/1024.0/1024.0/1024.0)+"GB";
}
}//end-function
/*********************************************************************************************/
void handlePostData()
{
Serial.print( "-------------------------------");
Serial.print( "handlePostData() called at: ");
Serial.print ( hour() );
Serial.print( " : ");
Serial.print ( minute() );
Serial.println( " (hrs:min)");
if ( httpServer.args() > 0 ) // get data from this page through POST/GET Fields
{
for ( uint8_t i = 0; i < httpServer.args(); i++ )
{ // Iterate through the fields
/*
if (httpServer.argName(i) == "firstname")
{
// Your processing for the transmitted form-variable
String fName = httpServer.arg(i);
Serial.println(fName);
}//end-if
*/
Serial.print( "name: " );
Serial.print( httpServer.argName(i) );
Serial.print( " value: " );
Serial.print( httpServer.arg(i) );
Serial.print( " value to Int: " );
Serial.print( httpServer.arg(i).toInt() );
Serial.println( );
if ( httpServer.argName(i) == "matrixmode" )
{
}//end-if-matrixmode
}//end-for-iterate-server-args
//button1:
if ( httpServer.arg("switch1") == "'..switch1_pin..'" )
{
Serial.println( "arg:switch.has.value..1_pin. Now creating dummy-files." );
}
}//end-if-server-has-args
//show URI
//if(httpServer.uri() != "/upload") return; //url-path must be /upload, otherwise exit.
Serial.print( "URI: " );
Serial.println( httpServer.uri() );
//show headers... (http://bienonline.magix.net/public/esp8266-webserver-klasse.html#esp-fun)
/*
// Gewünschte Header-Elemente festlegen (https://de.wikipedia.org/wiki/Liste_der_HTTP-Headerfelder)
const char* Headers[] = {"User-Agent", "Connection"};
// Speicherung anfordern
httpServer.collectHeaders(Headers, sizeof(Headers)/ sizeof(Headers[0]));
*/
// Gespeicherte Header-Elemente ausgeben
Serial.print( "Headers count: " );
Serial.println( httpServer.headers() );
for (int i = 0; i < httpServer.headers(); i++)
{
Serial.printf( "Header[%i]: %s\n", i, httpServer.header(i).c_str() );
/*
Serial.println( httpServer.header(i) );
Serial.println( httpServer.header(i).c_str() );
*/
}
Serial.print("Host in headers: ");
Serial.println( httpServer.hostHeader() );
//!!dont send any response to client!! //gives browser error on ajax-request
httpServer.send(200, "text/plain", ""); //send nothing?
//httpServer.send(200, "text/html", "OK --> MD5: "+browserMD5);
}//end-func