Add light file manager to upload/download/delete
files on SPIFFS - need to decrease printer.tpl size to implement have more space for new settings.tpl for 64K SPIFFS
BIN
Page1.png
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 27 KiB |
BIN
Page2.png
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
BIN
Page3.png
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 16 KiB |
BIN
Page4.png
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 20 KiB |
BIN
Page6.png
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 31 KiB |
@ -73,7 +73,7 @@ the template files are stored on SPIFFS:
|
||||
and uploaded using [IDE](http://arduino.esp8266.com/versions/1.6.5-1160-gef26c5f/doc/reference.html#file-system)
|
||||
The list of keywords can be find here : https://github.com/luc-github/ESP8266/blob/master/keywords.txt
|
||||
Any files on SPIFFS can be called on web interface without having the path hard coded - this give more flexibility, favicon.ico is a good example of it.
|
||||
So UI is kind of separated from FW which allow easier modifications.
|
||||
So UI is kind of separated from FW which allow easier modifications. For this a light file manager is available in extra settings page, it allows to upload/download/delete files. as SPIFFS is flat filesystem no directory management is necessary so it is very simple.
|
||||
|
||||
Additionally 404.tpl (the page not found) and restart.tpl(restart page when applying changes) are not mandatory, a fail safe version is embeded if they are not present.
|
||||
|
||||
|
@ -15,7 +15,7 @@ $INCLUDE[css.inc]$
|
||||
<td class="$MENU_AP$"><a href="http://$WEB_ADDRESS$/CONFIGAP">AP Configuration</a></td>
|
||||
<td class="$MENU_STA$"><a href="http://$WEB_ADDRESS$/CONFIGSTA">Station Configuration</a></td>
|
||||
<td class="$MENU_PRINTER$"><a href="http://$WEB_ADDRESS$/PRINTER">Printer Status</a></td>
|
||||
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Printer Settings</a></td>
|
||||
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Extra Settings</a></td>
|
||||
<td width=100%> </td>
|
||||
<td>FW: V$FW_VER$</td>
|
||||
<td><a href="https://github.com/luc-github/ESP8266" >Github</a></td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
$INCLUDE[header.inc]$
|
||||
<div class="panel">
|
||||
<div class="panel-heading">Printer Settings</div>
|
||||
<div class="panel-heading">Extra Settings</div>
|
||||
<div class="panel-body">
|
||||
<form method="POST">
|
||||
<div class="form-group $REFRESH_PAGE_STATUS$"><label class="control-label" for="CONFIG1">Refresh page time: </label><br>
|
||||
@ -22,6 +22,65 @@ $SUCCESS_MSG$
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-heading">Filesystem</div>
|
||||
<div class="panel-body">
|
||||
<input type="file" id="file-select" name="myfiles[]" multiple />
|
||||
<input type="button" id="upload-button" onclick="Sendfile();" value="Upload"/><br><br>
|
||||
<table class="table table-striped" style="border:1px;solid #dddddd;margin-bottom:20px;" ><thead><tr><th>Name</th><th>size</th><th width='0%'></th></tr></thead><tbody id="file_list"><tbody></table>
|
||||
<label class="text-info" id="status"></label>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function dispatchstatus(jsonresponse)
|
||||
{
|
||||
var content ="";
|
||||
document.getElementById('status').innerHTML=jsonresponse.status;
|
||||
for (var i=0;i <jsonresponse.files.length;i++){
|
||||
content +="<TR><TD style=\"cursor:hand;\" onclick=\"window.open('"+jsonresponse.files[i].name+"');\">";
|
||||
content +=jsonresponse.files[i].name;
|
||||
content +="</TD><TD>";
|
||||
content +=jsonresponse.files[i].size;
|
||||
content +="</TD><TD width='0%'><div style=\"cursor:hand; background:red; color:white;border-radius:12px ;\" onclick=\"Delete('"+jsonresponse.files[i].name+"')\"> × ";
|
||||
content +="</div></TD></TR>";
|
||||
}
|
||||
document.getElementById('file_list').innerHTML=content;}
|
||||
function Delete(filename){
|
||||
if (confirm("Confirm deletion of :" + filename))SendCommand("delete",filename);
|
||||
}
|
||||
function SendCommand(action,filename){
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
var url = "/FILES?action="+action;
|
||||
url += "&filename="+encodeURI(filename);
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
var jsonresponse = JSON.parse(xmlhttp.responseText);
|
||||
dispatchstatus(jsonresponse);}
|
||||
}
|
||||
xmlhttp.open("GET", url, true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
function Sendfile(){
|
||||
document.getElementById('upload-button').value = "Uploading...";
|
||||
var files = document.getElementById('file-select').files;
|
||||
var formData = new FormData();
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var file = files[i];
|
||||
formData.append('myfiles[]', file, "/"+file.name);}
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.open('POST', '/FILES', true);
|
||||
xmlhttp.onload = function () {
|
||||
if (xmlhttp.status === 200) {
|
||||
document.getElementById('upload-button').value = 'Upload';
|
||||
document.getElementById('file-select').value="";
|
||||
var jsonresponse = JSON.parse(xmlhttp.responseText);
|
||||
dispatchstatus(jsonresponse);
|
||||
} else alert('An error occurred!');
|
||||
}
|
||||
xmlhttp.send(formData);
|
||||
}
|
||||
SendCommand('list','all');
|
||||
</script>
|
||||
$INCLUDE[footer.inc]$
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@ $INCLUDE[css.inc]$
|
||||
<td class="$MENU_AP$"><a href="http://$WEB_ADDRESS$/CONFIGAP">AP Configuration</a></td>
|
||||
<td class="$MENU_STA$"><a href="http://$WEB_ADDRESS$/CONFIGSTA">Station Configuration</a></td>
|
||||
<td class="$MENU_PRINTER$"><a href="http://$WEB_ADDRESS$/PRINTER">Printer Status</a></td>
|
||||
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Printer Settings</a></td>
|
||||
<td class="$MENU_SETTINGS$"><a href="http://$WEB_ADDRESS$/SETTINGS">Extra Settings</a></td>
|
||||
<td width=100%> </td>
|
||||
<td>FW: V$FW_VER$</td>
|
||||
<td><a href="https://github.com/luc-github/ESP8266" >Github</a></td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
$INCLUDE[header.inc]$
|
||||
<div class="panel">
|
||||
<div class="panel-heading">Printer Settings</div>
|
||||
<div class="panel-heading">Extra Settings</div>
|
||||
<div class="panel-body">
|
||||
<form method="POST">
|
||||
<div class="form-group $REFRESH_PAGE_STATUS$"><label class="control-label" for="CONFIG1">Refresh page time: </label><br>
|
||||
@ -22,6 +22,65 @@ $SUCCESS_MSG$
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-heading">Filesystem</div>
|
||||
<div class="panel-body">
|
||||
<input type="file" id="file-select" name="myfiles[]" multiple />
|
||||
<input type="button" id="upload-button" onclick="Sendfile();" value="Upload"/><br><br>
|
||||
<table class="table table-striped" style="border:1px;solid #dddddd;margin-bottom:20px;" ><thead><tr><th>Name</th><th>size</th><th width='0%'></th></tr></thead><tbody id="file_list"><tbody></table>
|
||||
<label class="text-info" id="status"></label>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function dispatchstatus(jsonresponse)
|
||||
{
|
||||
var content ="";
|
||||
document.getElementById('status').innerHTML=jsonresponse.status;
|
||||
for (var i=0;i <jsonresponse.files.length;i++){
|
||||
content +="<TR><TD style=\"cursor:hand;\" onclick=\"window.open('"+jsonresponse.files[i].name+"');\">";
|
||||
content +=jsonresponse.files[i].name;
|
||||
content +="</TD><TD>";
|
||||
content +=jsonresponse.files[i].size;
|
||||
content +="</TD><TD width='0%'><div style=\"cursor:hand; background:red; color:white;border-radius:12px ;\" onclick=\"Delete('"+jsonresponse.files[i].name+"')\"> × ";
|
||||
content +="</div></TD></TR>";
|
||||
}
|
||||
document.getElementById('file_list').innerHTML=content;}
|
||||
function Delete(filename){
|
||||
if (confirm("Confirm deletion of :" + filename))SendCommand("delete",filename);
|
||||
}
|
||||
function SendCommand(action,filename){
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
var url = "/FILES?action="+action;
|
||||
url += "&filename="+encodeURI(filename);
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
var jsonresponse = JSON.parse(xmlhttp.responseText);
|
||||
dispatchstatus(jsonresponse);}
|
||||
}
|
||||
xmlhttp.open("GET", url, true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
function Sendfile(){
|
||||
document.getElementById('upload-button').value = "Uploading...";
|
||||
var files = document.getElementById('file-select').files;
|
||||
var formData = new FormData();
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var file = files[i];
|
||||
formData.append('myfiles[]', file, "/"+file.name);}
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.open('POST', '/FILES', true);
|
||||
xmlhttp.onload = function () {
|
||||
if (xmlhttp.status === 200) {
|
||||
document.getElementById('upload-button').value = 'Upload';
|
||||
document.getElementById('file-select').value="";
|
||||
var jsonresponse = JSON.parse(xmlhttp.responseText);
|
||||
dispatchstatus(jsonresponse);
|
||||
} else alert('An error occurred!');
|
||||
}
|
||||
xmlhttp.send(formData);
|
||||
}
|
||||
SendCommand('list','all');
|
||||
</script>
|
||||
$INCLUDE[footer.inc]$
|
||||
|
||||
|
||||
|
@ -180,7 +180,7 @@ const char KEY_E_FEEDRATE [] PROGMEM = "$E_FEEDRATE$";
|
||||
const char KEY_XY_FEEDRATE_STATUS [] PROGMEM = "$XY_FEEDRATE_STATUS$";
|
||||
const char KEY_Z_FEEDRATE_STATUS [] PROGMEM = "$Z_FEEDRATE_STATUS$";
|
||||
const char KEY_E_FEEDRATE_STATUS [] PROGMEM = "$E_FEEDRATE_STATUS$";
|
||||
const char VALUE_SETTINGS [] PROGMEM = "Printer Settings";
|
||||
const char VALUE_SETTINGS [] PROGMEM = "Extra Settings";
|
||||
const char KEY_REFRESH_PAGE_STATUS [] PROGMEM = "$REFRESH_PAGE_STATUS$";
|
||||
|
||||
bool WEBINTERFACE_CLASS::isHostnameValid(const char * hostname)
|
||||
@ -2306,13 +2306,24 @@ void handle_web_interface_status()
|
||||
buffer2send+="\"}";
|
||||
}
|
||||
buffer2send+="]";
|
||||
// buffer2send+="\"end\":\"end\"";
|
||||
buffer2send+="}";
|
||||
web_interface->WebServer.send(200, "text/plain",buffer2send);
|
||||
web_interface->WebServer.send(200, "application/json",buffer2send);
|
||||
Serial.println(system_get_free_heap_size());
|
||||
|
||||
}
|
||||
|
||||
String formatBytes(size_t bytes){
|
||||
if (bytes < 1024){
|
||||
return String(bytes)+"oct";
|
||||
} else if(bytes < (1024 * 1024)){
|
||||
return String(bytes/1024.0)+"Ko";
|
||||
} else if(bytes < (1024 * 1024 * 1024)){
|
||||
return String(bytes/1024.0/1024.0)+"Mo";
|
||||
} else {
|
||||
return String(bytes/1024.0/1024.0/1024.0)+"Go";
|
||||
}
|
||||
}
|
||||
|
||||
String getContentType(String filename){
|
||||
if(filename.endsWith(".htm")) return "text/html";
|
||||
else if(filename.endsWith(".html")) return "text/html";
|
||||
@ -2331,6 +2342,65 @@ String getContentType(String filename){
|
||||
else if(filename.endsWith(".txt")) return "text/plain";
|
||||
return "application/octet-stream";
|
||||
}
|
||||
void handleFileUpload(){
|
||||
if(web_interface->WebServer.uri() != "/FILES") return;
|
||||
HTTPUpload& upload = (web_interface->WebServer).upload();
|
||||
if(upload.status == UPLOAD_FILE_START){
|
||||
String filename = upload.filename;
|
||||
web_interface->fsUploadFile = SPIFFS.open(filename, "w");
|
||||
filename = String();
|
||||
} else if(upload.status == UPLOAD_FILE_WRITE){
|
||||
if(web_interface->fsUploadFile)
|
||||
{
|
||||
web_interface->fsUploadFile.write(upload.buf, upload.currentSize);
|
||||
}
|
||||
} else if(upload.status == UPLOAD_FILE_END){
|
||||
if(web_interface->fsUploadFile)
|
||||
web_interface->fsUploadFile.close();
|
||||
}
|
||||
else Serial.println("Cannot open file");
|
||||
}
|
||||
|
||||
void handleFileList() {
|
||||
String path = "/";
|
||||
String status="Ok";
|
||||
if(web_interface->WebServer.hasArg("action")) {
|
||||
if(web_interface->WebServer.arg("action")=="delete" && web_interface->WebServer.hasArg("filename"))
|
||||
{
|
||||
String filename;
|
||||
web_interface->urldecode(filename,web_interface->WebServer.arg("filename").c_str());
|
||||
if(!SPIFFS.exists(filename)){
|
||||
status="Cannot delete, file not found!";
|
||||
}
|
||||
else
|
||||
{
|
||||
SPIFFS.remove(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
String jsonfile = "{\"path\":\"" + path + "\",";
|
||||
Dir dir = SPIFFS.openDir(path);
|
||||
jsonfile+="\"files\":[";
|
||||
bool firstentry=true;
|
||||
while (dir.next()) {
|
||||
if (!firstentry) jsonfile+=",";
|
||||
else firstentry=false;
|
||||
jsonfile+="{";
|
||||
jsonfile+="\"name\":\"";
|
||||
jsonfile+=dir.fileName();
|
||||
jsonfile+="\",\"size\":\"";
|
||||
File f = dir.openFile("r");
|
||||
jsonfile+=formatBytes(f.size());
|
||||
jsonfile+="\"";
|
||||
jsonfile+="}";
|
||||
f.close();
|
||||
}
|
||||
jsonfile+="],";
|
||||
jsonfile+="\"status\":\"" + status + "\"";
|
||||
jsonfile+="}";
|
||||
path = "";
|
||||
web_interface->WebServer.send(200, "application/json", jsonfile);
|
||||
}
|
||||
|
||||
//do a redirect to avoid to many query
|
||||
//and handle not registred path
|
||||
@ -2558,6 +2628,8 @@ WEBINTERFACE_CLASS::WEBINTERFACE_CLASS (int port):WebServer(port)
|
||||
WebServer.on("/PRINTER",HTTP_ANY, handle_web_interface_printer);
|
||||
WebServer.on("/CMD",HTTP_ANY, handle_web_command);
|
||||
WebServer.on("/RESTART",HTTP_GET, handle_restart);
|
||||
WebServer.on("/FILES", HTTP_ANY, handleFileList);
|
||||
WebServer.onFileUpload(handleFileUpload);
|
||||
//Captive portal Feature
|
||||
#ifdef CAPTIVE_PORTAL_FEATURE
|
||||
WebServer.on("/generate_204",HTTP_ANY, handle_web_interface_root);
|
||||
@ -2580,6 +2652,7 @@ WEBINTERFACE_CLASS::WEBINTERFACE_CLASS (int port):WebServer(port)
|
||||
info_msg.setlenght(50);
|
||||
status_msg.setsize(4);
|
||||
status_msg.setlenght(50);
|
||||
fsUploadFile=(fs::File)0;
|
||||
}
|
||||
//Destructor
|
||||
WEBINTERFACE_CLASS::~WEBINTERFACE_CLASS()
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <FS.h>
|
||||
#include "storestrings.h"
|
||||
|
||||
#define MAX_EXTRUDERS 4
|
||||
@ -34,6 +35,7 @@ class WEBINTERFACE_CLASS
|
||||
WEBINTERFACE_CLASS (int port = 80);
|
||||
~WEBINTERFACE_CLASS();
|
||||
ESP8266WebServer WebServer;
|
||||
File fsUploadFile;
|
||||
void urldecode( String & dst, const char *src);
|
||||
bool isSSIDValid(const char * ssid);
|
||||
bool isPasswordValid(const char * password);
|
||||
|