В этом уроке мы покажем вам, как создать веб-сервер, который обслуживает файлы HTML и CSS, хранящиеся в файловой системе ESP32. Вместо того чтобы писать текст HTML и CSS в скетче Arduino, мы создадим отдельные файлы HTML и CSS.
Для демонстрации веб-сервер, который мы создадим, будет управлять выводом ESP32, но его можно легко адаптировать для других целей, таких как отображение показаний датчиков.
Рекомендуемое чтение: Веб-сервер ESP8266 с использованием SPIFFS
Плагин загрузчика файловой системы ESP32
Чтобы следовать этому уроку, у вас должен быть установлен плагин загрузчика файловой системы ESP32 в вашей Arduino IDE. Если его нет, следуйте следующему уроку, чтобы сначала установить его:
- Установите ESP32 Filesystem Uploader на Arduino IDE
Обзор проекта
Прежде чем переходить непосредственно к проекту, важно определить, что будет делать наш веб-сервер, чтобы вам было легче его понять.
- Веб-сервер, который вы создадите, управляет светодиодом, подключенным к GPIO 2 ESP32. Это встроенный светодиод ESP32. Вы можете управлять любым другим GPIO;
- На веб-странице сервера отображаются две кнопки: ВКЛ и ВЫКЛ — для включения и выключения GPIO 2;
- На веб-странице сервера также отображается текущее состояние GPIO.
Следующая схема показывает упрощенный диаграмму, чтобы продемонстрировать, как все работает.
- ESP32 запускает код веб-сервера на основе библиотеки ESPAsyncWebServer;
- Файлы HTML и CSS хранятся на SPIFFS (Serial Peripheral Interface Flash File System) ESP32;
- Когда вы делаете запрос на определенный URL, используя ваш браузер, ESP32 отвечает запрошенными файлами;
- Когда вы нажимаете кнопку ВКЛ, вы перенаправляетесь на корневой URL, за которым следует /on, и светодиод включается;
- Когда вы нажимаете кнопку ВЫКЛ, вы перенаправляетесь на корневой URL, за которым следует /off, и светодиод выключается;
- На веб-странице есть заполнитель для состояния GPIO. Заполнитель состояния GPIO записывается непосредственно в файл HTML между знаками %, например %STATE%.
Установка библиотек
В большинстве наших проектов мы создавали файлы HTML и CSS для веб-сервера в виде строки непосредственно в скетче Arduino. С помощью SPIFFS вы можете записать HTML и CSS в отдельные файлы и сохранить их в файловой системе ESP32.
Один из самых простых способов создания веб-сервера, использующего файлы из файловой системы, заключается в использовании библиотеки ESPAsyncWebServer. Библиотека ESPAsyncWebServer хорошо задокументирована на своей странице GitHub. Для получения дополнительной информации о библиотеке перейдите по следующей ссылке:
Установка библиотеки ESPAsyncWebServer
Следуйте следующим шагам для установки библиотеки ESPAsyncWebServer:
- Скачайте библиотеку ESPAsyncWebServer. В вашей папке "Загрузки" должен появиться файл .zip.
- Разархивируйте папку .zip, и вы получите папку ESPAsyncWebServer-master.
- Переименуйте папку из ESPAsyncWebServer-master в ESPAsyncWebServer.
- Переместите папку ESPAsyncWebServer в папку библиотек вашей установки Arduino IDE.
Установка библиотеки Async TCP для ESP32
Библиотека ESPAsyncWebServer требует библиотеку AsyncTCP для работы. Следуйте следующим шагам для установки этой библиотеки:
- Скачайте библиотеку AsyncTCP. В вашей папке "Загрузки" должен появиться файл .zip.
- Разархивируйте папку .zip, и вы получите папку AsyncTCP-master.
- Переименуйте папку из AsyncTCP-master в AsyncTCP.
- Переместите папку AsyncTCP в папку библиотек вашей установки Arduino IDE.
Наконец, перезапустите вашу Arduino IDE.
Организация файлов
Для создания веб-сервера вам понадобятся три разных файла: скетч Arduino, файл HTML и файл CSS. Файлы HTML и CSS должны быть сохранены внутри папки data в папке скетча Arduino, как показано ниже:
Создание файла HTML
HTML для этого проекта очень простой. Нам нужно создать заголовок для веб-страницы, абзац для отображения состояния GPIO и две кнопки.
Создайте файл index.html со следующим содержимым:
<!DOCTYPE html>
<html>
<head>
<title>ESP32 Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>ESP32 Web Server</h1>
<p>GPIO state: <strong>%STATE%</strong></p>
<p><a href="/on"><button class="button">ON</button></a></p>
<p><a href="/off"><button class="button button2">OFF</button></a></p>
</body>
</html>
Поскольку мы используем CSS и HTML в разных файлах, нам нужно ссылаться на файл CSS в тексте HTML. Следующая строка должна быть добавлена между тегами
<link rel="stylesheet" type="text/css" href="style.css">
Тег <link>
сообщает файлу HTML, что вы используете внешний стиль для форматирования внешнего вида страницы. Атрибут rel
указывает на природу внешнего файла, в данном случае это файл стилей — файл CSS, который будет использоваться для изменения внешнего вида страницы.
Атрибут type
установлен на "text/css", чтобы указать, что вы используете файл CSS для стилей. Атрибут href
указывает местоположение файла; поскольку файлы CSS и HTML будут находиться в одной папке, вам нужно просто указать имя файла: style.css
.
В следующей строке мы пишем первый заголовок нашей веб-страницы. В данном случае у нас есть "ESP32 Web Server". Вы можете изменить заголовок на любой текст по вашему желанию:
<h1>ESP32 Web Server</h1>
Затем мы добавляем абзац с текстом "GPIO state: " за которым следует состояние GPIO. Поскольку состояние GPIO меняется в зависимости от состояния GPIO, мы можем добавить заполнитель, который затем будет заменен на любое значение, которое мы установим в скетче Arduino.
Чтобы добавить заполнитель, мы используем знаки %. Чтобы создать заполнитель для состояния, мы можем использовать %STATE%
, например:
<p>GPIO state: <strong>%STATE%</strong></p>
Присвоение значения заполнителю STATE
выполняется в скетче Arduino.
Затем мы создаем кнопки "ВКЛ" и "ВЫКЛ". Когда вы нажимаете кнопку "ВКЛ", мы перенаправляем веб-страницу на корневой URL, за которым следует /on
. Когда вы нажимаете кнопку "ВЫКЛ", вы перенаправляетесь на URL /off
.
<p><a href="/on"><button class="button">ON</button></a></p>
<p><a href="/off"><button class="button button2">OFF</button></a></p>
Создание файла CSS
Создайте файл style.css
со следующим содержимым:
html {
font-family: Helvetica;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h1{
color: #0F3376;
padding: 2vh;
}
p{
font-size: 1.5rem;
}
.button {
display: inline-block;
background-color: #008CBA;
border: none;
border-radius: 4px;
color: white;
padding: 16px 40px;
text-decoration: none;
font-size: 30px;
margin: 2px;
cursor: pointer;
}
.button2 {
background-color: #f44336;
}
Это просто базовый файл CSS для установки размера шрифта, стиля и цвета кнопок и выравнивания страницы. Мы не будем объяснять, как работает CSS. Хорошее место для изучения CSS — это веб-сайт W3Schools.
Скетч Arduino
Скопируйте следующий код в Arduino IDE:
// Импорт необходимых библиотек
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
// Замените на ваши сетевые данные
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Установите GPIO для светодиода
const int ledPin = 2;
// Сохраняет состояние светодиода
String ledState;
// Создайте объект AsyncWebServer на порту 80
AsyncWebServer server(80);
// Заменяет заполнитель значением состояния светодиода
String processor(const String& var){
Serial.println(var);
if(var == "STATE"){
if(digitalRead(ledPin)){
ledState = "ON";
}else{
ledState = "OFF";
}
Serial.print(ledState);
return ledState;
}
return String();
}
void setup(){
// Последовательный порт для целей отладки
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
// Инициализация SPIFFS
if(!SPIFFS.begin(true)){
Serial.println("Произошла ошибка при монтировании SPIFFS");
return;
}
// Подключение к Wi-Fi
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.println("Подключение к WiFi..");
}
// Печать локального IP-адреса ESP32
Serial.println(WiFi.localIP());
// Маршрут для корня / веб-страницы
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Маршрут для загрузки файла style.css
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
// Маршрут для установки GPIO в HIGH
server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(ledPin, HIGH);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Маршрут для установки GPIO в LOW
server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(ledPin, LOW);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Запуск сервера
server.begin();
}
void loop(){
}
Как работает код
Во-первых, импортируйте необходимые библиотеки:
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
Введите ваши сетевые данные в следующие переменные:
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Далее создайте переменную, относящуюся к GPIO 2, называемую ledPin
, и строковую переменную для хранения состояния светодиода: ledState
.
const int ledPin = 2;
String ledState;
Создайте объект AsynWebServer, называемый server
, который будет слушать на порту 80.
AsyncWebServer server(80);
Функция processor()
Функция processor()
предназначена для того, чтобы присвоить значение заполнителю, созданному в файле HTML. Она принимает в качестве аргумента заполнитель и должна возвращать строку, которая заменит этот заполнитель. Функция processor()
должна иметь следующую структуру:
String processor(const String& var) {
Serial.println(var);
if (var == "STATE") {
if (digitalRead(ledPin)) {
ledState = "ON";
} else {
ledState = "OFF";
}
Serial.print(ledState);
return ledState;
}
return String();
}
Эта функция сначала проверяет, является ли заполнитель тем, который мы создали в файле HTML.
if (var == "STATE") {
Если да, то в зависимости от состояния светодиода мы устанавливаем переменную ledState
на "ON" или "OFF".
if (digitalRead(ledPin)) {
ledState = "ON";
} else {
ledState = "OFF";
}
Наконец, мы возвращаем переменную ledState
. Это заменяет заполнитель строковым значением ledState
.
return ledState;
Функция setup()
В функции setup()
начните с инициализации Серийного монитора и настройки GPIO как выхода.
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
Инициализируйте SPIFFS:
if(!SPIFFS.begin(true)){
Serial.println("Произошла ошибка при монтировании SPIFFS");
return;
}
Подключение к Wi-Fi
Подключитесь к Wi-Fi и выведите IP-адрес ESP32:
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Подключение к WiFi..");
}
Serial.println(WiFi.localIP());
Асинхронный веб-сервер
Библиотека ESPAsyncWebServer позволяет нам настраивать маршруты, по которым сервер будет принимать входящие HTTP-запросы, и выполнять функции при получении запроса на этом маршруте. Для этого используйте метод on()
на объекте сервера следующим образом:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", String(), false, processor);
});
Когда сервер получает запрос на корневом URL-адресе "/", он отправляет файл index.html
клиенту. Последним аргументом функции send()
является processor
, чтобы мы могли заменить заполнитель на нужное нам значение — в данном случае состояние светодиода.
Поскольку мы ссылались на файл CSS в файле HTML, клиент сделает запрос на файл CSS. Когда это произойдет, файл CSS будет отправлен клиенту:
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SPIFFS, "/style.css", "text/css");
});
Наконец, вам нужно определить, что произойдет на маршрутах /on
и /off
. Когда на этих маршрутах делается запрос, светодиод либо включается, либо выключается, и ESP32 обслуживает файл HTML.
server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request) {
digitalWrite(ledPin, HIGH);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request) {
digitalWrite(ledPin, LOW);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
В конце концов, используйте метод begin()
на объекте сервера, чтобы сервер начал принимать входящие запросы.
server.begin();
Поскольку это асинхронный веб-сервер, вы можете определить все запросы в функции setup()
. Затем вы можете добавить другой код в функцию loop()
, пока сервер принимает входящие запросы.
Загрузка кода и файлов
Сохраните код как Async_ESP32_Web_Server
или скачайте все файлы проекта. Перейдите в Скетч> Показать папку скетча
, и создайте папку под названием data
. Внутри этой папки сохраните файлы HTML и CSS.
Затем загрузите код на вашу плату ESP32. Убедитесь, что выбрана правильная плата и COM-порт. Также убедитесь, что вы добавили данные вашей сети в код.
После загрузки кода вам нужно загрузить файлы. Перейдите в Инструменты> ESP32 Data Sketch Upload
и дождитесь загрузки файлов.
Когда все успешно загружено, откройте Серийный монитор на скорости 115200. Нажмите кнопку "ENABLE" на плате ESP32, и должен быть выведен IP-адрес ESP32.
Демонстрация
Откройте ваш браузер и введите IP-адрес ESP32. Нажмите кнопки "ON" и "OFF", чтобы управлять встроенным светодиодом ESP32. Также проверьте, что состояние GPIO обновляется корректно.
Заключение
Использование SPI Flash File System (SPIFFS) особенно полезно для хранения файлов HTML и CSS, чтобы обслуживать их клиенту, вместо того чтобы писать весь код внутри скетча Arduino.