Интернет-сервер Arduino IDE + ESP32 — как перенаправить на root после нажатия кнопки

Я пытаюсь использовать ESP32 + Arduino IDE для управления реле.

Я начал с использования библиотеки и приведенного ниже кода.

Проблема, с которой я столкнулся:

после нажатия на кнопку и активации контакта, если оставить браузер в таком виде, а затем по ошибке обновить страницу, действие повторится.

Я подумал, что это может помочь, если при любом нажатии на кнопку активируется контакт, а затем я получаю перенаправление обратно в корень страницы. поэтому обновление не вызовет никаких проблем.

Я искал по всему Интернету и не смог найти ничего убедительного, кроме этого фрагмента кода, который, кажется, не имеет никакого значения, где бы я ни разместил его в основном коде

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

а это основной код:

// Загрузить библиотеку Wi-Fi
#include <WiFi.h>

// Замените учетными данными вашей сети
const char* ssid     = "WalrusnTiny";
const char* password = "994483329I";

// Установить номер порта веб-сервера на 80
WiFiServer server(80);

// Переменная для хранения HTTP-запроса
String header;

// Вспомогательные переменные для хранения текущего состояния вывода
String output26State = "off";
String output27State = "off";

// Назначаем выходные переменные контактам GPIO
const int output26 = 26;
const int output27 = 27;

void setup() {

  Serial.begin(115200);
  // Инициализировать выходные переменные как выходы
  pinMode(output26, OUTPUT);
  pinMode(output27, OUTPUT);
  // Установить выходы на НИЗКИЙ уровень
  digitalWrite(output26, LOW);
  digitalWrite(output27, LOW);

  // Подключаемся к сети Wi-Fi с SSID и паролем
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Выводим локальный IP-адрес и запускаем веб-сервер
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}




void loop(){
  WiFiClient client = server.available();   // Слушаем входящих клиентов

  if (client) {                             // Если подключается новый клиент,
    Serial.println("New Client.");          // вывести сообщение в последовательный порт
    String currentLine = "";                // создаем строку для хранения входящих данных от клиента
    while (client.connected()) {            // цикл, пока клиент подключен
      if (client.available()) {             // если есть байты для чтения от клиента,
        char c = client.read();             // прочитать байт, затем
        Serial.write(c);                    // вывести его на серийный монитор
        header += c;
        if (c == '\n') {                    // если байт является символом новой строки
          // если текущая строка пуста, вы получили два символа новой строки подряд.
          // это конец клиентского HTTP-запроса, поэтому отправьте ответ:
          if (currentLine.length() == 0) {
            // Заголовки HTTP всегда начинаются с кода ответа (например, HTTP/1.1 200 OK)
            // и тип контента, чтобы клиент знал, что придет, затем пустая строка:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // включает и выключает GPIO
            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);
            }

            // Отображение веб-страницы в формате HTML
            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 для оформления кнопок включения/выключения
            // Не стесняйтесь изменять атрибуты background-color и font-size в соответствии с вашими предпочтениями
            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>");

            // Заголовок веб-страницы
            client.println("<body><h1>ESP32 Web Server</h1>");
            // Отображение текущего состояния и кнопки ВКЛ/ВЫКЛ для GPIO 26
            client.println("<p>GPIO 26 - State " + output26State + "</p>");
            // Если output26State выключен, отображается кнопка ON
            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>");
            } 

            // Отображение текущего состояния и кнопки ВКЛ/ВЫКЛ для GPIO 27
            client.println("<p>GPIO 27 - State " + output27State + "</p>");
            // Если output27State выключен, отображается кнопка ON
            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>");

            // Ответ HTTP заканчивается еще одной пустой строкой
            client.println();
            // Выход из цикла while
            break;
          } else { // если вы получили новую строку, то очищаем currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // если вы получили что-то еще, кроме символа возврата каретки,
          currentLine += c;      // добавляем его в конец currentLine
        }
      }
    }
    // Очистить переменную заголовка

    header = "";
    // Закрыть соединение



    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Любая помощь будет принята с благодарностью. Заранее спасибо.

, 👍1


2 ответа


2

Решено:

Просто нужно было добавить этот код при каждом нажатии кнопки,

 client.print("<HEAD>");
 client.print("<meta http-equiv=\"refresh\" content=\"0;url=/\">");
 client.print("</head>");
,

Отметьте свое решение как принятое., @RooiWillie


0

Сначала, возможно, стоит упомянуть, что это слишком много для веб-сервера

добавление

include <WebServer.h>

вы можете легко обрабатывать эти конечные точки

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

В основном:

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)); 
}

В любом случае, это все еще неправильно, так как вы заканчиваете с той же проблемой, /led1on отображается как ваша главная страница

Лучшим решением было бы использовать обработчики этой конечной точки для установки переменной и просто перенаправления:

Вот полное решение

#include <WiFi.h>
include <WebServer.h>

// Замените учетными данными вашей сети
const char* ssid = "SSID";
const char* password = "password";

// Установить номер порта веб-сервера на 80
WebServer server(80);

uint8_t led1Pin = 12;
uint8_t led2Pin = 13;

bool led1State = LOW;
bool led2State = LOW;

void setup() {
  Serial.begin(115200);
  // Инициализировать выходные переменные как выходы
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  // Установить выходы на НИЗКИЙ уровень
  led1State = LOW;
  led2State = LOW;
  digitalWrite(led1Pin, led1State);
  digitalWrite(led2Pin, led2State);

  // Подключаемся к сети Wi-Fi с SSID и паролем
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Выводим локальный IP-адрес и запускаем веб-сервер
  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=\"обновить\" содержание=\"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();
}

Даже это неоптимально, так как конечные точки светодиода должны быть не GET конечными точками, а POST (на самом деле PUT, поскольку он только обновляет информацию, но для простоты давайте придерживаться POST)

Вот версия, использующая POST и уникальную конечную точку /led для обработки любого меньшего числа для управления:

#include <WebServer.h>

// Замените учетными данными вашей сети
const char* ssid = "SSID";
const char* password = "password";

// Установить номер порта веб-сервера на 80
WebServer server(80);

uint8_t led1Pin = 12;
uint8_t led2Pin = 13;

bool led1State = LOW;
bool led2State = LOW;

void setup() {
  Serial.begin(115200);
  // Инициализировать выходные переменные как выходы
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  // Установить выходы на НИЗКИЙ уровень
  led1State = LOW;
  led2State = LOW;
  digitalWrite(led1Pin, led1State);
  digitalWrite(led2Pin, led2State);

  // Подключаемся к сети Wi-Fi с SSID и паролем
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Выводим локальный IP-адрес и запускаем веб-сервер
  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();
}

Для нетривиального управления вы, вероятно, захотите использовать spiffs

https://randomnerdtutorials.com/esp32-web-server-spiffs- файловая система spi-flash/

,