1

I'm trying to use ESP32 + Arduino IDE to control a relay.

I've started by using the library and the code below.

The problem I'm having:

after clicking on the button and activating the pin, if the browser is left like this, and then the page gets refreshed by mistake, the action will be repeated.

What I thought might help, is if for any click on the button, the pin activates, and then I get a redirect back to the root of the page. so refreshing will not pose any issue.

I've searched allover the internet and could not find anything conclusive, except for this piece of code, which doesnt seem to make any difference nomatter where I place it in the main code

client.println("HTTP/1.1 307 Temporary Redirect");
client.println("Location: /");
client.println("Connection: Close");
client.println();
client.stop();

and this is the main code:

// Load Wi-Fi library
#include <WiFi.h>
// Replace with your network credentials
const char* ssid = "WalrusnTiny";
const char* password = "994483329I";
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Auxiliar variables to store the current output state
String output26State = "off";
String output27State = "off";
// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;
void setup() {
 Serial.begin(115200);
 // Initialize the output variables as outputs
 pinMode(output26, OUTPUT);
 pinMode(output27, OUTPUT);
 // Set outputs to LOW
 digitalWrite(output26, LOW);
 digitalWrite(output27, LOW);
 // Connect to Wi-Fi network with SSID and password
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 // Print local IP address and start web server
 Serial.println("");
 Serial.println("WiFi connected.");
 Serial.println("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 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
 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) {
 // 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();
 // turns the GPIOs on and off
 if (header.indexOf("GET /26/on") >= 0) { 
 client.println();
 output26State = "on";
 digitalWrite(output26, HIGH);
 } else if (header.indexOf("GET /26/off") >= 0) {
 Serial.println("GPIO 26 off");
 output26State = "off";
 digitalWrite(output26, LOW);
 } else if (header.indexOf("GET /27/on") >= 0) {
 Serial.println("GPIO 27 on");
 output27State = "on";
 digitalWrite(output27, HIGH);
 } else if (header.indexOf("GET /27/off") >= 0) {
 Serial.println("GPIO 27 off");
 output27State = "off";
 digitalWrite(output27, LOW);
 }
 // 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 
 // Feel free to change the background-color and font-size attributes to fit your preferences
 client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
 client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
 client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
 client.println(".button2 {background-color: #555555;}</style></head>");
 // Web Page Heading
 client.println("<body><h1>ESP32 Web Server</h1>");
 // Display current state, and ON/OFF buttons for GPIO 26 
 client.println("<p>GPIO 26 - State " + output26State + "</p>");
 // If the output26State is off, it displays the ON button 
 if (output26State=="off") {
 client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
 } else {
 client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
 } 
 // Display current state, and ON/OFF buttons for GPIO 27 
 client.println("<p>GPIO 27 - State " + output27State + "</p>");
 // If the output27State is off, it displays the ON button 
 if (output27State=="off") {
 client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");
 } else {
 client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");
 }
 client.println("</body></html>");
 // The HTTP response ends with another blank line
 client.println();
 // 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
 }
 }
 }
 // Clear the header variable
 header = "";
 // Close the connection
 Serial.println("Client disconnected.");
 Serial.println("");
 }
}

Any help would be greatly appreciated. Thank you in advance.

asked Feb 21, 2019 at 20:03

2 Answers 2

2

Solved:

Just needed to add this code to every button press,

 client.print("<HEAD>");
 client.print("<meta http-equiv=\"refresh\" content=\"0;url=/\">");
 client.print("</head>");
answered Feb 22, 2019 at 10:04
0
0

First probably mention this is too much overhead for a webserver

adding

include <WebServer.h>

you can handle those endpoints easily

See https://lastminuteengineers.com/creating-esp32-web-server-arduino-ide/

Basically:

setup() {
 ...
 server.on("/", handle_OnConnect);
 server.on("/led1on", handle_led1on);
 server.on("/led1off", handle_led1off);
 server.on("/led2on", handle_led2on);
 server.on("/led2off", handle_led2off);
 server.onNotFound(handle_NotFound);
 
 server.begin();
 Serial.println("HTTP server started");
}
void loop() {
 server.handleClient();
 ...
}
void handle_led1on() {
 LED1status = HIGH;
 Serial.println("GPIO4 Status: ON");
 server.send(200, "text/html", SendHTML(true,LED2status)); 
}

Anyway this is still wrong, as you end with same problem, /led1on renders as your main page

A better solution would be to use this endpoint handlers to set the variable and just redirect:

Here a complete solution

#include <WiFi.h>
include <WebServer.h>
// Replace with your network credentials
const char* ssid = "SSID";
const char* password = "password";
// Set web server port number to 80
WebServer server(80);
uint8_t led1Pin = 12;
uint8_t led2Pin = 13;
bool led1State = LOW;
bool led2State = LOW;
void setup() {
 Serial.begin(115200);
 // Initialize the output variables as outputs
 pinMode(led1Pin, OUTPUT);
 pinMode(led2Pin, OUTPUT);
 // Set outputs to LOW
 led1State = LOW;
 led2State = LOW;
 digitalWrite(led1Pin, led1State);
 digitalWrite(led2Pin, led2State);
 // Connect to Wi-Fi network with SSID and password
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 // Print local IP address and start web server
 Serial.println("");
 Serial.println("WiFi connected.");
 Serial.println("IP address: ");
 Serial.println(WiFi.localIP());
 
 server.on("/", handle_root);
 server.on("/led/1/on", handle_led1on);
 server.on("/led/1/off", handle_led1off);
 server.on("/led/2/on", handle_led2on);
 server.on("/led/2/off", handle_led2off);
 server.onNotFound(handle_NotFound);
 server.begin();
 Serial.println("HTTP Server started");
}
void handle_root() {
 server.send(200, "text/html", sendHTML());
}
 
void handle_led1on() {
 led1State = HIGH;
 Serial.println("led1 state: ON");
 server.sendHeader("Location", "/",true); 
 server.send(302, "text/plain", "");
}
 
void handle_led1off() {
 led1State = LOW;
 Serial.println("led1 state: OFF");
 server.sendHeader("Location", "/",true);
 server.send(302, "text/plain", "");
}
 
void handle_led2on() {
 led2State = HIGH;
 Serial.println("led2 state: ON");
 server.sendHeader("Location", "/",true);
 server.send(302, "text/plain", "");
}
 
void handle_led2off() {
 led2State = LOW;
 Serial.println("led2 state: OFF");
 server.sendHeader("Location", "/",true);
 server.send(302, "text/plain", "");
}
 
void handle_NotFound() {
 server.send(404, "text/html", sendPageUnknown());
}
String sendPageUnknown() {
 String ptr = "<!DOCTYPE html> <html>\n";
 
 ptr += "<head>";
 
 ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
 //ptr += "<meta http-equiv=\"refresh\" content=\"0;url=/\">";
 ptr += "<title>Page unknown</title>\n";
 
 ptr += "</head>\n";
 ptr += "<body>\n";
 ptr += "<h1>Page unknown</h1>\n";
 ptr += "<a href=\"/\">Return to main page</a>\n";
 
 ptr += "</body>\n";
 ptr += "</html>\n";
 return ptr;
}
String sendHTML() {
 digitalWrite(led1Pin, led1State);
 digitalWrite(led2Pin, led2State);
 String ptr = "<!DOCTYPE html> <html>\n";
 
 ptr += "<head>";
 
 ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
 ptr += "<title>LED Dashboard</title>\n";
 
 ptr += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
 ptr += "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
 ptr += ".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
 ptr += ".button-on {background-color: #3498db;}\n";
 ptr += ".button-on:active {background-color: #2980b9;}\n";
 ptr += ".button-off {background-color: #34495e;}\n";
 ptr += ".button-off:active {background-color: #2c3e50;}\n";
 ptr += "p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
 ptr += "</style>\n";
 ptr += "</head>\n";
 ptr += "<body>\n";
 ptr += "<h1>ESP32 Web Server</h1>\n";
 if (led1State)
 {
 ptr += "<p>LED1: ON</p><a class=\"button button-off\" href=\"/led/1/off\">OFF</a>\n";
 }
 else
 {
 ptr += "<p>LED1: OFF</p><a class=\"button button-on\" href=\"/led/1/on\">ON</a>\n";
 }
 
 if (led2State)
 {
 ptr += "<p>LED2: ON</p><a class=\"button button-off\" href=\"/led/2/off\">OFF</a>\n";
 }
 else
 {
 ptr += "<p>LED2: OFF</p><a class=\"button button-on\" href=\"/led/2/on\">ON</a>\n";
 }
 
 ptr += "</body>\n";
 ptr += "</html>\n";
 return ptr;
}
void loop() {
 server.handleClient();
}

Even that is suboptimal, as led endpoints shouldn't be GET endpoints but POST (really PUT as it only updates info, but let's stick to POST for simplicity)

Here a version using POST and unique endpoint /led to handle any number of less to manage:

#include <WebServer.h>
// Replace with your network credentials
const char* ssid = "SSID";
const char* password = "password";
// Set web server port number to 80
WebServer server(80);
uint8_t led1Pin = 12;
uint8_t led2Pin = 13;
bool led1State = LOW;
bool led2State = LOW;
void setup() {
 Serial.begin(115200);
 // Initialize the output variables as outputs
 pinMode(led1Pin, OUTPUT);
 pinMode(led2Pin, OUTPUT);
 // Set outputs to LOW
 led1State = LOW;
 led2State = LOW;
 digitalWrite(led1Pin, led1State);
 digitalWrite(led2Pin, led2State);
 // Connect to Wi-Fi network with SSID and password
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 // Print local IP address and start web server
 Serial.println("");
 Serial.println("WiFi connected.");
 Serial.println("IP address: ");
 Serial.println(WiFi.localIP());
 
 server.on("/", handle_root);
 server.on("/led", HTTP_POST, handle_led);
 server.onNotFound(handle_NotFound);
 server.begin();
 Serial.println("HTTP Server started");
}
void handle_root() {
 server.send(200, "text/html", sendHTML());
}
uint8_t evaluate_led_state(String ledState) {
 uint8_t state;
 if (ledState == "on") {
 Serial.println("led state: ON");
 state = HIGH;
 } else if (ledState == "off") {
 Serial.println("led state: OFF");
 state = LOW;
 } else {
 Serial.println("unknow led state: "+ledState);
 }
 return state;
}
void handle_led() {
 String ledPin = server.arg("ledPin");
 String ledState = server.arg("ledState");
 if (ledPin == "1") {
 Serial.println("setting led1");
 led1State = evaluate_led_state(ledState);
 } else if (ledPin == "2") {
 Serial.println("setting led2");
 led2State = evaluate_led_state(ledState);
 } else {
 Serial.println("led unknow: "+ledPin);
 }
 server.sendHeader("Location", "/",true); 
 server.send(302, "text/plain", "");
}
 
void handle_NotFound() {
 server.send(404, "text/html", sendPageUnknown());
}
String sendPageUnknown() {
 String ptr = "<!DOCTYPE html> <html>\n";
 
 ptr += "<head>";
 
 ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
 ptr += "<title>Page unknown</title>\n";
 
 ptr += "</head>\n";
 ptr += "<body>\n";
 ptr += "<h1>Page unknown</h1>\n";
 ptr += "<a href=\"/\">Return to main page</a>\n";
 
 ptr += "</body>\n";
 ptr += "</html>\n";
 return ptr;
}
String build_led_form(String ledPin, uint8_t ledState) {
 String ptr = "<form action=\"led\" method=\"post\">\n";
 ptr += " <input type=\"hidden\" name=\"ledPin\" value=\""+ledPin+"\">\n";
 String ledStateStr;
 
 if (ledState)
 {
 ledStateStr = "off";
 }
 else
 {
 ledStateStr = "on";
 }
 ptr += " <input type=\"hidden\" name=\"ledState\" value=\""+ledStateStr+"\">\n";
 ptr += " <label>Led"+ledPin+"</label>\n";
 ptr += " <input type=\"submit\" class=\"button button-"+ledStateStr+"\" value=\"";
 ledStateStr.toUpperCase();
 ptr += ledStateStr+"\">\n";
 ptr += "</form>\n";
 return ptr;
}
String sendHTML() {
 digitalWrite(led1Pin, led1State);
 digitalWrite(led2Pin, led2State);
 String ptr = "<!DOCTYPE html> <html>\n";
 
 ptr += "<head>";
 
 ptr += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
 ptr += "<title>LED Dashboard</title>\n";
 
 ptr += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
 ptr += "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;} form {margin-bottom: 30px;}\n";
 ptr += ".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;text-decoration: none;font-size: 25px;margin: auto;cursor: pointer;border-radius: 4px;}\n";
 ptr += ".button-on {background-color: #3498db;}\n";
 ptr += ".button-on:active {background-color: #2980b9;}\n";
 ptr += ".button-off {background-color: #34495e;}\n";
 ptr += ".button-off:active {background-color: #2c3e50;}\n";
 ptr += "p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
 ptr += "</style>\n";
 ptr += "</head>\n";
 ptr += "<body>\n";
 ptr += "<h1>ESP32 Web Server</h1>\n";
 ptr += build_led_form("1", led1State);
 ptr += build_led_form("2", led2State);
 
 ptr += "</body>\n";
 ptr += "</html>\n";
 return ptr;
}
void loop() {
 server.handleClient();
}

For non trivial management you probably want to use spiffs

https://randomnerdtutorials.com/esp32-web-server-spiffs-spi-flash-file-system/

answered Sep 13, 2022 at 6:54

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.