The onclick="fetch('/rotate')"
is the entirety of the request.
Web servers are about coding responses to different requests, for example
- the root path
/
/favicon.ico
/someimage.png
/whatever_path_you_used_to_send_that_html
/rotate
You're adding that last one. Servers vary in their API, but it's usually something like
// set up response handlers
server.on("/", serveRoot);
server.on("/favicon.ico", serveFavIcon);
Those are separate functions above, but some servers/examples favor lambdas. Either way, it would look like
server.on("/rotate", HTTP_GET, [] (AsyncWebServerRequest *request) {
rotate(10000); // do the thing
request->send(204); // respond with something, so both
// the server here knows you're done, and
// the client browser is not left hanging
});
But you're not using a web server class; you're manually performing HTTP, as a server. If you're planning on doing more than just this one other thing, I recommend using a real server. But if you're going for the stone knives approach, in addition to the corrected HTML for the input
, it's just a handful of additional statements, added to this stripped-down version that runs on the ESP32 I have handy
#include <WiFi.h>
#include "arduino_secrets.h"
WiFiServer server(80);
void setup() {
Serial.begin(115200);
WiFi.begin(SECRET_SSID, SECRET_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected.");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
////////////////////////////////////////////////////////////////////////////////////////////////
void loop(){
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
Serial.println("New Client."); // print a message out in the serial port
String header;
header.reserve(400);
String currentLine; // make a String to hold incoming data from the client
currentLine.reserve(100);
auto currentTime = millis();
auto previousTime = currentTime;
while (client.connected() && currentTime - previousTime <= 2000) { // loop while the client's connected
currentTime = millis();
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
header += c;
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) {
// Is it the request to rotate?
if (header.startsWith("GET /rotate")) {
rotate(10000);
client.println("HTTP/1.1 204 No Content");
client.println("Connection: close");
client.println();
break;
}
// 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:
client.println("HTTP/1.1 200 OK");
client.println("Content-type: text/html");
client.println("Connection: close");
client.println();
// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS to style the on/off buttons
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #77878A;}</style></head>");
// Web Page Heading
client.println("<body><h1>Snow Dumper</h1>");
// client.println("<p>Current time on device " + formattedTime + "</p>");
client.print("<p>IP Address ""</p>");
client.println(WiFi.localIP());
// Web Page Button
client.println("<p><a href=\"SendPage (rotate(10000))\"><button class=\"button buttonRed\">Press to Dump Snow now</button></a></p>");
//client.println("<input type=button value=ON onmousedown=location.href='/?on4;'>");
//client.println("<input type=button value=Dump1 onclick=(rotate(10000) >");
//client.println("<input type=button value=Dump2 onmousedown=rotate(10000) >");
// use raw string to easily include double-quote in HTML
client.println(R"~(<input type="button" value="Dump2" onclick="fetch('/rotate')">)~");
client.println(); // The HTTP response ends with another blank line
break; // Break out of the while loop
} 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
}
}
}
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println();
}
}
void rotate(int steps){
Serial.print("rotate: ");
Serial.println(steps);
}
This hard-codes the steps
to 10000
. If you want to be able to input that on the web page, the easiest thing would be to have a query parameter. Then the request-line would look like "GET /rotate?steps=9876
". You'd parse out that number.
On the HTML side, you'd have "fetch('/rotate?steps=' + getTheSteps())
", where getTheSteps
reads whatever you're using to input the number. But that's an HTML/JavaScript question, not an Arduino one.
BTW, startsWith("GET /rotate")
also matches /rotaterZZZ
and anything else like that. If you look at the echoed request-line
GET /rotate HTTP/1.1
There's a space between the request-path and the HTTP/
-thing that follows. But if you're doing a query parameter, you'd have to allow for ?
as well. A web server would parse the request-line for you to handle these details.
And now with an exposed endpoint, with no additional checks, anyone that can ping your server can invoke it.