ESP32:Примеры/Создание веб-сервера на базе ESP32 при помощи файлов из файловой системы (SPIFFS)

Материал из Онлайн справочника
Перейти к навигации Перейти к поиску

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Pixel Art Mini Meow Animated.gif Черновик


Создание веб-сервера на базе ESP32 при помощи файлов из файловой системы (SPIFFS)

В руководстве «SPIFFS платы ESP32 (файловая система памяти SPI Flash)» мы рассказывали, как с помощью файловой системы SPIFFS загружать и манипулировать файлами, хранящимися на flash-памяти ESP32. В этом руководстве мы покажем, как создать веб-сервер, использующий HTML- и CSS-файлы, хранящиеся в файловой системе.

Веб-сервер, который мы сделаем в этом руководстве, будет похож на веб-сервер, который мы сделали в руководстве «Веб-сервер на базе ESP32: управление выходными контактами».

Чтобы продолжить дальше, в IDE Arduino должен быть установлен плагин загрузчика SPIFFS. О том, как это сделать, читайте в руководстве «SPIFFS платы ESP32 (файловая система памяти SPI Flash)».

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

Для начала давайте в общих чертах обрисуем, что будет делать наш веб-сервер – чтобы нам было проще над ним работать.

Esp32 web server with spiffs files main page 1.PNG
  • Веб-сервер будет управлять светодиодом, подключенным к контакту GPIO2 на ESP32 (это встроенный светодиод ESP32). Но вы можете задать для этого любой другой GPIO-контакт;
  • На странице веб-сервера будет показано две кнопки: «ON» и «OFF» – для включения и выключения контакта GPIO2;
  • Также страница веб-сервера будет показывать текущее состояние контакта GPIO2;
  • На изображении ниже схематически изображено, как все это будет работать:
Esp32 spiffs web server project overview 1.png
  • Для создания веб-сервера будет использоваться библиотека «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»

  1. Кликните тут, чтобы скачать ZIP-архив библиотеки. Он должен скачаться в папку «Загрузки» на вашем ПК;
  2. Распакуйте этот архив. У вас должна получиться папка «ESPAsyncWebServer-master»;
  3. Переименуйте ее на «ESPAsyncWebServer»;
  4. Переместите папку «ESPAsyncWebServer» в папку «libraries» (туда устанавливаются библиотеки для IDE Arduino), которая находится внутри папки, куда установлена IDE Arduino;

Устанавливаем библиотеку «AsyncTCP»

Библиотеке «ESPAsyncWebServer» необходима для работы библиотека «AsyncTCP».

  1. Кликните тут, чтобы скачать ZIP-архив библиотеки. Он должен скачаться в папку «Загрузки» на вашем ПК;
  2. Распакуйте этот архив. У вас должна получиться папка «AsyncTCP-master»;
  3. Переименуйте ее на «AsyncTCP»;
  4. Переместите папку «AsyncTCP» в папку «libraries» (туда устанавливаются библиотеки для IDE Arduino), которая находится внутри директории, куда установлена IDE Arduino;
  5. Наконец, перезапустите IDE Arduino.

Правильно раскладываем файлы

Для создания веб-сервера нам понадобится три разных файла – скетч IDE Arduino, HTML-файл и CSS-файл. Файлы для HTML и CSS должны храниться внутри папки «data», которая должна находиться внутри папки скетча IDE Arduino. Вот так:

Esp32 web server with spiffs files 1.PNG

Создание HTML-файла

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

Создаем файл «index.html» со следующим содержимым:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4   <title>ESP32 Web Server</title>
 5   <meta name="viewport" content="width=device-width, initialscale=1">
 6   <link rel="icon" href="data:,">
 7   <link rel="stylesheet" type="text/css" href="style.css">
 8 </head>
 9 <body>
10   <h1>ESP32 Web Server</h1>
11   <p>GPIO state: <strong> %STATE%</strong></p>
12   <p><a href="/on"><button class="button">ON</button></a></p>
13   <p><a href="/off"><button class="button button2">OFF</button></a></p>
14 </body>
15 </html>

Примечание: Введение в HTML и CSS читайте в руководстве «Веб-сервер на базе ESP32: управление выходными контактами».

Поскольку код для 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».

1 <p><a href="/on"><button class="button">ON</button></a></p>
2 <p><a href="/off"><button class="button button2">OFF</button></a></p>

Создаем CSS-файл

Теперь создаем файл «style.css», содержащий в себе код ниже:

 1 html {
 2   font-family: Helvetica;
 3   display: inline-block;
 4   margin: 0px auto;
 5   text-align: center;
 6 }
 7 h1{
 8   color: #0F3376;
 9   padding: 2vh;
10 }
11 p{
12   font-size: 1.5rem;
13 }
14 .button {
15   display: inline-block;
16   background-color: #008CBA;
17   border: none;
18   border-radius: 4px;
19   color: white;
20   padding: 16px 40px;
21   text-decoration: none;
22   font-size: 30px;
23   margin: 2px;
24   cursor: pointer;
25 }
26 .button2 {
27   background-color: #f44336;
28 }

Этот CSS-файл задает несколько базовых параметров: размер шрифта, стиль и цвет кнопок, а также выравнивание страницы. Краткое введение в CSS можно найти в этом руководстве, а более подробное – на этом сайте.

Скетч IDE Arduino

Скопируйте код ниже в IDE Arduino:

Укажите в нем SSID и пароль для своей WiFi-сети.

 1 /*********
 2   Руи Сантос
 3   Более подробно о проекте на: https://randomnerdtutorials.com  
 4 *********/
 5 
 6 // Импортируем необходимые библиотеки:
 7 #include "WiFi.h"
 8 #include "ESPAsyncWebServer.h"
 9 #include "SPIFFS.h"
10 
11 // Вставьте ниже SSID и пароль для своей WiFi-сети:
12 const char* ssid = "REPLACE_WITH_YOUR_SSID";
13 const char* password = "REPLACE_WITH_YOUR_PASSWORD";
14 
15 // Задаем GPIO-контакт, к которому подключен светодиод:
16 const int ledPin = 2;
17 
18 // Создаем экземпляр класса «AsyncWebServer»
19 // под названием «server» и задаем ему номер порта «80»:
20 AsyncWebServer server(80);
21 
22 // Меняем заглушку на текущее состояние светодиода:
23 String processor(const String& var){
24   // Создаем переменную для хранения состояния светодиода:
25   String ledState;
26 
27   Serial.println(var);
28   if(var == "STATE"){
29     if(digitalRead(ledPin)){
30       ledState = "ON";
31     }
32     else{
33       ledState = "OFF";
34     }
35     Serial.print(ledState);
36     return ledState;
37   }
38   return String();
39 }
40  
41 void setup(){
42   // Включаем последовательную коммуникацию (для отладки):
43   Serial.begin(115200);
44   pinMode(ledPin, OUTPUT);
45 
46   // Инициализируем SPIFFS:
47   if(!SPIFFS.begin(true)){
48     Serial.println("An Error has occurred while mounting SPIFFS");
49                //  "При монтировании SPIFFS произошла ошибка"
50     return;
51   }
52 
53   // Подключаемся к WiFi:
54   WiFi.begin(ssid, password);
55   while (WiFi.status() != WL_CONNECTED) {
56     delay(1000);
57     Serial.println("Connecting to WiFi..");
58                //  "Подключаемся к WiFi..."
59   }
60 
61   // Печатаем в мониторе порта локальный IP-адрес ESP32:
62   Serial.println(WiFi.localIP());
63 
64   // URL для корневой страницы веб-сервера:
65   server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
66     request->send(SPIFFS, "/index.html", String(), false, processor);
67   });
68   
69   // URL для файла «style.css»:
70   server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
71     request->send(SPIFFS, "/style.css", "text/css");
72   });
73 
74   // URL для переключения GPIO-контакта на «HIGH»:
75   server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
76     digitalWrite(ledPin, HIGH);    
77     request->send(SPIFFS, "/index.html", String(), false, processor);
78   });
79   
80   // URL для переключения GPIO-контакта на «LOW»:
81   server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
82     digitalWrite(ledPin, LOW);    
83     request->send(SPIFFS, "/index.html", String(), false, processor);
84   });
85 
86   // Запускаем сервер:
87   server.begin();
88 }
89  
90 void loop(){
91   
92 }

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

Сначала подключаем необходимые библиотеки.

1 #include "WiFi.h"
2 #include "ESPAsyncWebServer.h"
3 #include "SPIFFS.h"

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

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

Далее создаем переменную «ledPin», хранящую номер контакта (GPIO2), к которому подключен светодиод.

1 // Задаем GPIO-контакт для светодиода:
2 const int ledPin = 2;

Создаем экземпляр класса «AsyncWebServer» под названием «server» и задаем ему номер порта «80» (через него будет вестись прослушка запросов).

AsyncWebServer server(80);

Функция processor()

Эта функция меняет на веб-странице заглушку, которую мы создали в HTML-файле, на текущее значение GPIO-контакта светодиода. Единственным параметром для этой функции служит заглушка, а возвращаемым значением – значение типа «String», которое будет заменять эту заглушку. Функция processor() имеет следующую структуру:

 1 // Меняем заглушку на состояние светодиода:
 2 String processor(const String& var){
 3   // Создаем переменную для хранения состояния светодиода:
 4   String ledState;
 5 
 6   Serial.println(var);
 7   if(var == "STATE"){
 8     if(digitalRead(ledPin)){
 9       ledState = "ON";
10     }
11     else{
12       ledState = "OFF";
13     }
14     Serial.print(ledState);
15     return ledState;
16   }
17   return String();
18 }

Сперва функция проверяет, является ли заглушка значением «STATE», заданным нами в HTML-файле.

if(var == "STATE"){

Если да, то функция processor() заменит значение в переменной «ledState» на «ON» или «OFF» – в зависимости от текущего состояния GPIO-контакта светодиода.

1 if(digitalRead(ledPin)){
2   ledState = "ON";
3 }
4 else{
5   ledState = "OFF";
6 }

Наконец, возвращаем значение переменной «ledState» – оно заменяет значение в заглушке.

return ledState;

setup()

Блок setup() начинается с запуска последовательной коммуникации и переключения GPIO-контакта светодиода в режим «OUTPUT» (т.е. режим вывода данных).

 1 // Включаем последовательную коммуникацию (для отладки):
 2 Serial.begin(115200);
 3 pinMode(ledPin, OUTPUT);
 4 
 5 // Инициализируем SPIFFS:
 6 if(!SPIFFS.begin(true)){
 7   Serial.println("An Error has occurred while mounting SPIFFS");
 8                //  "При монтировании SPIFFS произошла ошибка"
 9   return;
10 }

Подключение к WiFi

Далее подключаемся к WiFi и печатаем IP-адрес ESP32:

 1 // Подключаемся к WiFi:
 2 WiFi.begin(ssid, password);
 3 while (WiFi.status() != WL_CONNECTED) {
 4   delay(1000);
 5   Serial.println("Connecting to WiFi..");
 6                //  "Подключаемся к WiFi..."
 7 }
 8 
 9 // Печатаем в мониторе порта локальный IP-адрес ESP32:
10 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-файл, и веб-сервер в ответ вышлет его клиенту.

1 server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
2 request->send(SPIFFS, "/style.css", "text/css");
3 });

Наконец, задаем, что произойдет, если пользователь сделает запрос на URL «/on» и «/off» – светодиод либо включится, либо выключится, а ESP32 соответствующим образом поменяет веб-страницу в браузере.

 1 // URL для переключения GPIO-контакта на «HIGH»:
 2 server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
 3   digitalWrite(ledPin, HIGH);    
 4   request->send(SPIFFS, "/index.html", String(), false, processor);
 5 });
 6   
 7 // URL для переключения GPIO-контакта на «LOW»:
 8 server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
 9   digitalWrite(ledPin, LOW);    
10   request->send(SPIFFS, "/index.html", String(), false, processor);
11 });

В конце используем метод 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) и ждем, пока файлы загрузятся.

Esp32 arduino scetch data upload 1.PNG

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

Демонстрация

Откройте браузер и впишите в нем IP-адрес ESP32. В результате в браузере должна открыться веб-страница с кнопками «ON» и «OFF» для управления встроенным светодиодом ESP32. Также проверьте, правильно ли показывается и обновляется на веб-странице состояние GPIO-контакта.

Esp32 web server with spiffs files main page 1.PNG

Итого

Файловая система SPIFFS особенно полезна для хранения HTML- и CSS-файлов, используемых для обслуживания веб-клиентов. Благодаря ей вам не приходится писать код для веб-сервера прямо в скетче IDE Arduino.

Библиотека «ESPAsyncWebServer» позволяет создать веб-сервер, у которого для разных запросов приготовлены разные варианты действий. Кроме того, мы можем добавить в HTML-страницу заглушку, а затем вставить вместо нее необходимое значение – например, данные от датчиков, состояние GPIO-контакта и т.д.

См.также

Внешние ссылки