ESP32 Веб-сервер с использованием SPIFFS (файловая система SPI Flash)

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

ESP32 веб-сервер с SPIFFS

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

Рекомендуемое чтение: ESP8266 Web Server using SPIFFS

Плагин загрузки файловой системы ESP32

Для выполнения этого руководства у вас должен быть установлен плагин ESP32 Filesystem Uploader в вашей Arduino IDE. Если у вас его нет, сначала следуйте следующему руководству для его установки:

Примечание: убедитесь, что у вас установлена последняя версия Arduino IDE, а также дополнение ESP32 для Arduino IDE. Если нет, следуйте одному из следующих руководств для установки:

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

Прежде чем переходить непосредственно к проекту, важно описать, что будет делать наш веб-сервер, чтобы было легче понять.

Обзор асинхронного веб-сервера ESP32
  • Веб-сервер, который вы создадите, управляет светодиодом, подключённым к GPIO 2 ESP32. Это встроенный светодиод ESP32. Вы можете управлять любым другим GPIO;

  • Страница веб-сервера отображает две кнопки: ON и OFF – для включения и выключения GPIO 2;

  • Страница веб-сервера также показывает текущее состояние GPIO.

На следующем рисунке показана упрощённая диаграмма, демонстрирующая, как всё работает.

Диаграмма работы асинхронного веб-сервера с SPIFFS
  • ESP32 запускает код веб-сервера на основе библиотеки ESPAsyncWebServer;

  • HTML и CSS файлы хранятся в SPIFFS (Serial Peripheral Interface Flash File System) ESP32;

  • Когда вы делаете запрос на определённый URL с помощью браузера, ESP32 отвечает запрошенными файлами;

  • Когда вы нажимаете кнопку ON, вы перенаправляетесь на корневой URL с добавлением /on, и светодиод включается;

  • Когда вы нажимаете кнопку OFF, вы перенаправляетесь на корневой URL с добавлением /off, и светодиод выключается;

  • На веб-странице есть заполнитель (placeholder) для состояния GPIO. Заполнитель для состояния GPIO записывается непосредственно в HTML-файле между знаками %, например %STATE%.

Установка библиотек

В большинстве наших проектов мы создавали HTML и CSS файлы для веб-сервера как строку (String) непосредственно в скетче Arduino. С SPIFFS вы можете написать HTML и CSS в отдельных файлах и сохранить их в файловой системе ESP32.

Один из самых простых способов создать веб-сервер, используя файлы из файловой системы, – это использование библиотеки ESPAsyncWebServer. Библиотека ESPAsyncWebServer хорошо документирована на её странице GitHub. Для получения дополнительной информации об этой библиотеке перейдите по следующей ссылке:

Установка библиотеки ESPAsyncWebServer

Выполните следующие шаги для установки библиотеки ESPAsyncWebServer:

  1. Нажмите здесь для загрузки библиотеки ESPAsyncWebServer. У вас должен появиться .zip файл в папке Загрузки

  2. Распакуйте .zip файл, и вы должны получить папку ESPAsyncWebServer-master

  3. Переименуйте папку из ESPAsyncWebServer-master в ESPAsyncWebServer

  4. Переместите папку ESPAsyncWebServer в папку библиотек вашей Arduino IDE

Установка библиотеки Async TCP для ESP32

Библиотека ESPAsyncWebServer требует библиотеку AsyncTCP для работы. Выполните следующие шаги для установки этой библиотеки:

  1. Нажмите здесь для загрузки библиотеки AsyncTCP. У вас должен появиться .zip файл в папке Загрузки

  2. Распакуйте .zip файл, и вы должны получить папку AsyncTCP-master

  3. Переименуйте папку из AsyncTCP-master в AsyncTCP

  4. Переместите папку AsyncTCP в папку библиотек вашей Arduino IDE

  5. Наконец, перезапустите Arduino IDE

Организация файлов

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

Организация папок для асинхронного веб-сервера с SPIFFS

Создание 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-тексте. Следующая строка должна быть добавлена между тегами <head> </head>:

<link rel="stylesheet" type="text/css" href="style.css">

Тег <link> сообщает HTML-файлу, что вы используете внешнюю таблицу стилей для форматирования внешнего вида страницы. Атрибут rel указывает природу внешнего файла, в данном случае это stylesheet – 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.

Затем мы создаём кнопки 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. Хорошее место для изучения CSS – это сайт W3Schools.

Скетч Arduino

Скопируйте следующий код в Arduino IDE или скачайте все файлы проекта здесь. Затем вам нужно ввести ваши сетевые учётные данные (SSID и пароль), чтобы он заработал.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com
*********/

// Import required libraries
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Set LED GPIO
const int ledPin = 2;
// Stores LED state
String ledState;

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Replaces placeholder with LED state value
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 port for debugging purposes
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);

  // Initialize SPIFFS
  if(!SPIFFS.begin(true)){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP32 Local IP Address
  Serial.println(WiFi.localIP());

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

  // Route to load style.css file
  server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/style.css", "text/css");
  });

  // Route to set GPIO to HIGH
  server.on("/on", HTTP_GET, [](AsyncWebServerRequest *request){
    digitalWrite(ledPin, HIGH);
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

  // Route to set GPIO to LOW
  server.on("/off", HTTP_GET, [](AsyncWebServerRequest *request){
    digitalWrite(ledPin, LOW);
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

  // Start server
  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;

Создайте объект AsyncWebServer с именем server, который прослушивает порт 80.

AsyncWebServer server(80);

Функция processor()

Функция processor() – это то, что присваивает значение заполнителю, который мы создали в HTML-файле. Она принимает в качестве аргумента заполнитель и должна возвращать строку (String), которая заменит заполнитель. Функция 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();
}

Эта функция сначала проверяет, является ли заполнитель тем самым STATE, который мы создали в 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("An Error has occurred while mounting SPIFFS");
  return;
}

Подключение к Wi-Fi

Подключитесь к Wi-Fi и выведите IP-адрес ESP32:

WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.println("Connecting to WiFi..");
}
Serial.println(WiFi.localIP());

Асинхронный веб-сервер

Библиотека ESPAsyncWebServer позволяет нам настроить маршруты, по которым сервер будет прослушивать входящие HTTP-запросы и выполнять функции при получении запроса на этом маршруте. Для этого используйте метод on() объекта server следующим образом:

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(SPIFFS, "/index.html", String(), false, processor);
});

Когда сервер получает запрос на корневой URL « / «, он отправляет файл index.html клиенту. Последний аргумент функции send() – это процессор (processor), чтобы мы могли заменить заполнитель на нужное значение – в данном случае на ledState.

Поскольку мы сослались на 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, чтобы сервер начал прослушивать входящих клиентов.

server.begin();

Поскольку это асинхронный веб-сервер, вы можете определить все запросы в функции setup(). Затем вы можете добавить другой код в loop(), пока сервер прослушивает входящих клиентов.

Загрузка кода и файлов

Сохраните код как Async_ESP32_Web_Server или скачайте все файлы проекта здесь. Перейдите в Sketch > Show Sketch Folder и создайте папку с именем data. Внутри этой папки вы должны сохранить файлы HTML и CSS.

Затем загрузите код на вашу плату ESP32. Убедитесь, что вы выбрали правильную плату и COM-порт. Также убедитесь, что вы добавили ваши сетевые учётные данные в код.

Кнопка загрузки в Arduino IDE

После загрузки кода вам нужно загрузить файлы. Перейдите в Tools > ESP32 Data Sketch Upload и дождитесь загрузки файлов.

Загрузка данных скетча ESP32

Когда всё успешно загружено, откройте монитор порта на скорости 115200 бод. Нажмите кнопку « ENABLE « на ESP32, и он должен вывести IP-адрес ESP32.

IP-адрес ESP32 в мониторе порта

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

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

Пример работы веб-сервера ESP32 с SPIFFS

Заключение

Использование файловой системы SPI Flash (SPIFFS) особенно полезно для хранения HTML и CSS файлов, которые обслуживаются клиенту – вместо того, чтобы писать весь код внутри скетча Arduino.

Библиотека ESPAsyncWebServer позволяет создать веб-сервер, запуская определённую функцию в ответ на определённый запрос. Вы также можете добавить заполнители в HTML-файл, которые могут быть заменены переменными – например, показаниями датчиков или состояниями GPIO.

Если вам понравился этот проект, вам также могут понравиться:

Это отрывок из нашего курса: Learn ESP32 with Arduino IDE . Если вам нравится ESP32 и вы хотите узнать больше, мы рекомендуем записаться на курс Learn ESP32 with Arduino IDE .


Источник: ESP32 Web Server using SPIFFS (SPI Flash File System)