hi,
I have added a html grid (10x12) to my html website (ID numbering 0-119) and now would like to retrieve which cell had been clicked by mouse (similar to read html button click).
How would that be possible?
Or which different widget would I have to choose to read mouse clicks inside?
void handleWebsite() {
int igrid=0;
String script="";
String website_title = "myESP32WifiServer";
WiFiClient client = wifiserver.available(); // listen for incoming clients
//if(!client) return; // <<<<<<<< needed?
if (client) { // if you get a client,
Serial.println("New Client."); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
script += "HTTP/1.1 200 OK \n";
script += "Content-type:text/html \n";
script += "\n";
// *SNIP*
script += "<style>";
script += " #grid { ";
script += " display: grid; ";
script += " grid-template-columns: repeat(10, 40px); ";
script += " grid-template-rows: repeat(12, 40px); ";
script += " grid-gap: 2px; ";
script += " } ";
script += " #grid > div { ";
script += " font-size: 10px; ";
script += " padding: .5em; ";
script += " background: gold; ";
script += " text-align: center; ";
script += " } ";
script += " </style> ";
script += " <div id=\"grid\"> ";
for(igrid=0; igrid<120; igrid++) {
script += " <div>" +(String)igrid+"</div> ";
}
script += " </div> ";
// The HTTP response ends with 2 blank lines:
script += "\n";
script += "\n";
client.print(script);
// break out of the while loop:
break;
}
else { // if you got a newline, then clear currentLine:
currentLine = "";
}
}
else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
delay(1);
// Check the client request (grid or button click):
// *SNIP*
}
}
// close the connection:
client.stop();
delay(1);
Serial.println("Client Disconnected.");
}
delay(5);
}
good idea, just the positioning and initialization perhaps would be more challenging...
(And I admittedly never used radiobuttons by html code.)
In fact, the value (state) will have to be stored.
If there will be really no easier code for the grid cell reading then I'll probably think about that, thank you!
To specify the number of columns of the grid and the widths of each column, the CSS property grid-template-columns is used on the grid container . The number of width values determines the number of columns and each width value can be either in pixels( px ) or percentages(%).
thank you, but I do not get it:
How am I supposed to use this JS function code in my Arduino C++ html code addressing my ESP32 WiFiClient()?
Or how to port that to C++ or html or css?
function getCellText(e) {
if (!isNaN(e.target.innerHTML)) // Check if is a valid number (string)
console.log(e.target.innerHTML);
}
document.getElementById("grid").addEventListener('click', getCellText);
This must be at the end of your HTML page enclosed in a script tag.
The problem could be that you are not serving a well formed HTML webpage but just a bunch of <div></div> elements
<script>
function getCellText(e) {
if (!isNaN(e.target.innerHTML)) // Check if is a valid number (string)
console.log(e.target.innerHTML);
}
document.getElementById("grid").addEventListener('click', getCellText);
</script>
I am adding different lines as Strings to build the website, and then sending that entire String by
client.print(script);
that is the way the example code works - I don't have another working code for ES32 WiFiServer/Client yet.
This code is also featuring website buttons to switch remote LEDs additionally which are read e.g. by sort of
// *SNIP*
String currentLine = ""; // make a String to hold incoming data from the client
// *SNIP*
if (OUT1 == HIGH) {
script += "<a href=\" /OUT1L\"\"> <button style=\"height:70px;width:70px; background-color: red\" > 1=EIN </button></a> ";
}
else if (OUT1 == LOW) {
script += "<a href=\" /OUT1H\"\"> <button style=\"height:70px;width:70px; background-color: white\" > 1=AUS </button></a> ";
}
//...
if (currentLine.endsWith("GET /OUT1H")) {
OUT1=HIGH; // GET /OUT1H turns the LED on
}
if (currentLine.endsWith("GET /OUT1L")) {
OUT1=LOW; // GET /OUT1L turns the LED off
}
So how can I make it work with my code and the extra grid?
And as I need to store the cell number in a variable, how to I change this line
console.log(e.target.innerHTML);
by sort of
int cell_ID = e.target.innerHTML;
Serial.println(cell_ID);
static const char html_start[] PROGMEM = R"EOF(
<!DOCTYPE html>
<html>
<style>
#grid {
display: grid;
grid-template-columns: repeat(10, 40px);
grid-template-rows: repeat(12, 40px);
grid-gap: 2px;
}
#grid > div {
font-size: 10px;
padding: .5em;
background: gold;
text-align: center;
}
</style>
<body>
)EOF";
static const char html_end_script[] PROGMEM = R"EOF(
<script>
function getCellText(e) {
if (!isNaN(e.target.innerHTML)) // Check if is a valid number (string)
console.log(e.target.innerHTML);
}
document.getElementById("grid").addEventListener('click', getCellText);
</script>
</body>
</html>
)EOF";
void handleWebsite() {
int igrid = 0;
String script = "";
String website_title = "myESP32WifiServer";
WiFiClient client = wifiserver.available(); // listen for incoming clients
//if(!client) return; // <<<<<<<< needed?
if (client) { // if you get a client,
Serial.println("New Client."); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
script += "HTTP/1.1 200 OK \n";
script += "Content-type:text/html \n";
script += "\n";
// *SNIP*
script += html_start;
script += " <div id=\"grid\"> ";
for (igrid = 0; igrid < 120; igrid++) {
script += " <div>" + (String)igrid + "</div> ";
}
script += " </div> ";
script += html_end_script;
// The HTTP response ends with 2 blank lines:
script += "\n";
script += "\n";
client.print(script);
// break out of the while loop:
break;
}
else { // if you got a newline, then clear currentLine:
currentLine = "";
}
}
else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
delay(1);
// Check the client request (grid or button click):
// *SNIP*
}
}
// close the connection:
client.stop();
delay(1);
Serial.println("Client Disconnected.");
}
delay(5);
}
The variable on which side? You need to store on your webpage or back to the microcontroller?
In the second case you should delve deeper into the concept of HTTP AJAX calls.
In fact, in my opinion you should actually review the entire functioning of your web pages according to this principle.
For example, you could generate the table with 120 cells dynamically directly in the html page and set the click event hanlder in order to send back the actual value to the microcrontroller.
As you can see, the page code is all in the HTML section, so you can serve the webpage simply (compared to the link I gave you above, I prefer to use the fetch API instead of XMLHttpRequest).
I need the variable on my ESP32 for further processing,
like reading a mouseclick on the website, return it's buttonstate by the value of the currentLine String,
if (currentLine.endsWith("GET /OUT1H")) {
OUT1=HIGH; // GET /OUT1H turns the LED on
}
if (currentLine.endsWith("GET /OUT1L")) {
OUT1=LOW; // GET /OUT1L turns the LED off
}
PS, I actually don't understand how this or either different website works actually, I just have c+p'ed this code I have shown, I changed and extended it a little, and it eventually works for my buttons.
tbh, I do not even understand what your
is really for and what it does.
Now I would need working code also for reading my grids, but how to write that is WAY beyond my skills.
PS,
the entire WiFiServer code (without grids yet) I have posted here: https://forum.arduino.cc/t/how-to-extend-html-wifiserver-code-esp32-to-additionally-display-a-video-stream/1178283
(How I hate how this effing forum's editor processes links!!!)
Starting from the example link, all I can do is provide you a working small sketch.
For the rest you will have to study and deepen these concepts if you want to continue developing this project in a more avdanced way.
This is only a convenient way to write a constant literal string without wasting precious SRAM .
Everything between the delimiters R"EOF(.....)EOF" will be saved in the char array which is stored in program section memory instead of SRAM.
In this way you can save your HTML webpage (or others literal srings) in flash memory instead creating it at runtime.
static const char html_end_script[] PROGMEM = R"EOF(
Your literal string can be written here even adding new lines without \n and \r chars
)EOF";
Thank you very much for your efforts, I actually could compile your example code and it really works fine out of the box.
Do you know how to change the color of the grid cells related to their current actual states (e.g., red/lightgray for true/false, toggle by either click) ?
For further processing I would intermediately store all values in a global array,
char gridState[129];
initialized in setup()
memset(gridState, 0, sizeof(gridState) );
and then toggle states here in this function immediately after
...server.arg("val").toInt()
You can change almost everything with Javascript on your webpage included styling properties.
So, from your webpage you should as first thing query the MCU for actual array state.
Once you have a valid reply from ESP32, the Javascript can build the grid with right colors depending of the actual state.
thank you!
I tested but the grid has only 1 cell (0),
but the good news is that it more or less toggles it's color by mouseclick (albeit wrong way round as the 1st click is ignored).
(BTW for better visability a changed the colors to
default 0=lightgray / 1=red )
I didn't understand this though, tbh:
Maybe you need to avoid last comma to be sended by ESP32
thank you very much!
Now just the color toggles always 1 click delayed,
it starts correctly with grey cells (grids=0),
but after the 1st click somewhere (e.g. 19) nothing changes by color (state of 19 toggles to 1 though)
and only after each follow-up click then it shows the alternative color (value 19 state to 0 but color=>red which is the inverse color for state=0).
Can you confirm that or is it now me who has an obscured c+p error?
OTOH,
would it be possible to read the cell states from the global gridState array in order to apply the correct color?
because when I close the browser tab (whilst running program) and reopen it then agaiin, the grids don't show the correct state colors any more but they all are initialized by lightgray instead...