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

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

Перевод: Максим Кузьмин (Cubewriter)
Перевел 28058 статей для сайта.

Контакты:

Проверка/Оформление/Редактирование: Мякишев Е.А.


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-контакта и т.д.

См.также

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