Создание веб-сервера на ESP32: Полное руководство для начинающих

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

Создание веб-сервера на ESP32: Полное руководство для начинающих

Мы рассмотрим создание веб-сервера для управления выходами и отображения показаний датчиков, добавление аутентификации к веб-серверу, настройку ESP32 в качестве точки доступа и многое другое. Для максимальной простоты мы будем использовать встроенную библиотеку WebServer.h.

Новичок в ESP32? Рекомендуем сначала ознакомиться с этими вводными руководствами:

Обзор руководства

В этом руководстве мы рассмотрим следующие темы. Если вы новичок в веб-серверах ESP32 и хотите узнать больше об этой теме, рекомендуем следовать этим разделам по порядку.

  1. Введение в веб-серверы (Основные концепции)

  2. Пример веб-сервера ESP32 (Управление выходами)

  3. Добавление аутентификации к веб-серверу

  4. Веб-сервер ESP32 в режиме точки доступа (AP)

  5. Пример веб-сервера ESP32 (Отображение показаний датчиков)

Рекомендуемая книга: Build Web Servers with the ESP32 and ESP8266 (3rd edition)

Предварительные требования

Это руководство сосредоточено на программировании ESP32 с использованием ядра Arduino. Перед тем как продолжить, у вас должно быть установлено ядро ESP32 Arduino в вашей Arduino IDE. Следуйте следующему руководству для установки ESP32 в Arduino IDE, если вы этого ещё не сделали.


Введение в веб-серверы (Основные концепции)

Говоря простым языком, веб-сервер — это «компьютер», который доставляет веб-страницы. Он хранит файлы веб-сайта, включая HTML-документы и связанные ресурсы, такие как изображения, таблицы стилей CSS, шрифты и другие файлы. Когда пользователь отправляет запрос, сервер отправляет эти файлы в веб-браузер пользователя.

Когда вы открываете веб-страницу в браузере, вы фактически отправляете запрос на сервер, используя протокол передачи гипертекста (HTTP). Этот протокол управляет тем, как информация запрашивается и доставляется в Интернете. Сервер затем отвечает, отправляя запрошенную вами веб-страницу — также через HTTP.

Чтобы лучше понять, как всё это работает с вашими платами ESP32, давайте рассмотрим некоторые термины, которые вы, вероятно, слышали раньше, но, возможно, не полностью понимаете.

Запрос-Ответ

Запрос-ответ — это шаблон обмена сообщениями, в котором запрашивающая сторона (ваш браузер) отправляет сообщение-запрос системе-ответчику (ESP32 в качестве веб-сервера), которая получает и обрабатывает запрос и возвращает сообщение в ответ.

ESP32 Запрос-Ответ

В большинстве наших проектов ответное сообщение будет веб-страницей, которая отображает последние показания датчиков или предоставляет интерфейс для управления выходами.

Это простой, но мощный шаблон обмена сообщениями, особенно в архитектурах клиент-сервер.

Клиент-Сервер

Когда вы вводите URL в браузере, ваше устройство (клиент) отправляет запрос на сервер, используя протокол передачи гипертекста (HTTP). Сервер получает запрос и отвечает — также через HTTP — отправляя обратно веб-страницу. Этот обмен между клиентами и серверами происходит через компьютерную сеть.

ESP32 Клиент-Серверная коммуникация

Проще говоря, клиенты отправляют запросы серверам. Серверы обрабатывают запросы клиентов.

В этом руководстве мы будем рассматривать ESP32 как сервер, а вас — использующих браузер — как клиента. В наших проектах есть только один сервер (плата ESP32), но может быть несколько клиентов. Это могут быть различные веб-браузеры на разных устройствах, таких как компьютеры, смартфоны или планшеты, все подключённые к одной сети, или даже несколько вкладок браузера, открытых на одном устройстве.

IP-адрес

IP-адрес — это числовая метка, присвоенная каждому устройству, подключённому к компьютерной сети.

Это серия из четырёх значений, разделённых точками, где каждое значение варьируется от 0 до 255. Вот пример:

192.168.1.75

Дома ваши устройства подключены к частной сети через роутер (локальная сеть). Все устройства, подключённые к вашему роутеру, являются частью вашей локальной сети. Внутри этой сети каждое устройство имеет свой собственный IP-адрес.

Устройства, подключённые к одному роутеру, могут обращаться друг к другу через IP-адрес. Устройства вне вашей локальной сети не могут получить доступ к вашим локальным устройствам, используя их локальный IP-адрес.

Когда вы подключаете платы ESP32 к роутеру, они становятся частью вашей локальной сети. Таким образом, вашим платам ESP32 присваивается IP-адрес.

ESP32 Объяснение IP-адресов

В вашей локальной сети IP-адрес ESP32 (и других устройств) назначается роутером с использованием так называемого DHCP (Dynamic Host Configuration Protocol — протокол динамической настройки хоста). Вам не нужно беспокоиться о деталях. Вам просто нужно знать, что DHCP автоматически назначает IP-адрес и другие сетевые параметры каждому устройству в сети.

Роутер отслеживает каждое устройство в сети и сопоставляет IP-адрес каждому устройству каждый раз, когда оно присоединяется к сети. Два устройства в одной сети не могут иметь одинаковый IP-адрес.

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

Wi-Fi станция и Wi-Fi точка доступа

Плата ESP32 может работать как Wi-Fi станция, точка доступа или и то, и другое.

Wi-Fi станция

Когда ESP32 настроен для работы в качестве Wi-Fi станции, он подключается к существующей сети, например к вашему домашнему роутеру. В этой конфигурации роутер даёт ESP32 уникальный локальный IP-адрес. Затем вы можете связываться с ESP32 с других устройств (таких как ваш телефон или компьютер), подключённых к той же сети, просто используя этот IP-адрес.

ESP32 Wi-Fi станция

Поскольку роутер также подключён к интернету, мы можем запрашивать информацию из интернета, используя наши платы ESP32, например данные из API, публиковать данные на онлайн-платформах, использовать иконки и изображения из интернета на страницах нашего веб-сервера или подключать JavaScript-библиотеки.

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

Точка доступа

Когда ваш ESP32 настроен как точка доступа, другие устройства (такие как ваш смартфон, планшет или компьютер) могут подключаться к нему без необходимости роутера; ESP управляет своей собственной Wi-Fi сетью.

ESP32 Точка доступа

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

Коммуникация клиент-сервер

Существует несколько способов связи между клиентом и сервером: HTTP Polling, Server-Sent Events (SSE) и WebSocket. Мы сосредоточимся на HTTP Polling, который является самым простым протоколом для начала работы и лучшего понимания того, как работают веб-серверы.

У нас есть электронная книга, посвящённая веб-серверам, которая подробно рассматривает эти три протокола связи:

HTTP Polling

При HTTP polling клиент многократно запрашивает у сервера новую информацию. Когда сервер получает запрос, он отвечает запрошенными данными. Сервер отправляет информацию только тогда, когда клиент запрашивает её.

Коммуникация клиент-сервер HTTP Polling

Например, ваш браузер отправляет запрос к ESP32, и он отвечает тем, что вы запрограммировали, например веб-страницей, показывающей последние показания датчиков. Чтобы поддерживать веб-страницу в актуальном состоянии с помощью этого метода, браузер должен продолжать отправлять запросы через регулярные интервалы.

Веб-сервер ESP32

Давайте рассмотрим практический пример с ESP32, который действует как веб-сервер в локальной сети.

Обычно веб-сервер с ESP32 в локальной сети выглядит так: ESP32, работающий как веб-сервер, подключён через Wi-Fi к вашему роутеру. Ваш компьютер, смартфон или планшет также подключены к вашему роутеру через Wi-Fi или Ethernet-кабель. Таким образом, ESP32 и ваш браузер находятся в одной сети.

ESP32 действует как веб-сервер

Когда вы вводите IP-адрес ESP32 в браузере, вы отправляете HTTP-запрос к ESP32. Затем ESP32 отвечает ответом, который может содержать значение, показание, HTML-текст для отображения веб-страницы или любые другие данные.

ESP32 Веб-сервер Запрос-Ответ

Пример веб-сервера ESP32 (Управление выходами)

Основываясь на том, что мы узнали о веб-серверах и ESP32, как можно объединить всё это для создания IoT-проектов? Поскольку ESP32 имеет GPIO-пины, вы можете подключать датчики, исполнительные механизмы и другие устройства, а затем управлять ими или контролировать их через веб-интерфейс.

Вот пример веб-сервера, который мы создали для управления выходом. Следующая веб-страница появляется, когда вы вводите IP-адрес ESP32 в браузере.

ESP32 Веб-сервер — Пример управления выходами

Когда вы нажимаете кнопку ON, URL меняется на IP-адрес ESP, за которым следует /on. ESP получает запрос по этому новому URL, проверяет, какой URL запрашивается, и соответственно изменяет состояние светодиода.

  • Нажмите кнопку ON > запрос: /on > светодиод включается

Когда вы нажимаете кнопку OFF, новый запрос отправляется к ESP32 по URL /off. ESP снова проверяет, какой URL запрашивается, и выключает светодиод.

  • Нажмите кнопку OFF > запрос: /off > светодиод выключается

Та же концепция может быть применена для управления несколькими выходами.

Обзор проекта

Прежде чем переходить непосредственно к проекту, важно описать, что будет делать наш веб-сервер, чтобы потом было легче следовать и понимать шаги.

  • Веб-сервер, который вы создадите, управляет двумя светодиодами: один подключён к GPIO 26 ESP32, а другой — к GPIO 27.

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

  • Нажимая кнопки на веб-сервере, вы можете мгновенно изменять состояние каждого светодиода.

Это простой пример, который иллюстрирует, как создать веб-сервер, управляющий двумя светодиодами. Идея состоит в том, чтобы заменить эти светодиоды реле или любыми другими электронными компонентами, которыми вы хотите управлять.

Сборка схемы

Начните со сборки схемы. Подключите два светодиода к ESP32, как показано на следующей схеме — один светодиод подключён к GPIO 26, а другой к GPIO 27.

Вот список компонентов, необходимых для сборки схемы:

ESP32 подключён к двум светодиодам

Рекомендуемая литература: ESP32 Pinout Reference: Which GPIO pins should you use?

Создание веб-сервера

После сборки схемы следующий шаг — загрузка кода на ESP32. Скопируйте код ниже в Arduino IDE, но пока не загружайте его. Вам нужно внести некоторые изменения, чтобы он заработал.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  https://RandomNerdTutorials.com/esp32-web-server-beginners-guide/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

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

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;
String output26State = "off";
String output27State = "off";

// Create a web server object
WebServer server(80);

// Function to handle turning GPIO 26 on
void handleGPIO26On() {
  output26State = "on";
  digitalWrite(output26, HIGH);
  handleRoot();
}

// Function to handle turning GPIO 26 off
void handleGPIO26Off() {
  output26State = "off";
  digitalWrite(output26, LOW);
  handleRoot();
}

// Function to handle turning GPIO 27 on
void handleGPIO27On() {
  output27State = "on";
  digitalWrite(output27, HIGH);
  handleRoot();
}

// Function to handle turning GPIO 27 off
void handleGPIO27Off() {
  output27State = "off";
  digitalWrite(output27, LOW);
  handleRoot();
}

// Function to handle the root URL and show the current states
void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<link rel=\"icon\" href=\"data:,\">";
  html += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}";
  html += ".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}";
  html += ".button2 { background-color: #555555; }</style></head>";
  html += "<body><h1>ESP32 Web Server</h1>";

  // Display GPIO 26 controls
  html += "<p>GPIO 26 - State " + output26State + "</p>";
  if (output26State == "off") {
    html += "<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  // Display GPIO 27 controls
  html += "<p>GPIO 27 - State " + output27State + "</p>";
  if (output27State == "off") {
    html += "<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  html += "</body></html>";
  server.send(200, "text/html", html);
}

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
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Set up the web server to handle different routes
  server.on("/", handleRoot);
  server.on("/26/on", handleGPIO26On);
  server.on("/26/off", handleGPIO26Off);
  server.on("/27/on", handleGPIO27On);
  server.on("/27/off", handleGPIO27Off);

  // Start the web server
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  // Handle incoming client requests
  server.handleClient();
}

Посмотреть исходный код

Настройка сетевых учётных данных

Вам нужно изменить следующие строки, указав свои сетевые учётные данные: SSID и пароль.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = " REPLACE_WITH_YOUR_PASSWORD";

Получение IP-адреса ESP32

Теперь вы можете загрузить код, и он сразу заработает. Не забудьте проверить, что у вас выбрана правильная плата и COM-порт.

Откройте Serial Monitor на скорости 115200 бод.

ESP32 подключается к Wi-Fi и выводит свой IP-адрес в Serial Monitor. Скопируйте этот IP-адрес, потому что он нужен вам для доступа к веб-серверу ESP32.

ESP32 Веб-сервер — получение IP-адреса в Serial Monitor

Примечание: Если в Serial Monitor ничего не появляется, нажмите кнопку «EN» на ESP32 (кнопка ENABLE/RESET рядом с портом microUSB).

Доступ к веб-серверу

Откройте браузер, вставьте IP-адрес ESP32, и вы увидите следующую страницу.

ESP32 Базовый пример веб-сервера — управление выходами

Тестирование веб-сервера

Давайте протестируем веб-сервер. Нажмите кнопку, чтобы включить GPIO 26. В Serial Monitor вы можете увидеть, что ESP32 получает запрос по URL /26/on.

ESP32 Базовый пример веб-сервера — управление выходами объяснение

Когда ESP получает этот запрос, он включает светодиод, подключённый к GPIO 26, и его состояние также обновляется на веб-странице. Протестируйте кнопку для GPIO 27 и убедитесь, что она работает аналогично.

ESP32 Базовый веб-сервер — как это работает

Вы также можете получить доступ к веб-серверу на своём смартфоне, если он подключён к той же сети.

Как работает код

Теперь давайте подробнее рассмотрим код, чтобы понять, как он работает.

Первое, что вам нужно сделать — подключить необходимые библиотеки для подключения к Wi-Fi и настройки веб-сервера.

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

Как упоминалось ранее, вам нужно вставить свои ssid и password в следующие строки внутри двойных кавычек.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = " REPLACE_WITH_YOUR_PASSWORD";

Назначьте GPIO-пины каждому из ваших выходов. В этом примере мы используем GPIO 26 и GPIO 27, но вы можете использовать любые другие подходящие GPIO.

const int output26 = 26;
const int output27 = 27;

Затем создайте переменные для хранения состояний этих выходов. Вы можете добавить больше выходов, определив дополнительные переменные.

String output26State = "off";
String output27State = "off";

Создайте объект веб-сервера на порту 80 с именем server.

// Create a web server object
WebServer server(80);

setup()

Теперь перейдём к setup(). Сначала мы запускаем последовательную связь на скорости 115200 бод для отладки.

Serial.begin(115200);

Также определяем GPIO как OUTPUT и устанавливаем их в LOW.

// Initialize the output variables as outputs
pinMode(output26, OUTPUT);
pinMode(output27, OUTPUT);
// Set outputs to LOW
digitalWrite(output26, LOW);
digitalWrite(output27, LOW);

Следующие строки начинают Wi-Fi подключение с помощью WiFi.begin(ssid, password), ожидают успешного подключения и выводят IP-адрес ESP32 в Serial Monitor.

// Connect to Wi-Fi network
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

Прочитайте это руководство, чтобы узнать больше о Wi-Fi с ESP32: ESP32 Useful Wi-Fi Library Functions (Arduino IDE).

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

// Set up the web server to handle different routes
server.on("/", handleRoot);
server.on("/26/on", handleGPIO26On);
server.on("/26/off", handleGPIO26Off);
server.on("/27/on", handleGPIO27On);
server.on("/27/off", handleGPIO27Off);

// Start the web server
server.begin();
Serial.println("HTTP server started");

Например, когда вы делаете запрос по корневому URL / (вы просто вставляете IP-адрес ESP32 в веб-браузер), будет выполнена функция handleRoot(). Когда вы нажимаете кнопку GPIO 26 ON, будет сделан запрос по маршруту /26/on, и плата выполнит функцию handleGPIO26On(), и так далее… Эти функции определены в начале кода перед setup(). Мы рассмотрим их далее.

loop()

В loop() мы непрерывно слушаем входящие запросы клиентов. Это гарантирует, что ESP32 всегда готов отвечать на запросы из вашего браузера.

server.handleClient();

Обработка управления GPIO

На веб-странице вы видели, что есть четыре кнопки для управления GPIO:

  • Кнопка GPIO 26 ON > запрос: /26/on > функция: handleGPIO26On()

  • Кнопка GPIO 26 OFF > запрос: /26/off > функция: handleGPIO26Off()

  • Кнопка GPIO 27 ON > запрос: /27/on > функция: handleGPIO27On()

  • Кнопка GPIO 27 OFF > запрос: /27/off > функция: handleGPIO27Off()

Давайте рассмотрим кнопку GPIO 26 ON. Когда вы нажимаете эту кнопку, она делает запрос к ESP32 по URL /26/on. Когда это происходит, выполняется функция handleGPIO26On().

// Function to handle turning GPIO 26 on
void handleGPIO26On() {
  output26State = "on";
  digitalWrite(output26, HIGH);
  handleRoot();
}

Эта функция обновляет состояние GPIO в переменной output26State и включает GPIO. Наконец, она вызывает функцию handleRoot() для отображения веб-страницы с правильным состоянием GPIO.

Это работает аналогично для других кнопок и соответствующих маршрутов и функций. Обратите внимание, что все эти функции вызывают функцию handleRoot() для отображения веб-страницы с правильными состояниями GPIO.

// Function to handle turning GPIO 26 off
void handleGPIO26Off() {
  output26State = "off";
  digitalWrite(output26, LOW);
  handleRoot();
}

// Function to handle turning GPIO 27 on
void handleGPIO27On() {
  output27State = "on";
  digitalWrite(output27, HIGH);
  handleRoot();
}

// Function to handle turning GPIO 27 off
void handleGPIO27Off() {
  output27State = "off";
  digitalWrite(output27, LOW);
  handleRoot();
}

Отображение веб-страницы

Функция handleRoot() отвечает за генерацию веб-страницы. Она отправляет HTML и CSS, необходимые для построения страницы. HTML и CSS текст, необходимый для построения веб-страницы, сохраняется в переменной html.

// Function to handle the root URL and show the current states
void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<link rel=\"icon\" href=\"data:,\">";
  html += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}";
  html += ".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}";
  html += ".button2 { background-color: #555555; }</style></head>";
  html += "<body><h1>ESP32 Web Server</h1>";

  // Display GPIO 26 controls
  html += "<p>GPIO 26 - State " + output26State + "</p>";
  if (output26State == "off") {
    html += "<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  // Display GPIO 27 controls
  html += "<p>GPIO 27 - State " + output27State + "</p>";
  if (output27State == "off") {
    html += "<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  html += "</body></html>";
  server.send(200, "text/html", html);
}

Обратите внимание, что для генерации кнопок мы используем операторы if и else для отображения правильной кнопки и состояния в соответствии с текущим состоянием GPIO.

// Display GPIO 26 controls
html += "<p>GPIO 26 - State " + output26State + "</p>";
if (output26State == "off") {
    html += "<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>";
} else {
    html += "<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>";
}

// Display GPIO 27 controls
html += "<p>GPIO 27 - State " + output27State + "</p>";
if (output27State == "off") {
    html += "<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>";
} else {
    html += "<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>";
}

Наконец, веб-страница отправляется клиенту:

server.send(200, "text/html", HTML);

Добавление аутентификации к веб-серверу

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

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  https://RandomNerdTutorials.com/esp32-web-server-beginners-guide/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

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

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Username and password for web page access
const char* http_username = "admin";
const char* http_password = "admin";

// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;
String output26State = "off";
String output27State = "off";

// Create a web server object
WebServer server(80);

// Function to authenticate user
bool isAuthenticated() {
  if (!server.authenticate(http_username, http_password)) {
    server.requestAuthentication();
    return false;
  }
  return true;
}

// Function to handle turning GPIO 26 on
void handleGPIO26On() {
  if (!isAuthenticated()) return;
  output26State = "on";
  digitalWrite(output26, HIGH);
  handleRoot();
}

// Function to handle turning GPIO 26 off
void handleGPIO26Off() {
  if (!isAuthenticated()) return;
  output26State = "off";
  digitalWrite(output26, LOW);
  handleRoot();
}

// Function to handle turning GPIO 27 on
void handleGPIO27On() {
  if (!isAuthenticated()) return;
  output27State = "on";
  digitalWrite(output27, HIGH);
  handleRoot();
}

// Function to handle turning GPIO 27 off
void handleGPIO27Off() {
  if (!isAuthenticated()) return;
  output27State = "off";
  digitalWrite(output27, LOW);
  handleRoot();
}

// Function to handle the root URL and show the current states
void handleRoot() {
  if (!isAuthenticated()) return;

  String html = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<link rel=\"icon\" href=\"data:,\">";
  html += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}";
  html += ".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}";
  html += ".button2 { background-color: #555555; }</style></head>";
  html += "<body><h1>ESP32 Web Server</h1>";

  // Display GPIO 26 controls
  html += "<p>GPIO 26 - State " + output26State + "</p>";
  if (output26State == "off") {
    html += "<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  // Display GPIO 27 controls
  html += "<p>GPIO 27 - State " + output27State + "</p>";
  if (output27State == "off") {
    html += "<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  html += "</body></html>";
  server.send(200, "text/html", html);
}

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
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Set up the web server to handle different routes with authentication
  server.on("/", handleRoot);
  server.on("/26/on", handleGPIO26On);
  server.on("/26/off", handleGPIO26Off);
  server.on("/27/on", handleGPIO27On);
  server.on("/27/off", handleGPIO27Off);

  // Start the web server
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  // Handle incoming client requests
  server.handleClient();
}

Посмотреть исходный код

Добавление имени пользователя и пароля

Следующий код защищает ваш веб-сервер именем пользователя и паролем. По умолчанию имя пользователя — admin, и пароль — admin.

Вы можете добавить желаемое имя пользователя и пароль в следующих строках.

const char* http_username = "admin";
const char* http_password = "admin";

Обработка аутентификации и запросов

Для защиты вашей веб-страницы мы добавили простой механизм аутентификации. Перед доступом к любой части веб-сервера пользователь должен ввести правильное имя пользователя и пароль. Это обрабатывается функцией isAuthenticated().

bool isAuthenticated() {
  if (!server.authenticate(http_username, http_password)) {
    server.requestAuthentication();
    return false;
  }
  return true;
}

Эта функция проверяет, аутентифицирован ли пользователь. Если нет, она предлагает пользователю ввести учётные данные. Функция возвращает true, если пользователь аутентифицирован, или false в противном случае.

Перед отправкой любого ответа клиенту мы проверяем, аутентифицирован ли пользователь. Обратите внимание на использование следующей строки перед возвратом чего-либо клиенту.

if (!isAuthenticated()) return;

Например, в случае функции handleGPIO26On():

// Function to handle turning GPIO 26 on
void handleGPIO26On() {
  if (!isAuthenticated()) return;
  output26State = "on";
  digitalWrite(output26, HIGH);
  handleRoot();
}

Тестирование веб-сервера с аутентификацией

Теперь, когда вы попытаетесь получить доступ к IP-адресу вашего ESP32, вам потребуется ввести имя пользователя и пароль. Затем нажмите кнопку «Sign in»:

ESP32 Веб-сервер с аутентификацией

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

ESP32 Базовый пример веб-сервера — управление выходами

Если вы введёте неправильный пароль, окно входа появится снова.


Веб-сервер ESP32 в режиме точки доступа (AP)

Представьте, что вы хотите управлять ESP32 через веб-страницу на смартфоне, но ESP32 не имеет доступа к роутеру для подключения к интернету (то есть вы не можете настроить его как Wi-Fi станцию, как в предыдущих примерах). В этом случае вы можете настроить ESP32 как точку доступа.

ESP32 Веб-сервер Точка доступа AP

Когда ваш ESP32 настроен как точка доступа, другие устройства (такие как ваш смартфон, планшет или компьютер) могут подключаться к нему без необходимости роутера. Давайте посмотрим, как это реализовать.

Настройка ESP32 как точки доступа

Чтобы настроить ESP32 как точку доступа, установите режим Wi-Fi как точку доступа следующим образом:

WiFi.mode(WIFI_AP);

А затем используйте метод softAP() следующим образом:

WiFi.softAP(ssid, password);

ssid — это имя, которое вы хотите дать точке доступа ESP32, а параметр password — это пароль для точки доступа. Если вы не хотите устанавливать пароль, установите его в NULL.

Есть также другие необязательные параметры, которые вы можете передать методу softAP(). Вот все параметры:

WiFi.softAP(const char* ssid, const char* password, int channel, int ssid_hidden, int max_connection);
  • ssid: имя для точки доступа — максимум 63 символа;

  • password: минимум 8 символов; установите NULL, если хотите, чтобы точка доступа была открытой;

  • channel: номер Wi-Fi канала (1-13)

  • ssid_hidden: (0 = транслировать SSID, 1 = скрыть SSID)

  • max_connection: максимальное количество одновременно подключённых клиентов (1-4)

Следующий код создаёт тот же веб-сервер, что и ранее, но в режиме точки доступа.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  https://RandomNerdTutorials.com/esp32-web-server-beginners-guide/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

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

// Replace with SSID and PASSWORD for the ESP32 ACCESS POINT
// (for testing you can leave the default)
const char* ssid = "ESP32_ACCESS_POINT";
const char* password = "pass123456";

// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;
String output26State = "off";
String output27State = "off";

// Create a web server object
WebServer server(80);

// Function to handle turning GPIO 26 on
void handleGPIO26On() {
  output26State = "on";
  digitalWrite(output26, HIGH);
  handleRoot();
}

// Function to handle turning GPIO 26 off
void handleGPIO26Off() {
  output26State = "off";
  digitalWrite(output26, LOW);
  handleRoot();
}

// Function to handle turning GPIO 27 on
void handleGPIO27On() {
  output27State = "on";
  digitalWrite(output27, HIGH);
  handleRoot();
}

// Function to handle turning GPIO 27 off
void handleGPIO27Off() {
  output27State = "off";
  digitalWrite(output27, LOW);
  handleRoot();
}

// Function to handle the root URL and show the current states
void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<link rel=\"icon\" href=\"data:,\">";
  html += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}";
  html += ".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}";
  html += ".button2 { background-color: #555555; }</style></head>";
  html += "<body><h1>ESP32 Web Server</h1>";

  // Display GPIO 26 controls
  html += "<p>GPIO 26 - State " + output26State + "</p>";
  if (output26State == "off") {
    html += "<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  // Display GPIO 27 controls
  html += "<p>GPIO 27 - State " + output27State + "</p>";
  if (output27State == "off") {
    html += "<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>";
  } else {
    html += "<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>";
  }

  html += "</body></html>";
  server.send(200, "text/html", html);
}

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

  // Set the ESP32 as access point
  Serial.print("Setting as access point ");
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, password);

  Serial.println("");
  Serial.println("ESP32 Wi-Fi Access Point ready!");
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  // Set up the web server to handle different routes
  server.on("/", handleRoot);
  server.on("/26/on", handleGPIO26On);
  server.on("/26/off", handleGPIO26Off);
  server.on("/27/on", handleGPIO27On);
  server.on("/27/off", handleGPIO27Off);

  // Start the web server
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  // Handle incoming client requests
  server.handleClient();
}

Посмотреть исходный код

Вы можете загрузить предыдущий код на плату.

ESP32 настроит свою собственную Wi-Fi сеть. Теперь, чтобы получить доступ к веб-серверу, вам нужно подключить компьютер или смартфон к сети ESP32.

Настройка ESP32 как точки доступа

На смартфоне перейдите в настройки Wi-Fi и подключитесь к ESP32_ACCESS_POINT. Пароль — pass123456 (если вы оставили значения по умолчанию). Затем откройте браузер и введите IP-адрес ESP32: 192.168.4.1.

Подключение к точке доступа ESP32 Ввод пароля для точки доступа ESP32 ESP32 Веб-сервер в режиме точки доступа

Теперь вы должны иметь возможность управлять ESP32 без необходимости роутера. Вы используете Wi-Fi сеть ESP32.


Пример веб-сервера ESP32 (Отображение показаний датчиков)

Для завершения нашего руководства по веб-серверам ESP32 мы создадим простой пример веб-сервера для отображения показаний датчиков. Мы будем отображать показания температуры, влажности и давления с датчика BME280, но вы можете использовать любой другой датчик.

Рекомендуемая литература: ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity).

BME280 Датчик температуры, влажности и давления

У нас есть руководства для более чем 30 датчиков и модулей с ESP32, ознакомьтесь с ними здесь: ESP32: 30+ Free Guides for Sensors and Modules.

Обзор проекта

В этом примере мы будем отображать показания датчика BME280 в таблице. Веб-страница для отображения показаний будет выглядеть следующим образом:

ESP32 Веб-сервер — отображение показаний датчика BME280

Значения температуры, влажности, давления и высоты будут объединены с HTML-строкой. Когда ESP32 получает запрос по корневому URL, мы отправляем HTML-строку, объединённую с текущими показаниями датчиков.

Чтобы получить новые показания, вам нужно обновить веб-страницу для отправки нового запроса.

Создание таблицы в HTML

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

Для создания таблицы в HTML используются теги <table> и </table>.

Для создания строки используются теги <tr> и </tr>. Заголовок таблицы определяется с помощью тегов <th> и </th>, а каждая ячейка таблицы определяется с помощью тегов <td> и </td>.

Для создания таблицы наших показаний используется следующий HTML-текст:

<table>
  <tr>
    <th>MEASUREMENT</th>
    <th>VALUE</th>
  </tr>
  <tr>
    <td>Temp. Celsius</td>
    <td>--- *C</td>
  </tr>
  <tr>
    <td>Temp. Fahrenheit</td>
    <td>--- *F</td>
  </tr>
  <tr>
    <td>Pressure</td>
    <td>--- hPa</td>
  </tr>
  <tr>
    <td>Approx. Altitude</td>
    <td>--- meters</td></tr>
  <tr>
    <td>Humidity</td>
    <td>--- %</td>
  </tr>
</table>

Мы создаём заголовок таблицы с ячейкой MEASUREMENT и другой с именем VALUE.

Затем мы создаём шесть строк для отображения каждого из показаний, используя теги <tr> и </tr>. Внутри каждой строки мы создаём две ячейки, используя теги <td> и </td>, одну с названием измерения и другую для хранения значения измерения. Три тире «—» затем должны быть заменены фактическими измерениями с датчика BME280.

Вы можете сохранить этот текст как table.html, перетащить файл в браузер и увидеть результат. Предыдущий HTML-текст создаёт следующую таблицу.

ESP32 Базовая HTML-таблица для показаний датчиков

Таблица не имеет применённых стилей. Вы можете использовать CSS для стилизации таблицы. Вы можете прочитать руководство по следующей ссылке, чтобы узнать, как стилизовать таблицу: CSS Styling Tables.

Сборка схемы

Подключите датчик к пинам SDA и SCL ESP32, как показано на следующей схеме. Для платы ESP32 Devkit по умолчанию используются пины GPIO 21 (SDA) и GPIO 22 (SCL). Проверьте пины по умолчанию для используемой вами платы.

Вот список компонентов, необходимых для сборки этой схемы:

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

Отображение показаний датчика BME280 на веб-сервере — Код

Теперь, когда вы знаете, как создать таблицу для отображения результатов и основы создания веб-сервера, пришло время для кода. Если вы следовали предыдущим примерам, вам будут знакомы большинство строк кода.

Скопируйте следующий код в Arduino IDE. Перед загрузкой вам нужно вставить свои SSID и пароль.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  https://RandomNerdTutorials.com/esp32-web-server-beginners-guide/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include <WebServer.h>

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme; // I2C

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create an instance of the WebServer on port 80
WebServer server(80);

void handleRoot() {
  String html = "<!DOCTYPE html><html>";
  html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<link rel=\"icon\" href=\"data:,\">";
  html += "<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial;}";
  html += "table { border-collapse: collapse; width:60%; margin-left:auto; margin-right:auto; }";
  html += "th { padding: 10px; background-color: #0043af; color: white; }";
  html += "tr { border: 1px solid #ddd; padding: 10px; }";
  html += "tr:hover { background-color: #bcbcbc; }";
  html += "td { border: none; padding: 8px; }";
  html += ".sensor { color:white; font-weight: bold; background-color: #bcbcbc; padding: 1px; }</style></head>";
  html += "<body><h1>ESP32 with BME280</h1>";
  html += "<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>";
  html += "<tr><td>Temp. Celsius</td><td><span class=\"sensor\">";
  html += String(bme.readTemperature());
  html += " *C</span></td></tr>";
  html += "<tr><td>Temp. Fahrenheit</td><td><span class=\"sensor\">";
  html += String(1.8 * bme.readTemperature() + 32);
  html += " *F</span></td></tr>";
  html += "<tr><td>Pressure</td><td><span class=\"sensor\">";
  html += String(bme.readPressure() / 100.0F);
  html += " hPa</span></td></tr>";
  html += "<tr><td>Approx. Altitude</td><td><span class=\"sensor\">";
  html += String(bme.readAltitude(SEALEVELPRESSURE_HPA));
  html += " m</span></td></tr>";
  html += "<tr><td>Humidity</td><td><span class=\"sensor\">";
  html += String(bme.readHumidity());
  html += " %</span></td></tr></table></body></html>";

  // Send the response to the client
  server.send(200, "text/html", html);
}

void setup() {
  Serial.begin(115200);

  // Initialize the BME280 sensor
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Set up the routes
  server.on("/", handleRoot);

  // Start the server
  server.begin();
}

void loop() {
  server.handleClient();
}

Посмотреть исходный код

Измените следующие строки, чтобы указать свои SSID и пароль.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Затем проверьте, что у вас выбрана правильная плата и COM-порт, и загрузите код на ESP32. После загрузки откройте Serial Monitor на скорости 115200 бод и скопируйте IP-адрес ESP32.

Получение IP-адреса ESP32 в Serial Monitor

Откройте браузер, вставьте IP-адрес, и вы должны увидеть последние показания датчиков. Чтобы обновить показания, просто обновите веб-страницу.

ESP32 Отображение показаний датчика BME280 на веб-сервере

Как работает код

Этот скетч очень похож на предыдущие скетчи в этом руководстве. Вам должна быть знакома большая часть кода. Сначала вы подключаете библиотеки WiFi и WebServer для создания веб-сервера и необходимые библиотеки для чтения с датчика BME280.

#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include <WebServer.h>

Следующая строка определяет переменную для сохранения давления на уровне моря. Для более точной оценки высоты замените значение текущим давлением на уровне моря в вашем местоположении.

#define SEALEVELPRESSURE_HPA (1013.25)

В следующей строке вы создаёте объект Adafruit_BME280 с именем bme, который по умолчанию устанавливает связь с датчиком через I2C.

Adafruit_BME280 bme; // I2C

Узнайте больше об I2C с ESP32: ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals (Arduino IDE).

Как упоминалось ранее, вам нужно вставить свои ssid и password в следующие строки внутри двойных кавычек.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = " REPLACE_WITH_YOUR_PASSWORD";

Затем инициализируйте сервер на порту 80.

WebServer server(80);

setup()

В setup() мы запускаем последовательную связь на скорости 115200 бод для отладки.

Serial.begin(115200);

Вы проверяете, что датчик BME280 был успешно инициализирован.

if (!bme.begin(0x76)) {
  Serial.println("Could not find a valid BME280 sensor, check wiring!");
  while (1);
}

Следующие строки начинают Wi-Fi подключение с помощью WiFi.begin(ssid, password), ожидают успешного подключения и выводят IP-адрес ESP в Serial Monitor.

// Connect to Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

Наконец, мы настраиваем веб-сервер и определяем маршруты, которые он должен обрабатывать. Этот веб-сервер будет обрабатывать только корневой URL для отображения последних показаний датчиков. При доступе к корневому URL будет вызвана функция handleRoot().

// Set up the routes
server.on("/", handleRoot);
// Start the server
server.begin();

Отображение веб-страницы

В этом примере функция handleRoot() отвечает за генерацию веб-страницы. Она отправляет HTML и CSS, необходимые для построения страницы. HTML и CSS текст, необходимый для построения веб-страницы, сохраняется в переменной html. Мы объединяем текущие показания датчиков с переменной html. Таким образом, HTML, отправленный в веб-браузер, будет содержать последние показания датчиков.

void handleRoot() {
  String html = "<!DOCTYPE html><html>";
  html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<link rel=\"icon\" href=\"data:,\">";
  html += "<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial;}";
  html += "table { border-collapse: collapse; width:50%; margin-left:auto; margin-right:auto; }";
  html += "th { padding: 10px; background-color: #0043af; color: white; }";
  html += "tr { border: 1px solid #ddd; padding: 12px; }";
  html += "tr:hover { background-color: #bcbcbc; }";
  html += "td { border: none; padding: 10px; }";
  html += ".sensor { color:white; font-weight: bold; background-color: #bcbcbc; padding: 1px; }</style></head>";
  html += "<body><h1>ESP32 with BME280</h1>";
  html += "<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>";
  html += "<tr><td>Temp. Celsius</td><td><span class=\"sensor\">";
  html += String(bme.readTemperature());
  html += " *C</span></td></tr>";
  html += "<tr><td>Temp. Fahrenheit</td><td><span class=\"sensor\">";
  html += String(1.8 * bme.readTemperature() + 32);
  html += " *F</span></td></tr>";
  html += "<tr><td>Pressure</td><td><span class=\"sensor\">";
  html += String(bme.readPressure() / 100.0F);
  html += " hPa</span></td></tr>";
  html += "<tr><td>Approx. Altitude</td><td><span class=\"sensor\">";
  html += String(bme.readAltitude(SEALEVELPRESSURE_HPA));
  html += " m</span></td></tr>";
  html += "<tr><td>Humidity</td><td><span class=\"sensor\">";
  html += String(bme.readHumidity());
  html += " %</span></td></tr></table></body></html>";

  // Send the response to the client
  server.send(200, "text/html", html);
}

Для отображения показаний датчиков в таблице нам просто нужно отправить их между соответствующими тегами <td> и </td>. Например, для отображения температуры:

html += "<tr><td>Temp. Celsius</td><td><span class=\"sensor\">";
html += String(bme.readTemperature());
html += " *C</span></td></tr>";

Примечание: тег <span> полезен для стилизации определённой части текста. В данном случае мы используем тег <span> для включения показания датчика в класс «sensor». Это полезно для стилизации этой конкретной части текста с помощью CSS.

По умолчанию таблица отображает показания температуры как в градусах Цельсия, так и в градусах Фаренгейта.

ESP32 Отображение показаний датчика BME280 на веб-сервере

Чтобы получить последние показания датчиков, просто обновите веб-страницу. Для автоматического обновления показаний вам нужно изучить другие протоколы связи, такие как server-sent events или websockets.

Для более глубокого изучения создания веб-серверов ESP32 рекомендуем ознакомиться с нашей электронной книгой: Build Web Servers with ESP32 and ESP8266 eBook (3rd Edition).

Заключение

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

Если вы новичок в ESP32 и веб-серверах, рекомендуем следующие электронные книги:

Вот другие руководства, которые могут вам понравиться:


Источник: Random Nerd Tutorials — Rui Santos & Sara Santos https://randomnerdtutorials.com/esp32-web-server-beginners-guide/