Closed Tech500 closed 3 years ago
[STALE_SET] This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.
server.on("/whatever", HTTP_GET, [](AsyncWebServerRequest *request){
String resp = "<br><br><br><h2><a href='BME680'>Home</a></h2> ";
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", resp);
response->addHeader("Access-Control-Allow-Origin","*");
request->send(response);
});
Thank you zekageri; for your response.
[STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future.
Is it possible to add a html link to a text file. Fuction reads a text file and displays to browser. Have been unable to add link after text file has been displayed.
`void notFound(AsyncWebServerRequest *request) {
digitalWrite(online, HIGH); //turn-on online LED indicator
if (! request->url().endsWith(F(".TXT")))
{
request->send(404);
}
else
{
if (request->url().endsWith(F(".TXT")))
{
//.endsWith(F(".txt")))
// here comes some mambo-jambo to extract the filename from request->url()
int fnsstart = request->url().lastIndexOf('/');
fn = request->url().substring(fnsstart);
PATH = fn;
accessLog();
Serial.print("File: ");
Serial.println(fn);
File webFile = SPIFFS.open(fn);
Serial.print("File size: ");
Serial.println(webFile.size());
if (!webFile)
{
Serial.println("File: " + fn + " failed to open");
Serial.println("\n");
}
else if (webFile.size() == 0)
{
String resp = "<br><br><br><h2><a href=http://%LINK%/Weather >Home</a> ";
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", resp);
response->addHeader("Access-Control-Allow-Origin","*");
request->send(response);
webFile.close();
}
else
{
//request->send(SPIFFS, fn, String(), true); //Download file
request->send(SPIFFS, fn, String(), false); //Display file
webFile.close();
}
fn = "";
end();
}
}
digitalWrite(online, LOW); //turn-off online LED indicator
}`
William
I don't really understand what you want to do here.
In this example you opened a file and did nothing with it. You can serve a whole HTML page from directly the filesystem if you want. And inside that html file you can put whatever you like. Even links to another url on your esp.
zekageri your code works perfectly from setup. Is there way to provide a solution from inside "notFound(AsyncWebServerRequest *request) fuction? My attemps have all failed.
Yes. You can serve whatever you want from any callback. I will write a code for you soon.
Thank you zekageri; appreciate the help!
Here is an example for the notfound callback.
server.onNotFound([](AsyncWebServerRequest *request){
// for the LITTLEFS you can write your speicifc fs for example SPIFFS, next the actual file name in your system and the content type.
AsyncWebServerResponse* response = request->beginResponse(LITTLEFS, "/NotFound.html", "text/html");
// response->addHeader("Content-Encoding", "gzip"); // uncomment this if your file is gzipped
request->send(response);
});
Here is a favicon with cache control
server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request){
AsyncWebServerResponse* response = request->beginResponse(LITTLEFS, "/AppIcon.png","image/png");
response->addHeader("Cache-Control", "max-age=31536000");
request->send(response);
});
Here is a jSON file from the file system
server.on("/newManifest.json", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncWebServerResponse* response = request->beginResponse(LITTLEFS, "/newManifest.json", "application/json");
response->addHeader("Cache-Control", "max-age=31536000");
request->send(response);
});
Here is the index.html ( the main page ) with gzipped content encoding.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncWebServerResponse* response = request->beginResponse(LITTLEFS, "/index.html", "text/html");
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
zekageri really appreciate all the coding you wrote
This code is what trying to do in my project; on Win pb this code displays log file, then adds url link to bottom of displayed log file; which is plain text only.
<html>
<head>
<title>README</title>
</head>
<body>
<div><object data="C:\users\1234\Desktop\Notes\LOG07042020.TXT" width="100%" height="800"></object></div>
<br><h2><a href=http://10.0.0.100:8030/SdBrowse >SdBrowse</a>
</body>
</html>
Log*.TXT files are listed as url links on the SdBrowse web page; once selected the filename
is extracted by the notFound function, then the file is displayed.
Best I can summarize; is showing what I have done so far, this from the notFound function
to which the url link is passed, then file name is extracted.
String resp = "<!DOCTYPE html><html><head><title>Observations</title></head><body>";
resp += "<div><object data=" + fn + " width='100%' height='800'></object></div>";
resp += "<br><h2><a href=http://10.0.0.100:8030/SdBrowse >SdBrowse</a></body></html>";
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", resp);
response->addHeader("Access-Control-Allow-Origin","*");
request->send(response);
So if i understand you correctly.
You want a webpage where you can push a button and it displays a log file which is served from the esp32's filesystem?
You could serve a page from the esp like this:
// It will send the index.html file
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncWebServerResponse* response = request->beginResponse(LITTLEFS, "/index.html", "text/html");
request->send(response);
});
INDEX.HTML file would look like this:
note: i'm using JQUERY here from a CDN
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<title>Test</title>
</head>
<body>
<button onclick="fetchLogFile()" type="button" id="showLogFile">Show log</button>
<div id="logFileDiv"></div>
</body>
<script>
function fetchLogFile(){
// FETCHING THE FILE FROM THE ESP
$.get("/getMyLog", // <-- TheURLForLogFile
function (data, textStatus, jqXHR) {
$("#logFileDiv").append(data); // <-- HERE I APPEND THE DATA TO THE DIV
},
);
}
</script>
</html>
server.on("/getMyLog", HTTP_GET, [](AsyncWebServerRequest *request) {
String LOGSTRING = "blablabla";
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", LOGSTRING );
request->send(response);
});
ESP could serve the whole file to the response like this:
server.on("/getMyLog", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncWebServerResponse* response = request->beginResponse(LITTLEFS, "/LOGFILE.txt", "text/html");
request->send(response);
});
I would like to pass variable "fn" (developed in the notFound function) instead of a hard coded file name; do not see a way to do this in your examples. Do you think it is possible?
But why would you do that? I dont see the point. Do you need 404 response code? You can create one in an other callback.
In my example, your log file content will be appended to the web page's div. Just like you did. But without the link element. If you want to wrap every line in your txt file into a link element you can do that on the client side via javascript. That way the esp doesnt have to handle that as well.
I serve a web page that lists all LOG files. Once a file is selected it becomes a notFound request and the filename is extracted; which is the fn named variable. Since we can not have a GET request for each LOG filename; this is the reason it needs to be a variable.
Current code displays LOG file well; just with no way to reurn directly to the servered web page that lists LOG files, other than using the back arrow in the browser.
You can download the files when the user clicks one of the links.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Note iam using JQUERY -->
<title>Test</title>
</head>
<body>
<label for="logs">Select a log file</label>
<select name="logOptions" id="logs">
<option value="log1.txt">log1</option> <!-- value is the name of the file -->
<option value="log2.txt">log2</option>
<option value="log3.txt">log3</option>
<option value="log4.txt">log4</option>
</select>
<div id="logFileDiv"></div>
</body>
<script>
$(document).ready(function () {
$("#logs").on("change", function (e) {
var logFileName = $(this).val();
downloadLogFile(logFileName);
});
});
// Note there are no error checks in this example.
function downloadLogFile(fileName){
$.ajax({
url:`/downLog?param0=/${fileName}`,
success: function (data){
$("#logFileDiv").empty();
$("#logFileDiv").html(data);
}
});
}
</script>
</html>
server.on("/downLog", HTTP_GET, [](AsyncWebServerRequest *request){
AsyncWebParameter* p = request->getParam(0);
AsyncWebServerResponse *response;
char fileBuff[32];
p->value().toCharArray(fileBuff,32);
if( LITTLEFS.exists(fileBuff) ){
response = request->beginResponse(LITTLEFS, fileBuff, "text/plain", true);
request->send(response);
}else{
response = request->beginResponse(204, "text/plain", "No such file");
request->send(response);
}
});
That way you serve a relative small html page and fetch the contents of the log files when the user wants to see it. And you don't have to show them an other page, they can see it right there.
Does jQuery need to be installed on Win pc to use your code? Could not get code to work.
Jquery is a frontend javascript library. In this case, it will work if you have an internet connection. At least the esp. But i assume you have since i can see the esp's web interface so the problem is elsewhere. What part is not working?
But why would you want to use the notfound handler for this?
You can create an other callback just like i said and download the logs as you wish. If the problem is that the log file names are hardcoded, you can fetch all the files in the filesystem when a user loads a page and put all the file names inside the select element in my example.
"Lots of "moving" parts," I do not list all files; only LOG*.TXT files with the SdBrowse request. Requested url is not found; goes to the notfound handler, "/filename" is extracted from url Then sent using "request->send(SPIFFS, fn, String(), false); //Display file."
I would like to avoid adding additional "serverAsync.on("/something", HTTP_GET." Plus; I want to pass variable to String processor6 for "uncfn," which is "/" taken off the fn variable Need for
Would like to replace "request->send(SPIFFS, fn, String(), false);" with something similar to "request->send_P(200, PSTR("text/html"), HTML6, processor6);"
zekageri, Took another look at your example code; works 100%, thank you.
How would I format:
"Lat: 39.76091 , Long: -85.99419 Elevation: 843 Feet Indianapolis, IN , Sun , 07/04/2021 , 00:00:00 EDT Sun , 07/04/2021 , 00:00:00 EDT , Temperature: 79.3 F. , Heatindex: 78.9 F. , Humidity: 41.7 % , Dewpoint: 54.1 F. , Barometer: 29.968 inHg. , 0.000 Diff. inHg , Day 0.00 , Hour 0.00 , Five Minute 0.00 Sun , 07/04/2021 , 00:15:00 EDT , Temperature: 79.3 F. , Heatindex: 78.9 F. , Humidity: 42.0 % , Dewpoint: 54.2 F. , Barometer: 29.969 inHg. , 0.000 Diff. inHg , Day 0.00 , Hour 0.00 , Five Minute 0.00"
--to have it on a single line with no wrapping?
You can do this on Javascript client side. Before you append the content of the file you could replace or remove all the line breaks first like this:
someText = someText.replace(/(\r\n|\n|\r)
And your text should be in someText
variable without Line breaks.
Example from my previous example JS:
function downloadLogFile(fileName){
$.ajax({
url:`/downLog?param0=/${fileName}`,
success: function (data){
// replacing all kinds of line breaks with regex.
$("#logFileDiv").html( data.replace(/(\r\n|\n|\r) );
// Or here is an alternative, it is replacing with nothing '' or you can replace it with a blank whitespace ' ';
// $("#logFileDiv").html( data.replace(/(?:\r\n|\r|\n)/g, '') );
}
});
}
Sara Santos @ rntlab.com found a better solution:
To solve that issue you can add the following styling to the paragraph that displays the data:
white-space: pre-wrap;
Sara found this suggestion here: Solution
Now; log files have header, text area and hyperlink!
You wanted the text in a single line without wrapping and you does not said that you wanted it formatted. In this case you better create the txt file already formatted when logging at esp side. Or you could easily log this information in a JSON file at esp side and client side you can do anything with that JSON. ^^
check out arduinojson library
zekageri Thank you for all your coding examples and patience and time spent responding.
Here is code I am using to add header, text area, and hyperlink:
"HTML6":
const char HTML6[] PROGMEM = R"====(
<!DOCTYPE HTML>
<html>
<head>
<title>Show</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.main
{
type: text/txt;
font-size:18px;
width: auto;
height: auto;
margin: 30px;
}
</style>
</head>
<body>
<h2>Observations
<!-- <a href="/Show"><button>Show Log File</button></a> -->
<br>
<br>
<div class="main" style="white-space: pre-wrap;" type="text/txt" id=file-content></div>
<!-- <p style="white-space: pre-wrap;"id="file-content"></p> -->
<br>
<a href=http://%LINK%/SdBrowse >SdBrowse</a></h2><br>
</body>
<script>
window.addEventListener('load', getFile);
function getFile(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function()
{
if (this.readyState == 4 && this.status == 200)
{
console.log(this.responseText);
document.getElementById("file-content").innerHTML=this.responseText;
}
};
xhr.open("GET", "/get-file", true);
xhr.send();
}
</script>
</html>
)====";
----------
Request "/Show " //Loads HTML6
serverAsync.on("/Show", HTTP_GET, [](AsyncWebServerRequest * request) {
PATH = "/Show";
accessLog();
if (! flag == 1)
{
request->send_P(200, PSTR("text/html"), HTML6, processor6);
}
end();
});
Request to get text file for HTML6:
serverAsync.on("/get-file", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, fn, "text/txt");
});
---------------------
Request to get redirect from "notFound" function:
serverAsync.on("/redirect/internal", HTTP_GET, [](AsyncWebServerRequest *request){ request->redirect("/Show"); //recevies HTML request to redirect });
All that is left is a bit "fine tuning."
ESP32 Project "RainGauge" code
William
Trying to add a link to return to Home link; inside of a text file being displayed.
request->send("text/html", "<br><br><br><h2><a href='linkAddress/BME680' >Home"</a></h2>);
What is the correct syntax?
William