diff --git a/examples/csvLoggerSdFat/csvLoggerSdFat.ino b/examples/csvLoggerSdFat/csvLoggerSdFat.ino new file mode 100644 index 00000000..512ad6e6 --- /dev/null +++ b/examples/csvLoggerSdFat/csvLoggerSdFat.ino @@ -0,0 +1,155 @@ +#include +#include + +// Timezone definition to get properly time from NTP server +#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" +#include + +#define PIN_CS 14 +#define PIN_SCK 13 +#define PIN_MOSI 12 +#define PIN_MISO 11 + + +AsyncFsWebServer server(80, SD, "myServer"); +struct tm ntpTime; +const char* basePath = "/csv"; + +//////////////////////////////// NTP Time ///////////////////////////////////////// +void getUpdatedtime(const uint32_t timeout) { + uint32_t start = millis(); + do { + time_t now = time(nullptr); + ntpTime = *localtime(&now); + delay(1); + } while (millis() - start < timeout && ntpTime.tm_year <= (1970 - 1900)); +} + + +//////////////////////////////// Filesystem ///////////////////////////////////////// +bool startFilesystem(){ + if (SD.begin(PIN_CS)){ + server.printFileList(SD, "/", 2); + return true; + } + else { + Serial.println("ERROR on mounting filesystem. It will be formmatted!"); + ESP.restart(); + } + return false; +} + +//////////////////////////// Append a row to csv file /////////////////////////////////// +bool appenRow() { + getUpdatedtime(10); + + char filename[24]; + snprintf(filename, sizeof(filename), + "%s/%04d_%02d_%02d.csv", + basePath, + ntpTime.tm_year + 1900, + ntpTime.tm_mon + 1, + ntpTime.tm_mday + ); + + File file; + if (SD.exists(filename)) { + file = SD.open(filename, "a"); // Append to existing file + } + else { + file = SD.open(filename, "w"); // Create a new file + file.println("timestamp, free heap, largest free block, connected, wifi strength"); + } + + if (file) { + char timestamp[25]; + strftime(timestamp, sizeof(timestamp), "%c", &ntpTime); + + char row[64]; + #ifdef ESP32 + snprintf(row, sizeof(row), "%s, %d, %d, %s, %d", + timestamp, + heap_caps_get_free_size(0), + heap_caps_get_largest_free_block(0), + (WiFi.status() == WL_CONNECTED) ? "true" : "false", + WiFi.RSSI() + ); + #elif defined(ESP8266) + uint32_t free; + uint16_t max; + ESP.getHeapStats(&free, &max, nullptr); + snprintf(row, sizeof(row), + "%s, %d, %d, %s, %d", + timestamp, free, max, + (WiFi.status() == WL_CONNECTED) ? "true" : "false", + WiFi.RSSI() + ); + #endif + Serial.println(row); + file.println(row); + file.close(); + return true; + } + + return false; +} + + +void setup() { + SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS); + Serial.begin(115200); + + delay(1000); + startFilesystem(); + + // Create csv logs folder if not exists + if (!SD.exists(basePath)) { + SD.mkdir(basePath); + } + + server.setAP("ESP32_CSVLOGGER", "123456789"); + IPAddress myIP = server.startWiFi(15000); + + // Enable ACE FS file web editor and add FS info callback fucntion + server.enableFsCodeEditor(); + #ifdef ESP32 + server.setFsInfoCallback([](fsInfo_t* fsInfo) { + fsInfo->totalBytes = SD.totalBytes(); + fsInfo->usedBytes = SD.usedBytes(); + fsInfo->fsName = "SD"; + }); + #endif + + // Start server + server.init(); + Serial.print(F("\nAsync ESP Web Server started on IP Address: ")); + Serial.println(myIP); + Serial.println(F( + "This is \"scvLoggerSdFat.ino\" example.\n" + "Open /setup page to configure optional parameters.\n" + "Open /edit page to view, edit or upload example or your custom webserver source files." + )); + + // Set NTP servers + #ifdef ESP8266 + configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); + #elif defined(ESP32) + configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); + #endif + + // Wait for NTP sync (with timeout) + getUpdatedtime(5000); + + appenRow(); +} + +void loop() { + if (server.getCaptivePortal()) + server.updateDNS(); + + static uint32_t updateTime; + if (millis()- updateTime > 30000) { + updateTime = millis(); + appenRow(); + } +} diff --git a/examples/csvLoggerSdFat/data/assets/css/index.css b/examples/csvLoggerSdFat/data/assets/css/index.css new file mode 100644 index 00000000..5f2f5461 --- /dev/null +++ b/examples/csvLoggerSdFat/data/assets/css/index.css @@ -0,0 +1,189 @@ +/* Misc */ +html, body { + font-family: "Helvetica","Arial",sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 20px; +} +body { + margin: 0; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + background-color: #fff; +} + +h1 { + margin: 5px; + text-align: center; +} + +p { + font-size: 0.9rem; + margin: 0.5rem 0 1.5rem 0; +} + +a, +a:visited { + color: #08C; + text-decoration: none; +} + +a:hover, +a:focus { + color: #69c773; + cursor: pointer; +} + +a.delete-file, +a.delete-file:visited { + color: #CC0000; + margin-left: 0.5rem; + vertical-align: middle; +} + +button { + display: inline-block; + border-radius: 3px; + border: none; + font-size: 0.9rem; + padding: 0.5rem 1em; + background: #86b32d; + border-bottom: 1px solid #5d7d1f; + color: white; + margin: 5px 0; + text-align: center; +} + +button:hover { + opacity: 0.75; + cursor: pointer; +} + +#page-wrapper { + width: 95%; + background: #FFF; + padding: 1.25rem; + margin: 1rem auto; + min-height: 800px; + border-top: 5px solid #69c773; + box-shadow: 0 2px 10px rgba(0,0,0,0.8); +} + +#content { + width: 85%; + overflow: auto; + height: 86vh; +} + +#files { + width: 15%; +} + +#files ul { + margin: 20px 0; + padding: 0.5rem 1rem; + overflow-y: auto; + list-style: square; + background: #F7F7F7; + border: 1px solid #D9D9D9; + border-radius: 5px; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1); + max-height: 75vh; +} + +#files li { + margin-left: 8px; + font-size: 14px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.container { + display: flex; + flex-direction: row; + align-content: flex-start; + justify-content: space-between; + align-items: flex-start; + column-gap: 10px; + height: 86vh; +} + +.delete { + font-size: 24px; + transition: 0.3s; + margin-top:5px; +} + +.delete-all{ + color: #f44336; + font-size: 12px; + background-color: transparent; + background-repeat: no-repeat; + border: none; + cursor: pointer; + overflow: hidden; +} + +/* Tables */ +.table-holder { + margin-top: 20px; + border: 1px solid lightgray; + border-radius: 5px; + border-bottom: 0px; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +.tables { + margin-bottom: 50px; +} + +table { + width: 100%; + border-bottom: 0px; +} + +table, th, td { + border: 1px solid lightgrey; + border-collapse: collapse; + padding-left: 5px; +} + +table tr:nth-child(even) { + background-color: white; +} + +table tr:nth-child(odd) { + background-color: #f2f2f2; +} + +table th { + background-color: #e1e1e1; + color: black; +} + +/* Sections */ + +.section { + box-shadow: 10px 10px 10px 10px; + background-color: #e5e5e5; + padding: 10px; + padding-top: 20px; + font-size: 18px; +} + +.section-lightgrey { + background-color: #f9f9f9; +} + +/* 100% Image Width on Smaller Screens */ +@media only screen and (max-width: 700px){ + .modal-content { + width: 100%; + } +} diff --git a/examples/csvLoggerSdFat/data/assets/css/style.css b/examples/csvLoggerSdFat/data/assets/css/style.css new file mode 100644 index 00000000..ab8a17b9 --- /dev/null +++ b/examples/csvLoggerSdFat/data/assets/css/style.css @@ -0,0 +1,189 @@ +/* Misc */ +html, body { + font-family: "Helvetica","Arial",sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 20px; +} +body { + margin: 0; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #212529; + text-align: left; + background-color: #fff; +} + +h1 { + margin: 5px; + text-align: center; +} + +p { + font-size: 0.9rem; + margin: 0.5rem 0 1.5rem 0; +} + +a, +a:visited { + color: #08C; + text-decoration: none; +} + +a:hover, +a:focus { + color: #69c773; + cursor: pointer; +} + +a.delete-file, +a.delete-file:visited { + color: #CC0000; + margin-left: 0.5rem; + vertical-align: middle; +} + +button { + display: inline-block; + border-radius: 3px; + border: none; + font-size: 0.9rem; + padding: 0.5rem 1em; + background: #86b32d; + border-bottom: 1px solid #5d7d1f; + color: white; + margin: 5px 0; + text-align: center; +} + +button:hover { + opacity: 0.75; + cursor: pointer; +} + +#page-wrapper { + width: 95%; + background: #FFF; + padding: 1.25rem; + margin: 1rem auto; + min-height: 800px; + border-top: 5px solid #69c773; + box-shadow: 0 2px 10px rgba(0,0,0,0.8); +} + +#content { + width: 85%; + overflow: auto; + height: 86vh; +} + +#files { + width: 15%; + line-height: 1; +} + +#files ul { + margin: 20px 0; + padding: 0.5rem 1rem; + overflow-y: auto; + list-style: square; + background: #F7F7F7; + border: 1px solid #D9D9D9; + border-radius: 5px; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1); + max-height: 75vh; +} + +#files li { + font-size: 14px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.container { + display: flex; + flex-direction: row; + align-content: flex-start; + justify-content: space-between; + align-items: flex-start; + column-gap: 10px; + height: 86vh; +} + +.delete { + font-size: 24px; + transition: 0.3s; + margin-top:5px; +} + +.delete-all{ + color: #f44336; + font-size: 12px; + background-color: transparent; + background-repeat: no-repeat; + border: none; + cursor: pointer; + overflow: hidden; +} + +/* Tables */ +.table-holder { + margin-top: 20px; + border: 1px solid lightgray; + border-radius: 5px; + border-bottom: 0px; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +.tables { + margin-bottom: 50px; +} + +table { + width: 100%; + border-bottom: 0px; +} + +table, th, td { + border: 1px solid lightgrey; + border-collapse: collapse; + padding-left: 5px; +} + +table tr:nth-child(even) { + background-color: white; +} + +table tr:nth-child(odd) { + background-color: #f2f2f2; +} + +table th { + background-color: #e1e1e1; + color: black; +} + +/* Sections */ + +.section { + box-shadow: 10px 10px 10px 10px; + background-color: #e5e5e5; + padding: 10px; + padding-top: 20px; + font-size: 18px; +} + +.section-lightgrey { + background-color: #f9f9f9; +} + +/* 100% Image Width on Smaller Screens */ +@media only screen and (max-width: 700px){ + .modal-content { + width: 100%; + } +} diff --git a/examples/csvLoggerSdFat/data/assets/js/csv.js b/examples/csvLoggerSdFat/data/assets/js/csv.js new file mode 100644 index 00000000..06cdfd23 --- /dev/null +++ b/examples/csvLoggerSdFat/data/assets/js/csv.js @@ -0,0 +1,346 @@ + +// Default file to be loaded with no parameter in url +var filename = ''; + +// JQuery-like selector +var $ = function(el) { + return document.getElementById(el); +}; + + +/** + * @returns {getUserInput.userInput} an object + * containing all the user input at the time + * of the method call. + */ +function getUserInput() { + var userInput = {}; + userInput.fileName = filename; + userInput.maxRows = "0"; + userInput.encoding = 'UTF-8'; + userInput.columnSeparator = ','; + userInput.useQuotes = true; + userInput.firstRowHeaders = true; + userInput.firstRowInlcude = false; + return userInput; +} + +/* Tables */ + +var tableCount = 1; + +/** + * Creates a table holder with the + * given table in it. + * + * @param {type} title + * @param {type} tableHtml + * @returns {String|getTableUnit.tableHolder} + */ + +function getTableUnit(title, tableHtml){ + var id = "table-" + tableCount; + var tableHolder = "
{@name}{@table}
"; + tableHolder = tableHolder.replace("{@name}", title); + tableHolder = tableHolder.replace("{@table}", tableHtml); + tableCount++; + return tableHolder; +} + +/** + * Clears all tables from the page. + */ +function clearTables(){ + tableCount = 1; + $('csv-table').innerHTML = ''; +} + +/** + * Adds (appends) a table holder to the page. + * + * @param {type} unit + * @returns {undefined} + */ +function addTableUnit(unit){ + $('csv-table').innerHTML = unit ; +} + + +function saveTable(filename, text) { + var myblob = new Blob([text]); + var formData = new FormData(); + formData.append("data", myblob, filename); + + // POST data using the Fetch API + fetch('/edit', { + method: 'POST', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Max-Age': '600', + 'Access-Control-Allow-Methods': 'PUT,POST,GET,OPTIONS', + 'Access-Control-Allow-Headers': '*', + 'filename': filename + }, + body: formData + }) + // Handle the server response + .then(response => response.text()) + .then(text => { + console.log(text); + }); +} + + +/* Table downloading */ + +/** + * Download the specified table to + * the users computer. + * + * @param {type} table table number + * @param {save} save file to host memory + * @returns {undefined} + */ + +function downloadTable(table, save = false) { + var tableId = "table-" + table; + + var csvArray = []; + var rows = document.querySelectorAll("#" + tableId + " > table tr"); + + for (var i = 0; i < rows.length; i++) { + var row = [], cols = rows[i].querySelectorAll("td, th"); + for (var j = 0; j < cols.length; j++) { + + var value = cols[j].innerText; + + if(customParseFloat(value) ) { + row.push(value); + } + else { + row.push('"' + value +'"'); + } + } + csvArray.push(row.join(",")); + csvArray.push("\n"); + } + + var csvString = csvArray.join(""); + if (save === false) + download(filename, csvString); + else { + saveTable(filename, csvString); + } +} + + +/** + * Creates and downloads a file to the users computer. + * + * @param {type} filename + * @param {type} text + * @returns {undefined} + */ +function download(filename, text) { + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); +} + +/** + * Gets the users input and creates + * a set of tables from it. + */ +function populate(csv){ + var ui = getUserInput(); + addTableUnit( + getTableUnit( + ui.fileName, + getTable( + csvTo2DArray( + csv, + ui.columnSeparator, + ui.useQuotes, + ui.maxRows + ), + ui.firstRowHeaders, + ui.firstRowInlcude + ) + ) + ); + + // Prevents to ad a new line inside cell + var cells = document.querySelectorAll('td'); + + cells.forEach(item => { + item.addEventListener('keypress', event => { + if ( event.keyCode === 13 ){ + if (window.event) { + window.event.returnValue = false; + } + } + }); + }); +} + +/** + * Load the csv from webserver location and fit table with data +*/ +function loadCsv(path) { + clearTables(); + filename = path; + + fetch(path) + .then(response => response.text()) + .then(textString => { + populate(textString); + }); +} + + +/** + * Standard parseFloat don't handle properly "0", "0.0", "0.00" etc strings + * @param {strNumber} the string representing a number to be parsed + * @returns {float number} or NaN +*/ +function customParseFloat(strNumber){ + if (isNaN(parseFloat(strNumber)) === false){ + let toFixedLength = 0; + + let arr = strNumber.split('.'); + if (arr.length === 2 ){ + toFixedLength = arr[1].length; + } + return parseFloat(strNumber).toFixed(toFixedLength); + } + return NaN; // Not a number +} + +/** + * Creates an unstyled, bare-bones html table + * from the provided 2D(Multidimentional Array). + * + * @param {type} tableArray the 2D array. + * @param {type} useHeaders will make the first row + * in the table bold if true. + * @param {type} dupeHeaders will duplicate the first row + * in the table if true and useHeaders is true. + * @param {type} tableId HTML ID for the table. + * @returns {String} the constructed html table as text. + */ +function getTable(tableArray, useHeaders, dupeHeaders, tableId){ + var tableOpen = ""; + var tableClose = "
"; + + var headerCell = "{@val}"; + var cell = "{@val}"; + + var rowOpen = ""; + var rowClose = ""; + + var table = tableOpen; + + for(i = 0; i < tableArray.length; i++){ + //Row + if(i === 1 && useHeaders && dupeHeaders){ + i = 0; + useHeaders = false; + dupeHeaders = false; + } + + table += rowOpen; + for(j = 0; j < tableArray[i].length; j++){ + //Cell + if(i === 0 && useHeaders){ + table += headerCell.replace("{@val}", tableArray[i][j]); + } else { + table += cell.replace("{@val}", tableArray[i][j]); + } + } + + table += rowClose; + } + + return table + tableClose; +} + +/** + * Creates a 2D (Multidimentional) array from + * CSV data in string form. + * + * @param {type} csv the CSV data. + * @param {type} separator the character used + * to separate the columns/cells. + * @param {type} quotes ignores the separator + * in quoted text. + * @param {type} maxRows the maximum rows + * to scan. + * @returns {Array|csvTo2DArray.table} the CSV data + * as a 2D (Multidimentional) array. + */ +function csvTo2DArray(csv, separator, quotes, maxRows){ + var table = []; + var rows = 0; + + csv.split("\n").map(function(row){ + if(maxRows !== "0") + if(rows >= maxRows) + return; + + var tableRow = getRow(row, separator, quotes); + + if(tableRow === null) + return table; + + table.push(tableRow); + rows++; + }); + + return table; +} + +/** + * Creates an array from a CSV row (line) + * + * @param {type} row the CSV row. + * @param {type} separator character used to separate + * cells/columns + * @param {type} quotes ignores the separator + * in quoted text. + * @returns {Array|getRow.trow} the CSV row as an array. + */ +function getRow(row, separator, quotes){ + if(row.length === 0) + return null; + + isQuoted = false; + var trow = []; + var cell = ""; + + for(var i = 0; i < row.length; i++){ + var char = row.charAt(i); + + if(quotes){ + if(char === '\"' || char === '\''){ + isQuoted = !isQuoted; + continue; + } + } + + if(char === separator && !isQuoted){ + trow.push(cell); + cell = ""; + continue; + } + + cell += char; + } + + trow.push(cell); + return trow; +} \ No newline at end of file diff --git a/examples/csvLoggerSdFat/data/assets/js/index.js b/examples/csvLoggerSdFat/data/assets/js/index.js new file mode 100644 index 00000000..6da60711 --- /dev/null +++ b/examples/csvLoggerSdFat/data/assets/js/index.js @@ -0,0 +1,97 @@ +var dataFolder = document.getElementById("csv-path").value; +var fileList = document.getElementById('file-list'); +var currentFile = ""; + +// Fetch the list of files and fill the filelist +function listFiles() { + var url = '/list?dir=' + dataFolder; + if (url.charAt(url.length - 1) === '/') + url = url.slice(0, -1); // Remove the last character + fetch(url) // Do the request + .then(response => response.json()) // Parse the response + .then(obj => { // DO something with response + fileList.innerHTML = ''; + obj.forEach(function(entry, i) { + addEntry(entry.name); + }); + // Load last file + loadCsv(dataFolder + obj[obj.length -1].name); + }); +} + +// Load selected image inside the preview content +function loadFile(filename) { + loadCsv(filename); +} + +// Delete selected file in SD +async function deleteFile(filename) { + var isExecuted = confirm("Are you sure to delete "+ filename + "?"); + if(isExecuted){ + const data = new URLSearchParams(); + data.append('path', filename); + fetch('/edit', { + method: 'DELETE', + body: data + }); + // Update the file browser. + listFiles(); + } +} + +async function deleteAll() { + var isExecuted = confirm("Are you sure to delete all files in "+ dataFolder + " folder?"); + if(isExecuted){ + var ul = document.getElementById("file-list"); + var items = ul.getElementsByClassName("edit-file"); + for (var i=0; i + + + + ESP32 CSV List + + + + +
+
+

CSV list web interface

+
+
+
    +
    + +

    + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/examples/csvLoggerSdFat/readme.md b/examples/csvLoggerSdFat/readme.md new file mode 100644 index 00000000..47cdd6c2 --- /dev/null +++ b/examples/csvLoggerSdFat/readme.md @@ -0,0 +1,4 @@ +An example for logging to a CSV file and viewing the content with the browser. +It is also possible to modify or download the file. + +![image](https://github.com/cotestatnt/esp-fs-webserver/assets/27758688/a776a217-f634-480c-873c-8914e82f87e3) \ No newline at end of file diff --git a/src/AsyncFsWebServer.cpp b/src/AsyncFsWebServer.cpp index ce586ba6..ff5a7ca8 100644 --- a/src/AsyncFsWebServer.cpp +++ b/src/AsyncFsWebServer.cpp @@ -119,8 +119,6 @@ void AsyncFsWebServer::enableFsCodeEditor() { } bool AsyncFsWebServer::startCaptivePortal(const char* ssid, const char* pass, const char* redirectTargetURL) { - - WiFi.mode(WIFI_AP); delay(250); @@ -302,23 +300,46 @@ void AsyncFsWebServer::handleScanNetworks(AsyncWebServerRequest *request) { request->send(200, "application/json", "{\"reload\" : 1}"); } -bool AsyncFsWebServer::createDirFromPath(const String& filePath) { - log_debug("Check path: %s", filePath.c_str()); - int lastSlashIndex = filePath.lastIndexOf('/'); - if (lastSlashIndex != -1) { - String folderPath = filePath.substring(0, lastSlashIndex); - if (!m_filesystem->exists(folderPath)) { - if (m_filesystem->mkdir(folderPath)) { - log_debug("Folder %s created", folderPath.c_str()); - return true; - } - else { - log_debug("Error. Folder %s not created", folderPath.c_str()); - return false; +// bool AsyncFsWebServer::createDirFromPath(const String& filePath) { +// log_debug("Check path: %s", filePath.c_str()); +// int lastSlashIndex = filePath.lastIndexOf('/'); +// if (lastSlashIndex != -1) { +// String folderPath = filePath.substring(0, lastSlashIndex + 1); +// if (!m_filesystem->exists(folderPath)) { +// if (m_filesystem->mkdir(folderPath)) { +// log_debug("Folder %s created", folderPath.c_str()); +// return true; +// } +// else { +// log_debug("Error. Folder %s not created", folderPath.c_str()); +// return false; +// } +// } +// } +// return false; +// } + + +bool AsyncFsWebServer::createDirFromPath(const String& path) { + String dir; + int p1 = 0; int p2 = 0; + while (p2 != -1) { + p2 = path.indexOf("/", p1 + 1); + dir += path.substring(p1, p2); + // Check if its a valid dir + if (dir.indexOf(".") == -1) { + if (!m_filesystem->exists(dir)) { + if (m_filesystem->mkdir(dir)) { + log_info("Folder %s created\n", dir.c_str()); + } else { + log_info("Error. Folder %s not created\n", dir.c_str()); + return false; + } } } + p1 = p2; } - return false; + return true; } void AsyncFsWebServer::handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { diff --git a/src/AsyncFsWebServer.h b/src/AsyncFsWebServer.h index 4a6ca7be..e470d7bd 100644 --- a/src/AsyncFsWebServer.h +++ b/src/AsyncFsWebServer.h @@ -19,7 +19,7 @@ #endif #define DBG_OUTPUT_PORT Serial -#define LOG_LEVEL 2 // (0 disable, 1 error, 2 info, 3 debug) +#define LOG_LEVEL 3 // (0 disable, 1 error, 2 info, 3 debug) #ifndef ESP_FS_WS_EDIT #define ESP_FS_WS_EDIT 1 //has edit methods @@ -129,7 +129,7 @@ class AsyncFsWebServer : public AsyncWebServer String m_apSSID = ""; String m_apPsk = ""; bool m_captiveRun = false; - IPAddress m_captiveIp = IPAddress(8, 8, 8, 8); + IPAddress m_captiveIp = IPAddress(192, 168, 4, 1); public: SetupConfigurator* setup = nullptr; @@ -192,7 +192,7 @@ class AsyncFsWebServer : public AsyncWebServer */ IPAddress startWiFi(uint32_t timeout, const char *apSSID, const char *apPsw, CallbackF fn=nullptr) { setAP(apSSID, apPsw, m_captiveIp); - startWiFi(timeout, fn); + return startWiFi(timeout, fn); } /* @@ -273,7 +273,7 @@ class AsyncFsWebServer : public AsyncWebServer /* * Set Access Point SSID and password */ - void setAP(const char *ssid, const char *psk, IPAddress ip = IPAddress(8,8,8,8)) { + void setAP(const char *ssid, const char *psk, IPAddress ip = IPAddress(192,168,4,1)) { m_apSSID = ssid; m_apPsk = psk; m_captiveIp = ip;