ESP32:Примеры/Создание веб-сервера на базе ESP32 при помощи файлов из файловой системы (SPIFFS)
Создание веб-сервера на базе ESP32 при помощи файлов из файловой системы (SPIFFS)
В руководстве «SPIFFS платы ESP32 (файловая система памяти SPI Flash)» мы рассказывали, как с помощью файловой системы SPIFFS загружать и манипулировать файлами, хранящимися на flash-памяти ESP32. В этом руководстве мы покажем, как создать веб-сервер, использующий HTML- и CSS-файлы, хранящиеся в файловой системе.
Веб-сервер, который мы сделаем в этом руководстве, будет похож на веб-сервер, который мы сделали в руководстве «Веб-сервер на базе ESP32: управление выходными контактами».
Чтобы продолжить дальше, в IDE Arduino должен быть установлен плагин загрузчика SPIFFS. О том, как это сделать, читайте в руководстве «SPIFFS платы ESP32 (файловая система памяти SPI Flash)».
Обзор проекта
Для начала давайте в общих чертах обрисуем, что будет делать наш веб-сервер – чтобы нам было проще над ним работать.
- Веб-сервер будет управлять светодиодом, подключенным к контакту GPIO2 на ESP32 (это встроенный светодиод ESP32). Но вы можете задать для этого любой другой GPIO-контакт;
- На странице веб-сервера будет показано две кнопки: «ON» и «OFF» – для включения и выключения контакта GPIO2;
- Также страница веб-сервера будет показывать текущее состояние контакта GPIO2;
- На изображении ниже схематически изображено, как все это будет работать:
- Для создания веб-сервера будет использоваться библиотека «ESPAsyncWebServer»;
- HTML- и CSS-файлы будут храниться в файловой системе ESP32 (SPIFFS);
- Когда вы при помощи браузера будете делать запрос на определенный URL, ESP32 будет отвечать на это отправкой запрошенных файлов;
- Когда вы будете кликать на кнопку «ON», вас перенаправит к корневому URL, в конце которого будет стоять «/on», а также заставит светодиод включиться;
- Когда вы будете кликать на кнопку «OFF», вас перенаправит к корневому URL, в конце которого будет стоять «/off», а также заставит светодиод выключиться;
- На веб-странице есть поле для текущего состояния GPIO-контакта. В HTML-файле оно задается между двумя символами «%» (например, «%STATE%»).
Устанавливаем библиотеки
До сих пор мы писали HTML- и CSS-код для веб-сервера напрямую в скетч IDE Arduino. Но при помощи SPIFFS мы можем записывать HTML- и CSS-данные в отдельные файлы и сохранять их в файловую систему ESP32.
Один из самых простых способов создания веб-сервера с использованием файлов из файловой системы – при помощи библиотеки «ESPAsyncWebServer» (исчерпывающую документацию о ней можно найти на ее GitHub-странице).
Устанавливаем библиотеку «ESPAsyncWebServer»
- Кликните тут, чтобы скачать ZIP-архив библиотеки. Он должен скачаться в папку «Загрузки» на вашем ПК;
- Распакуйте этот архив. У вас должна получиться папка «ESPAsyncWebServer-master»;
- Переименуйте ее на «ESPAsyncWebServer»;
- Переместите папку «ESPAsyncWebServer» в папку «libraries» (туда устанавливаются библиотеки для IDE Arduino), которая находится внутри папки, куда установлена IDE Arduino;
Устанавливаем библиотеку «AsyncTCP»
Библиотеке «ESPAsyncWebServer» необходима для работы библиотека «AsyncTCP».
- Кликните тут, чтобы скачать ZIP-архив библиотеки. Он должен скачаться в папку «Загрузки» на вашем ПК;
- Распакуйте этот архив. У вас должна получиться папка «AsyncTCP-master»;
- Переименуйте ее на «AsyncTCP»;
- Переместите папку «AsyncTCP» в папку «libraries» (туда устанавливаются библиотеки для IDE Arduino), которая находится внутри директории, куда установлена IDE Arduino;
- Наконец, перезапустите IDE Arduino.
Правильно раскладываем файлы
Для создания веб-сервера нам понадобится три разных файла – скетч IDE Arduino, HTML-файл и CSS-файл. Файлы для HTML и CSS должны храниться внутри папки «data», которая должна находиться внутри папки скетча IDE Arduino. Вот так:
Создание HTML-файла
HTML-код для этого проекта очень прост. Нам нужно просто создать заголовок для веб-страницы, абзац для показа текущего состояния GPIO-контакта и две кнопки.
Создаем файл «index.html» со следующим содержимым:
<!DOCTYPE html>
<html>
<head>
<title>ESP32 Web Server</title>
<meta name="viewport" content="width=device-width, initialscale=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>
Поскольку код для HTML и CSS находится в разных файлах, в HTML-файле необходима ссылка на CSS-файл. Для этого между тегами <head> и </head> нужно добавить вот такую строчку:
<link rel="stylesheet" type="text/css" href="style.css">
Тег <link> говорит HTML-файлу, что мы будем использовать внешний файл для оформления того, как будет выглядеть веб-страница. Атрибут «rel» указывает на то, что этим внешним файлом будет таблица стилей.
Атрибут «type» со значением «text/css» указывает, что для стилей будет использоваться CSS-файл. Атрибут «href» указывает место, где хранится файл, и поскольку оба файла (для CSS и HTML) находятся в одной папке, нам достаточно написать в нем «style.css».
В следующей строчке пишем главный заголовок веб-страницы. В нашем случае это «ESP32 Web Server» («Веб-сервер на базе ESP32»). Но вы, если хотите, можете вписать здесь все, что угодно.
<title>ESP32 Web Server</title>
Затем пишем абзац с текстом «GPIO state:» («Состояние GPIO-контакта»), после которого будет стоять само это состояние. Так как это динамическое значение, меняющееся в зависимости от текущего состояния GPIO-контакта, место для него нужно сделать так называемой «заглушкой».
Заглушка делается с помощью двух символов «%» (например, в нашем случае это «%STATE%»).
<p>GPIO state: <strong> %STATE% </strong></p>
Присвоение значения для заглушки «STATE» выполняется в скетче IDE Arduino.
Затем создаем кнопки «ON» и «OFF». В результате при клике на кнопку «ON» нас будет перенаправлять к веб-странице с корневым URL, после которого будет идти «/on», а при клике на «OFF» – к веб-странице с корневым 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 можно найти в этом руководстве, а более подробное – на этом сайте.
Скетч IDE Arduino
Скопируйте код ниже в IDE Arduino:
Укажите в нем SSID и пароль для своей WiFi-сети.
/*********
Руи Сантос
Более подробно о проекте на: https://randomnerdtutorials.com
*********/
// Импортируем необходимые библиотеки:
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
// Вставьте ниже SSID и пароль для своей WiFi-сети:
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Задаем GPIO-контакт, к которому подключен светодиод:
const int ledPin = 2;
// Создаем экземпляр класса «AsyncWebServer»
// под названием «server» и задаем ему номер порта «80»:
AsyncWebServer server(80);
// Меняем заглушку на текущее состояние светодиода:
String processor(const String& var){
// Создаем переменную для хранения состояния светодиода:
String ledState;
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("An Error has occurred while mounting SPIFFS");
// "При монтировании SPIFFS произошла ошибка"
return;
}
// Подключаемся к WiFi:
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
// "Подключаемся к WiFi..."
}
// Печатаем в мониторе порта локальный IP-адрес ESP32:
Serial.println(WiFi.localIP());
// URL для корневой страницы веб-сервера:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// URL для файла «style.css»:
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
// URL для переключения GPIO-контакта на «HIGH»:
server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(ledPin, HIGH);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// URL для переключения 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"
В двух строчках ниже вписываем SSID и пароль для своей WiFi-сети.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Далее создаем переменную «ledPin», хранящую номер контакта (GPIO2), к которому подключен светодиод.
// Задаем GPIO-контакт для светодиода:
const int ledPin = 2;
Создаем экземпляр класса «AsyncWebServer» под названием «server» и задаем ему номер порта «80» (через него будет вестись прослушка запросов).
AsyncWebServer server(80);
Функция processor()
Эта функция меняет на веб-странице заглушку, которую мы создали в HTML-файле, на текущее значение GPIO-контакта светодиода. Единственным параметром для этой функции служит заглушка, а возвращаемым значением – значение типа «String», которое будет заменять эту заглушку. Функция processor() имеет следующую структуру:
// Меняем заглушку на состояние светодиода:
String processor(const String& var){
// Создаем переменную для хранения состояния светодиода:
String ledState;
Serial.println(var);
if(var == "STATE"){
if(digitalRead(ledPin)){
ledState = "ON";
}
else{
ledState = "OFF";
}
Serial.print(ledState);
return ledState;
}
return String();
}
Сперва функция проверяет, является ли заглушка значением «STATE», заданным нами в HTML-файле.
if(var == "STATE"){
Если да, то функция processor() заменит значение в переменной «ledState» на «ON» или «OFF» – в зависимости от текущего состояния GPIO-контакта светодиода.
if(digitalRead(ledPin)){
ledState = "ON";
}
else{
ledState = "OFF";
}
Наконец, возвращаем значение переменной «ledState» – оно заменяет значение в заглушке.
return ledState;
setup()
Блок setup() начинается с запуска последовательной коммуникации и переключения GPIO-контакта светодиода в режим «OUTPUT» (т.е. режим вывода данных).
// Включаем последовательную коммуникацию (для отладки):
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
// Инициализируем SPIFFS:
if(!SPIFFS.begin(true)){
Serial.println("An Error has occurred while mounting SPIFFS");
// "При монтировании SPIFFS произошла ошибка"
return;
}
Подключение к WiFi
Далее подключаемся к WiFi и печатаем IP-адрес ESP32:
// Подключаемся к WiFi:
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
// "Подключаемся к WiFi..."
}
// Печатаем в мониторе порта локальный IP-адрес ESP32:
Serial.println(WiFi.localIP());
Асинхронный веб-сервер
С помощью библиотеки «ESPAsyncWebServer» мы можем настроить веб-сервер так, чтобы он прослушивал входящие HTTP-запросы на разные URL и – в зависимости от полученного запроса – выполнял те или иные функции. Для этого мы будем использовать метод on() на объекте «server».
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/index.html", String(), false, processor); });
Получив запрос на корневой URL «/», сервер отправит клиенту файл «index.html». Последний параметр функции send() – это функция processor(), меняющая заглушку на необходимое нам значение (в данном случае – на значение из переменной «ledState»).
Поскольку мы в HTML-файле ссылаемся на CSS-файл, клиент также сделает запрос на этот CSS-файл, и веб-сервер в ответ вышлет его клиенту.
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/style.css", "text/css");
});
Наконец, задаем, что произойдет, если пользователь сделает запрос на URL «/on» и «/off» – светодиод либо включится, либо выключится, а ESP32 соответствующим образом поменяет веб-страницу в браузере.
// URL для переключения GPIO-контакта на «HIGH»:
server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(ledPin, HIGH);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// URL для переключения GPIO-контакта на «LOW»:
server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(ledPin, LOW);
request->send(SPIFFS, "/index.html", String(), false, processor);
});
В конце используем метод begin() на объекте «server», чтобы сервер начал прослушивать входящих клиентов.
server.begin();
Поскольку это асинхронный веб-сервер, все запросы можно задать в блоке setup(). В блок loop() можно добавить код, который будет отвечать за то, что будет происходить во время того, как сервер будет прослушивать входящих клиентов.
Загружаем код и файлы
Сохраните скетч выше под названием «Async_ESP32_Web_Server». Затем кликните в IDE Arduino на «Скетч» > «Показать папку скетча» (Sketch > Show sketch folder) и создайте в открывшейся директории папку «data». Внутрь нее нужно поместить HTML- и CSS-файлы для этого скетча.
Затем загрузите этот скетч на ESP32, но перед этим убедитесь, что в IDE Arduino выбраны правильные плата и COM-порт, а в скетче заданы правильные SSID и пароль для вашей WiFi-сети.
После загрузки кода нам нужно загрузить все необходимые файлы в файловую систему ESP32. Для этого кликаем в IDE Arduino на «Инструменты» > «ESP32 Sketch Data Upload» (Tools > ESP32 Sketch Data Upload) и ждем, пока файлы загрузятся.
После того, как все загрузится, открываем монитор порта на скорости 115200 бод и жмем на кнопку EN на ESP32. В мониторе порта должен напечататься IP-адрес ESP32.
Демонстрация
Откройте браузер и впишите в нем IP-адрес ESP32. В результате в браузере должна открыться веб-страница с кнопками «ON» и «OFF» для управления встроенным светодиодом ESP32. Также проверьте, правильно ли показывается и обновляется на веб-странице состояние GPIO-контакта.
Итого
Файловая система SPIFFS особенно полезна для хранения HTML- и CSS-файлов, используемых для обслуживания веб-клиентов. Благодаря ей вам не приходится писать код для веб-сервера прямо в скетче IDE Arduino.
Библиотека «ESPAsyncWebServer» позволяет создать веб-сервер, у которого для разных запросов приготовлены разные варианты действий. Кроме того, мы можем добавить в HTML-страницу заглушку, а затем вставить вместо нее необходимое значение – например, данные от датчиков, состояние GPIO-контакта и т.д.
См.также
Внешние ссылки