Search code examples
htmlarduinowifiesp8266

How do I add a delay before an HTML redirect with an ESP8266?


I've set up a simple ESP8266 web server that allows me to remotely control LEDs. It uses four buttons: one for each LED and one to turn off all the LEDs. When you click a button, it sends you to /LED and sends a value. Based on what the value is, it sends back plain text saying the color of the LED turned on. So far, it works fine, and the LEDs turn on or off as expected. However, I would like it to redirect to the root page after it lets you know which LED has been changed. I know that you can send a "Location" header and then a 303 code to do that, but that redirects immediately and doesn't allow me to show any text. I've already tried running something like this when handling the request to turn on an LED:

server.send(200, "text/plain", "led color");
delay(2000);
server.sendHeader("Location","/");
server.send(303);

This shows the text as expected, but never redirects back to the root page. Is there a straightforward way to show the text and then redirect after a short delay?

Here's the full code:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h> 
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>   // Include the WebServer library

ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'

ESP8266WebServer server(80);    // Create a webserver object that listens for HTTP request on port 80

void handleRoot();              // function prototypes for HTTP handlers
void handleNotFound();

void setup(void){
  pinMode(0, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(0, HIGH);
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);

  //Serial.begin(115200);         // Start the Serial communication to send messages to the computer
  delay(10);
  //Serial.println('\n');

  wifiMulti.addAP("*****", "*****");   // add Wi-Fi networks you want to connect to

  //Serial.println("Connecting ...");
  //int i = 0;
  while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
    delay(250);
    //Serial.print('.');
  }
  //Serial.println('\n');
  //Serial.print("Connected to ");
  //Serial.println(WiFi.SSID());              // Tell us what network we're connected to
  //Serial.print("IP address:\t");
  //Serial.println(WiFi.localIP());           // Send the IP address of the ESP8266 to the computer

  MDNS.begin("ledtower");
  //if (MDNS.begin("ledtower")) {              // Start the mDNS responder for ledtower.local
    //Serial.println("mDNS responder started");
  //} else {
    //Serial.println("Error setting up MDNS responder!");
  //}

  server.on("/", handleRoot);               // Call the 'handleRoot' function when a client requests URI "/"
  server.on("/LED", handleLED);             // Call the 'handleLED' function
  server.onNotFound(handleNotFound);        // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound"

  server.begin();                           // Actually start the server
  //Serial.println("HTTP server started");
}

void loop(void){
  server.handleClient();                    // Listen for HTTP requests from clients
}

void handleRoot() {
  server.send(200, "text/html", "<form action='/LED' method='post'><button type='submit' name='color' value='red'>Red LED</button><br><button type='submit' name='color' value='yellow'>Yellow LED</button><br><button type='submit' name='color' value='green'>Green LED</button><br><button type='submit' name='color' value='none'>Turn off LEDs</button></form>");   // Send HTTP status 200 (Ok) and send some text to the browser/client
}

void handleLED(){
  if(server.arg("color") == "red"){
    digitalWrite(0, LOW);
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
    server.send(200, "text/plain", "Red!"); 
  }
  if(server.arg("color") == "yellow"){
    digitalWrite(0, HIGH);
    digitalWrite(2, LOW);
    digitalWrite(3, HIGH);
    server.send(200, "text/plain", "Yellow!"); 
  }
  if(server.arg("color") == "green"){
    digitalWrite(0, HIGH);
    digitalWrite(2, HIGH);
    digitalWrite(3, LOW);
    server.send(200, "text/plain", "Green!"); 
  }
  if(server.arg("color") == "none"){
    digitalWrite(0, HIGH);
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
    server.sendHeader("Location","/");
    server.send(303);
  }
  else{
    server.send(400, "text/plain", "400: Invalid Request");
  }
}

void handleNotFound(){
  server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request
}

Solution

  • That's not the way HTTP redirects work. You can either send the redirect or you can send content. You can't do both. Also, as the HTTP redirect is an HTTP header field, it has to be sent before you would send any content.

    You can use an HTML redirect. You'll need to return a properly formatted HTML with which would look something like this:

    <html>
      <head>
        <meta http-equiv="refresh" content="2; URL=/" />
      </head>
      <body>
        led color
      </body>
    </html>
    

    In general displaying content and then redirecting is a poor design. It's okay for debugging but a bad way to interact with real users as they'll miss the message if they look away for a moment. It's better to redirect to the desired page and have that page present the content in a status or "flash" message.