| |

Простой веб-сервер на ESP32. Создание первого веб-сервера на ESP32

Режим работы веб-сервера в качестве «клиента сети»

Всем привет =)

В этой статье я расскажу как создать свой первый веб-сервер на основе очень популярной платы с микроконтроллером ESP32.

Сделаем веб-сервер для управления светодиодами — внешними и встроенным на плате.

Погнали =)

ВНИМАНИЕ!!!! Первым делом, если вы только начинаете работу с ESP32, необходимо установить ядро для плат ESP32 в Arduino IDE!!! Ознакомиться с инструкцией по установке ядра можно по этой ссылке! Ссылка для установки ядра доступна там же. Если вы знаете, как установить ядро, то вот ссылка: https://github.com/espressif/arduino-esp32

Сначала разберемся, что такое веб-сервер.

Веб-сервер — это устройство, которое подключено к WiFi сети или даже к Интернету, имеющее свой IP-адрес или даже доменное имя (например, ya.ru). Веб-сервер получает запросы на свой IP-адрес со сведениями об необходимых данных и посылает в ответ необходимые данные. Сейчас чаще всего веб-сервера используются для хранения сайтов и баз данных, а обычные пользователи посылают запросы на сервер, просто переходя по ссылке или используя приложение для телефона с какой-либо информацией (например, бот в Telegram).

Схема подключения светодиодов к ESP32

Мы сделаем простой локальный веб-сервер, который будет доступен только в нашей домашней сети. В роли сервера будет выступать наша любимая плата ESP32. при включении она сообщит свой IP-адрес, мы перейдём по нему как по ссылке и попадём на веб-страницу, загруженную с платы. Это очень интересно и круто!

Ниже приведённый код вы можете вставить в проект Arduino IDE, залить в свою плату ESP32 и наслаждаться результатом!

Необходимо подключить на пины 12 и 14 два светодиода через резисторы (подходящее сопротивление от 300 до 500 Ом, если будет меньше, светодиоды сгорят, если больше, будут тускло светиться), как показано на схеме. Наш веб-сервер будет управлять двумя светодиодами по нажатию кнопок на локальной веб-странице сервера.

#include <WiFi.h> // Подключаем библиотеку Wi-Fi

// Введите данные вашей СУЩЕСТВУЮЩЕЙ WiFi-сети в кавычках
// ВАЖНО!! Ваш компьютер/телефон должен быть подключен к этой же сети!
const char* ssid = "";
const char* password = "";

// Установка номера порта сервера на 80
WiFiServer server(80);

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

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

// Назначаем выходные переменные контактам GPIO
const int output12 = 12;
const int output14 = 14;

// Текущее время
unsigned long currentTime = millis();

// Предыдущее время
unsigned long previousTime = 0;

// Указываем время задержки в миллисекундах (пример: 2000 мс = 2 сек)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  
  // Устанавливаем пины 12 и 14 на ВЫХОД сигнала
  pinMode(output12, OUTPUT);
  pinMode(output14, OUTPUT);
  
  // Устанавливаем контакты в состояние LOW, то есть ВЫКЛ
  digitalWrite(output12, LOW);
  digitalWrite(output14, LOW);
  
  // Соединяемся с Wi-Fi сетью с нашим SSID и паролем
  Serial.print("Подключаюсь к сети '");
  Serial.print(ssid);
  Serial.print("', пожалуйста, дождитесь появления IP-адреса ");
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  // Выводим IP адрес платы в SerialMonitor и запускаем веб-сервер
  Serial.println("");
  Serial.println("Подключение установлено.");
  Serial.println("IP-адрес этого сервера: ");
  Serial.println(WiFi.localIP());
  Serial.println("Перейдите по этому адресу в браузере для продолжения взаимодействия с сервером ESP32!");
  server.begin();
}
void loop(){
  WiFiClient client = server.available();   // Отслеживаем входящих клиентов
  
  if (client) {                             // Если подключается новый клиент...
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("Новый клиент!");        // ...выводим сообщение в SerialMonitor...
    String currentLine = "";                // ...создаём строковую переменную для данных от клиента...
    while (client.connected() && currentTime - previousTime <= timeoutTime) {  // Цикл, пока клиент подключён...
      currentTime = millis();
      if (client.available()) {             // ...если поступили данные от клиента...
        char c = client.read();             // ...читаем данные...
        Serial.write(c);                    // ...выводим в SerialMonitor...
        header += c;
        if (c == '\n') {                    // Если поступил символ \n...
          // Если текущая строка пуста, создаём ещё одну строку.
          // Конец запроса от клиента, посылаем ответ...
          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();
            // переключение пинов - ВКЛ и ВЫКЛ
            if (header.indexOf("GET /12/on") >= 0) {
              Serial.println("Светодиод на пине 12 включен");
              output12State = "on";
              digitalWrite(output12, HIGH);
            } else if (header.indexOf("GET /12/off") >= 0) {
              Serial.println("Светодиод на пине 12 выключен");
              output12State = "off";
              digitalWrite(output12, LOW);
            } else if (header.indexOf("GET /14/on") >= 0) {
              Serial.println("Светодиод на пине 14 включен");
              output14State = "on";
              digitalWrite(output14, HIGH);
            } else if (header.indexOf("GET /14/off") >= 0) {
              Serial.println("Светодиод на пине 14 выключен");
              output14State = "off";
              digitalWrite(output14, 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 для стилизации ВКЛ/ВЫКЛ кнопок
            // Можете изменить фоновый цвет и шрифт
            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>");
            // Отображение текущего состояния пина 12 
            client.println("<p>GPIO 12 - State " + output12State + "</p>");
            // Если пин 12 ВЫКЛ, тогда выводим кнопку включения...     
            if (output12State=="off") {
              client.println("<p><a href=\"/12/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/12/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            // Отображение текущего состояния пина 14  
            client.println("<p>GPIO 14 - State " + output14State + "</p>");
            // Если пин 14 ВЫКЛ, тогда выводим кнопку включения...       
            if (output14State=="off") {
              client.println("<p><a href=\"/14/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/14/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");
            // Ответ HTTP заканчивается еще одной пустой строкой
            client.println();
            // Выходим из цикла while
            break;
          } else { // Если появилась новая строка, очистим текущую строку
            currentLine = "";
          }
        } else if (c != '\r') {  // Если у вас еще есть что-то кроме символа возврата курсора,
          currentLine += c;      // Добавляем его в конец текущей строки
        }
      }
    }
    // Очищаем переменную заголовка
    header = "";
    // Завершаем соединение
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Если вам не хочется подключать что-то к плате, или просто нет светодиодов или резисторов, можно сделать схему управления встроенным светодиодом. В этом случае ничего подключать к плате не нужно (кроме USB-кабеля для прошивки и питания, разумеется). Код представлен ниже.

#include &lt;WiFi.h> // Подключаем библиотеку Wi-Fi

// Введите данные вашей СУЩЕСТВУЮЩЕЙ WiFi-сети в кавычках
// ВАЖНО!! Ваш компьютер/телефон должен быть подключен к этой же сети!
const char* ssid = "";
const char* password = "";

// Установка номера порта сервера на 80
WiFiServer server(80);

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

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

// Назначаем выходную переменную контакту GPIO
const int c = LED_BUILTIN;

// Текущее время
unsigned long currentTime = millis();

// Предыдущее время
unsigned long previousTime = 0;

// Указываем время задержки в миллисекундах (пример: 2000 мс = 2 сек)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  
  // Устанавливаем пин LED_BUILTIN на ВЫХОД сигнала
  pinMode(LED_BUILTIN, OUTPUT);
  
  // Устанавливаем контакт в состояние LOW, то есть ВЫКЛ
  digitalWrite(LED_BUILTIN, LOW);
  
  // Соединяемся с Wi-Fi сетью с нашим SSID и паролем
  Serial.print("Подключаюсь к сети '");
  Serial.print(ssid);
  Serial.print("', пожалуйста, дождитесь появления IP-адреса ");
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  // Выводим IP адрес платы в SerialMonitor и запускаем веб-сервер
  Serial.println("");
  Serial.println("Подключение установлено.");
  Serial.println("IP-адрес этого сервера: ");
  Serial.println(WiFi.localIP());
  Serial.println("Перейдите по этому адресу в браузере для продолжения взаимодействия с сервером ESP32!");
  server.begin();
}
void loop(){
  WiFiClient client = server.available();   // Отслеживаем входящих клиентов
  
  if (client) {                             // Если подключается новый клиент...
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("Новый клиент!");        // ...выводим сообщение в SerialMonitor...
    String currentLine = "";                // ...создаём строковую переменную для данных от клиента...
    while (client.connected() &amp;&amp; currentTime - previousTime &lt;= timeoutTime) {  // Цикл, пока клиент подключён...
      currentTime = millis();
      if (client.available()) {             // ...если поступили данные от клиента...
        char c = client.read();             // ...читаем данные...
        Serial.write(c);                    // ...выводим в SerialMonitor...
        header += c;
        if (c == '\n') {                    // Если поступил символ \n...
          // Если текущая строка пуста, создаём ещё одну строку.
          // Конец запроса от клиента, посылаем ответ...
          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();
            // переключение пинов - ВКЛ и ВЫКЛ
			if (header.indexOf("GET /led/on") >= 0) {
              Serial.println("Светодиод включен.");
              ledState = "on";
              digitalWrite(ledPin, LOW);
            } else if (header.indexOf("GET /led/off") >= 0) {
              Serial.println("Светодиод выключен");
              ledState = "off";
              digitalWrite(ledPin, HIGH);
            }
			
            // Отображение HTML веб-страницы
            client.println("&lt;!DOCTYPE html>&lt;html>");
            client.println("&lt;head>&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("&lt;link rel=\"icon\" href=\"data:,\">");
            // CSS для стилизации ВКЛ/ВЫКЛ кнопок
            // Можете изменить фоновый цвет и шрифт
            client.println("&lt;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;}&lt;/style>&lt;/head>");
            // Заголовок веб-страницы
            client.println("&lt;body>&lt;h1>ESP32 Web Server&lt;/h1>");
            // Отображение текущего состояния встроенного светодиода  
            client.println("&lt;p>LED - State " + output14State + "&lt;/p>");
            // Если светодиод ВЫКЛ, тогда выводим кнопку включения...       
            if (outputLedState=="off") {
              client.println("&lt;p>&lt;a href=\"/led/on\">&lt;button class=\"button\">ON&lt;/button>&lt;/a>&lt;/p>");
            } else {
              client.println("&lt;p>&lt;a href=\"/led/off\">&lt;button class=\"button button2\">OFF&lt;/button>&lt;/a>&lt;/p>");
            }
            client.println("&lt;/body>&lt;/html>");
            // Ответ HTTP заканчивается еще одной пустой строкой
            client.println();
            // Выходим из цикла while
            break;
          } else { // Если появилась новая строка, очистим текущую строку
            currentLine = "";
          }
        } else if (c != '\r') {  // Если у вас еще есть что-то кроме символа возврата курсора,
          currentLine += c;      // Добавляем его в конец текущей строки
        }
      }
    }
    // Очищаем переменную заголовка
    header = "";
    // Завершаем соединение
    client.stop();
    Serial.println("Клиент отключён.");
    Serial.println("");
  }
}

Здесь логика включения светодиода немного другая. Встроенный светодиод уже подключен через резистор к плюсу, и нам нужно подать минус. Поэтому для включения этого светодиода нужно подать не HIGH, a LOW. Для выключения светодиода подадим HIGH.

Спасибо большое за внимание к статье! 🙂

5/5 - (1 голос)


Поделись!