Каталог

Веб-сервер ESP32 с использованием SPIFFS (SPI Flash File System)

В этом уроке мы покажем вам, как создать веб-сервер, который обслуживает файлы 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.

Комментарии
Отзывов еще никто не оставлял
Предзаказ
Предзаказ успешно отправлен!
Имя *
Телефон *
Добавить в корзину
Название товара
100 тг
1 шт.
Перейти в корзину
Обратный звонок
Запрос успешно отправлен!
Имя *
Телефон *
Заказ в один клик
С помощью уведомлений о заказе можно не только получать актуальную информацию по заказу, но и иметь быстрый канал связи с магазином