ESP32 веб-сервер с использованием файловой системы LittleFS

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

ESP32 веб-сервер с использованием файловой системы LittleFS

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

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

Введение в LittleFS

LittleFS — это легковесная файловая система, созданная для микроконтроллеров. Она позволяет работать с флэш-памятью так же, как с обычной файловой системой на вашем компьютере, но она проще и более ограничена. Вы можете читать, записывать, закрывать и удалять файлы. Использование LittleFS с платами ESP32 полезно для:

  • Создания файлов конфигурации с настройками;

  • Постоянного сохранения данных, даже после перезагрузки или отключения питания;

  • Создания файлов для хранения небольших объёмов данных вместо использования карты microSD;

  • Сохранения файлов HTML, CSS и JavaScript для создания интерфейса веб-сервера (как мы сделаем в этом руководстве);

  • Хранения изображений, рисунков и иконок для ваших веб-страниц или модулей отображения;

  • Локального журналирования показаний датчиков или данных приложения;

  • И многого другого, в зависимости от потребностей вашего проекта.

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

Введение в веб-серверы ESP32

Проще говоря, веб-сервер — это «компьютер», который доставляет веб-страницы пользователям. Он хранит файлы веб-сайта, включая HTML-документы и связанные ресурсы, такие как изображения, таблицы стилей CSS, шрифты и другие ресурсы.

Когда пользователь делает запрос — обычно вводя URL или нажимая на ссылку — веб-сервер отвечает, отправляя запрошенные файлы в веб-браузер пользователя, используя протокол HTTP (Hypertext Transfer Protocol). HTTP — это основа обмена данными в Интернете, определяющая, как сообщения форматируются и передаются между клиентами (например, вашим браузером) и серверами.

ESP32 запрос-ответ

В этом примере ESP32 выступает в роли веб-сервера. Он хранит HTML- и CSS-файлы, необходимые для построения веб-страницы, в файловой системе LittleFS. Когда вы обращаетесь к IP-адресу ESP32 в браузере, на ESP32 отправляется HTTP-запрос. ESP32 затем отвечает HTML- и CSS-файлами, которые браузер использует для отрисовки страницы. Эти файлы также могут содержать динамический контент, такой как показания датчиков и текущее состояние выходов, которые обновляются при каждом новом запросе.

ESP32 клиент-серверное взаимодействие

Если вы новичок в веб-серверах ESP32, рекомендуем прочитать следующее руководство:

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

Прежде чем приступить непосредственно к проекту, важно описать, что будет делать наш веб-сервер, чтобы его было легче понять. На следующем изображении показан интерфейс, который мы создадим с помощью файлов из файловой системы ESP32.

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

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

  • На странице веб-сервера также отображается текущее состояние GPIO;

  • Вы также будете использовать датчик BME280 для отображения показаний датчиков (температура, влажность и давление).

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

Обзор проекта ESP32 LittleFS веб-сервер

Необходимые условия

Перед тем как приступить к этому проекту, убедитесь, что вы выполнили все следующие предварительные условия.

1. Установка платы ESP32 в Arduino IDE 2

Мы будем программировать ESP32 с помощью Arduino IDE, поэтому у вас должны быть установлены платы ESP32. Следуйте следующему руководству, если вы ещё этого не сделали:

2. Установка плагина загрузчика файловой системы ESP32

Для загрузки файлов в файловую систему ESP32 LittleFS необходимо установить плагин Filesystem Uploader. Установите его в Arduino IDE 2:

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

Библиотеки Async Web Server

Мы создадим веб-сервер, используя следующие библиотеки:

Вы можете установить эти библиотеки в менеджере библиотек Arduino. Откройте менеджер библиотек, нажав на значок библиотеки на левой боковой панели.

Найдите ESPAsyncWebServer и установите ESPAsyncWebServer by ESP32Async.

Установка ESPAsyncWebServer ESP32 Arduino IDE

Затем установите библиотеку AsyncTCP. Найдите AsyncTCP и установите AsyncTCP by ESP32Async.

Установка AsyncTCP ESP32 Arduino IDE

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

В этом руководстве мы будем отображать показания датчика BME280 (Руководство с ESP32). Вам нужно установить следующие библиотеки:

Вы можете установить эти библиотеки через менеджер библиотек Arduino IDE. Перейдите в Sketch > Include Libraries > Manage Libraries. Затем найдите библиотеки по их названиям для установки.

Необходимые компоненты

Для выполнения этого проекта вам понадобятся следующие компоненты:

Схема подключения

Подключите все компоненты, следуя этой схеме:

Схема подключения ESP32 со светодиодом и BME280

Рекомендуемое чтение: Справочник по выводам ESP32: Какие GPIO использовать?

BME280

ESP32

Vin

3V3

GND

GND

SCL

GPIO 22

SDA

GPIO 21

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

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

Организация папок ESP32 LittleFS веб-сервер

Вы можете скачать все файлы проекта:

Затем вам нужно загрузить образ файловой системы перед загрузкой кода.

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

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

<!DOCTYPE html>
<!--
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-web-server-littlefs/
-->
<html>
<head>
  <meta charset="UTF-8">
  <title>ESP32 LittleFS 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 LittleFS Web Server</h1>

  <p>💡 GPIO state<strong> %STATE%</strong></p>

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

  <p>
    <span class="sensor-labels">🌡️ Temperature</span>
    <span id="temperature">%TEMPERATURE%</span>
    <sup class="units">&deg;C</sup>
  </p>

  <p>
    <span class="sensor-labels">💧 Humidity</span>
    <span id="humidity">%HUMIDITY%</span>
    <sup class="units">&#37;</sup>
  </p>

  <p>
    <span class="sensor-labels">↕️ Pressure</span>
    <span id="pressure">%PRESSURE%</span>
    <sup class="units">hPa</sup>
  </p>
</body>

<script>
  const updateSensorValue = (id, endpoint) => {
    fetch(endpoint)
      .then(response => {
        if (!response.ok) {
          throw new Error(`Failed to fetch ${endpoint}`);
        }
        return response.text();
      })
      .then(data => {
        document.getElementById(id).textContent = data;
      })
      .catch(error => {
        console.error(error);
        document.getElementById(id).textContent = 'Error';
      });
  };

  // Update all sensors every 10 seconds
  setInterval(() => {
    updateSensorValue('temperature', '/temperature');
    updateSensorValue('humidity', '/humidity');
    updateSensorValue('pressure', '/pressure');
  }, 10000);

</script>
</html>

Просмотреть исходный код

Head HTML-файла

В разделе <head> HTML-файла мы должны добавить метаданные. Следующая строка указывает кодировку документа. UTF-8 — самая популярная кодировка, поддерживающая все символы всех языков, включая эмодзи.

<meta charset="UTF-8">

Элемент <title> определяет заголовок веб-страницы, который отображается на вкладке браузера.

<title>ESP32 LittleFS Web Server</title>

Мы используем следующую строку, чтобы сделать веб-страницу адаптивной на всех устройствах.

<meta name="viewport" content="width=device-width, initial-scale=1">

Мы не будем использовать фавикон для нашей веб-страницы. Чтобы предотвратить запросы фавикона, можно сделать следующее:

<link rel="icon" href="data:,">

Поскольку мы используем CSS и HTML в разных файлах, нам нужно указать ссылку на CSS-файл в HTML-тексте.

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

Тег <link> сообщает HTML-файлу, что вы используете внешнюю таблицу стилей для форматирования внешнего вида страницы. Атрибут rel указывает характер внешнего файла, в данном случае — что это таблица стилей (stylesheet) — CSS-файл, который будет использоваться для изменения внешнего вида страницы.

Атрибут type установлен в «text/css», чтобы указать, что вы используете CSS-файл для стилей. Атрибут href указывает расположение файла; поскольку CSS- и HTML-файлы будут в одной папке, достаточно указать имя файла: style.css.

Body HTML-файла

В следующей строке мы записываем первый заголовок нашей веб-страницы. В данном случае это «ESP32 LittleFS Web Server». Вы можете изменить заголовок на любой текст:

<h1>ESP32 LittleFS Web Server</h1>

Затем добавьте абзац с текстом «GPIO state «, за которым следует состояние GPIO. Поскольку состояние GPIO меняется в соответствии с состоянием GPIO, мы можем добавить заполнитель (placeholder), который затем будет заменён любым значением, которое мы установим в скетче Arduino.

Чтобы добавить заполнитель, используйте знаки %. Для создания заполнителя для состояния можно использовать %STATE%, например.

<p>💡 GPIO state<strong> %STATE%</strong></p>

Вы присваиваете значение заполнителю STATE в скетче Arduino — мы увидим, как это работает, позже.

Затем создайте кнопки ON и OFF. При нажатии кнопки on мы перенаправляем веб-страницу на корневой URL с добавлением /on. При нажатии кнопки off вы перенаправляетесь на URL /off.

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

Наконец, создайте три абзаца для отображения температуры, влажности и давления.

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

<p>
  <span class="sensor-labels">🌡️ Temperature</span>
  <span id="temperature">%TEMPERATURE%</span>
  <sup class="units">&deg;C</sup>
</p>

<p>
  <span class="sensor-labels">💧 Humidity</span>
  <span id="humidity">%HUMIDITY%</span>
  <sup class="units">&#37;</sup>
</p>

<p>
  <span class="sensor-labels">↕️ Pressure</span>
  <span id="pressure">%PRESSURE%</span>
  <sup class="units">hPa</sup>
</p>

Мы используем заполнители %TEMPERATURE%, %HUMIDITY% и %PRESSURE%. Они затем будут заменены фактическими показаниями датчиков в скетче Arduino.

Автоматическое обновление

Мы также добавляем немного JavaScript в наш HTML-файл, который отвечает за обновление показаний каждые десять секунд без необходимости обновления веб-страницы. Он должен располагаться между тегами <script></script>.

По сути, мы получаем данные датчиков с сервера (ESP32) и обновляем содержимое соответствующих HTML-элементов на странице.

Мы создаём функцию под названием updateSensorValue, которая принимает два параметра: id (идентификатор HTML-элемента на странице) и endpoint (URL, с которого нужно получить данные датчика — например, для получения значений температуры мы делаем запрос по URL /temperature).

const updateSensorValue = (id, endpoint) => {
  fetch(endpoint)
    .then(response => {
      if (!response.ok) {
        throw new Error(`Failed to fetch ${endpoint}`);
      }
      return response.text();
    })
    .then(data => {
      document.getElementById(id).textContent = data;
    })
    .catch(error => {
      console.error(error);
      document.getElementById(id).textContent = 'Error';
    });
};

Команда fetch(endpoint) отправляет запрос на сервер (ESP32).

fetch(endpoint)

Если сервер отвечает успешно, функция извлекает данные ответа (в текстовом формате) и обновляет текстовое содержимое HTML-элемента с указанным id.

  }
  return response.text();
})
  .then(data => {
     document.getElementById(id).textContent = data;
   })

Если что-то пошло не так (например, сервер недоступен или запрос не удался), в HTML-элементе отображается Error, а ошибка записывается в консоль.

.catch(error => {
  console.error(error);
  document.getElementById(id).textContent = 'Error';
});

Обновление показаний датчиков

Функция setInterval() используется для вызова функции updateSensorValue() каждые 10 секунд. Она получает данные температуры, влажности и давления и помещает показания в соответствующие HTML-элементы.

// Update all sensors every 10 seconds
setInterval(() => {
  updateSensorValue('temperature', '/temperature');
  updateSensorValue('humidity', '/humidity');
  updateSensorValue('pressure', '/pressure');
}, 10000);

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

Создайте файл style.css со следующим содержимым:

/***
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-web-server-littlefs/
***/

html {
  font-family: Arial;
  display: inline-block;
  margin: 0 auto;
  text-align: center;
  background-color: #f4f4f4;
  color: #333;
}

h1 {
  color: #0F3376;
  padding: 2vh 1rem;
  font-size: 2rem;
  margin-bottom: 1rem;
}

p {
  font-size: 1.5rem;
  margin: 1rem auto;
  max-width: 600px;
}

.button {
  display: inline-block;
  background-color: #00A676;
  border: none;
  border-radius: 6px;
  color: white;
  padding: 14px 32px;
  text-decoration: none;
  font-size: 1.2rem;
  margin: 6px 10px;
  cursor: pointer;
  transition: background-color 0.3s ease, transform 0.1s ease;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
  width: 160px;
}

.button:hover {
  background-color: #0077a8;
  transform: translateY(-1px);
}

.button2 {
  background-color: #f44336;
}

.button2:hover {
  background-color: #d9362c;
}

.units {
  font-size: 1.2rem;
  color: #555;
  margin-left: 4px;
}

.sensor-labels {
  font-size: 1.5rem;
  font-weight: bold;
  vertical-align: middle;
  padding-bottom: 15px;
}

Просмотреть исходный код

Это просто базовый CSS-файл для установки размера шрифта, стиля и цвета кнопок и выравнивания страницы. Мы не будем объяснять, как работает CSS. Хорошее место для изучения CSS — сайт W3Schools.

ESP32 веб-сервер с файлами из LittleFS (скетч Arduino)

ESP32 LittleFS веб-сервер управление выходами и мониторинг датчиков

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

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-web-server-littlefs/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

// Import required libraries
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <FS.h>
#include <LittleFS.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

// 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);

String getTemperature() {
  float temperature = bme.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  //float t = dht.readTemperature(true);
  Serial.println(temperature);
  return String(temperature);
}

String getHumidity() {
  float humidity = bme.readHumidity();
  Serial.println(humidity);
  return String(humidity);
}

String getPressure() {
  float pressure = bme.readPressure()/ 100.0F;
  Serial.println(pressure);
  return String(pressure);
}

// 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.println(ledState);
    return ledState;
  }
  else if (var == "TEMPERATURE"){
    return getTemperature();
  }
  else if (var == "HUMIDITY"){
    return getHumidity();
  }
  else if (var == "PRESSURE"){
    return getPressure();
  }
  return String();
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);

  // Initialize the sensor
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Initialize LittleFS
  if(!LittleFS.begin()){
    Serial.println("An Error has occurred while mounting LittleFS");
    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(LittleFS, "/index.html", String(), false, processor);
  });

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

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

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

  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", getTemperature().c_str());
  });

  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", getHumidity().c_str());
  });

  server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", getPressure().c_str());
  });

  // Start server
  server.begin();
}

void loop(){

}

Просмотреть исходный код

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

Продолжайте чтение, чтобы узнать, как работает код, или перейдите к следующему разделу.

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

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
#include <FS.h>
#include <LittleFS.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

Вам нужно ввести свои сетевые учётные данные в следующие переменные:

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

Создайте экземпляр, ссылающийся на датчик BME280, с именем bme:

Adafruit_BME280 bme; // I2C

Далее создайте переменную, ссылающуюся на GPIO 2, с именем ledPin, и строковую переменную для хранения состояния светодиода: ledState.

const int ledPin = 2;
String ledState;

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

AsyncWebServer server(80);

Получение показаний датчиков

Мы создаём три функции для возврата показаний датчиков в виде строк: функции getTemperature(), getHumidity() и getPressure().

Вот как выглядит функция getTemperature() (остальные функции аналогичны).

String getTemperature() {
  float temperature = bme.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  //float temperature = 1.8 * bme.readTemperature() + 32;
  Serial.println(temperature);
  return String(temperature);
}

Если вы хотите отображать температуру в градусах Фаренгейта, просто раскомментируйте соответствующую строку в функции getTemperature():

float temperature = 1.8 * bme.readTemperature() + 32;

Чтобы узнать больше о подключении датчика BME280 к ESP32, прочитайте следующее руководство:

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;
  }
  else if (var == "TEMPERATURE"){
    return getTemperature();
  }
  else if (var == "HUMIDITY"){
    return getHumidity();
  }
  else if (var == "PRESSURE"){
    return getPressure();
  }
}

Эта функция сначала проверяет, является ли заполнитель STATE, который мы создали в HTML-файле.

if(var == "STATE"){

Если да, то в зависимости от состояния светодиода мы устанавливаем переменную ledState в ON или OFF.

if(digitalRead(ledPin)){
  ledState = "ON";
}
else{
  ledState = "OFF";
}

Наконец, мы возвращаем переменную ledState. Это заменяет заполнитель STATE на строковое значение ledState.

return ledState;

Если обнаруживается заполнитель %TEMPERATURE%, мы возвращаем температуру, вызывая ранее созданную функцию getTemperature().

else if (var == "TEMPERATURE"){
  return getTemperature();
}

То же самое происходит для заполнителей %HUMIDITY% и %PRESSURE% путём вызова соответствующих функций:

else if (var == "TEMPERATURE"){
  return getTemperature();
}
else if (var == "HUMIDITY"){
  return getHumidity();
}
else if (var == "PRESSURE"){
  return getPressure();
}

setup()

В setup() начните с инициализации Serial Monitor и настройки GPIO как выхода.

Serial.begin(115200);
pinMode(ledPin, OUTPUT);

Инициализируйте датчик BME280:

if (!bme.begin(0x76)) {
  Serial.println("Could not find a valid BME280 sensor, check wiring!");
  while (1);
}

Инициализируйте LittleFS:

// Initialize LittleFS
if(!LittleFS.begin()){
  Serial.println("An Error has occurred while mounting LittleFS");
  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());

Async Web Server

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

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

Когда сервер получает запрос на корневой URL /, он отправляет файл index.html клиенту. Первый аргумент — откуда искать файлы — в данном случае файлы сохранены в LittleFS.

Второй аргумент — путь к файлу в LittleFS, который будет обслуживаться при запросе корневого URL /.

String() — это MIME-тип. Передача пустой строки означает, что тип контента будет определён автоматически.

Аргумент false отключает кэширование, и, наконец, последний аргумент функции send() — это процессор. Это функция обратного вызова, которая позволяет динамически вставлять значения в HTML с использованием заполнителей шаблонов. Мы используем это, чтобы заменить заполнитель нужным значением — в данном случае ledState, а также для отправки обновлённых значений при обновлении веб-страницы.

Поскольку мы указали ссылку на CSS-файл в HTML-файле, клиент сделает запрос CSS-файла. Когда это произойдёт, CSS-файл будет отправлен клиенту:

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

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

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

В HTML-файле мы написали JavaScript-код, который запрашивает температуру, влажность и давление по маршрутам /temperature, /humidity, /pressure соответственно, каждые 10 секунд. Поэтому нам также нужно обработать, что происходит при получении запроса на этих маршрутах.

Нам просто нужно отправить обновлённые показания датчиков. Обновлённые показания возвращаются ранее созданными функциями getTemperature(), getHumidity() и getPressure().

Показания представляют собой обычный текст и должны быть отправлены как char, поэтому мы используем метод c_str().

server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(200, "text/plain", getTemperature().c_str());
});

server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(200, "text/plain", getHumidity().c_str());
});

server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(200, "text/plain", getPressure().c_str());
});

В конце мы используем метод begin() на объекте server, чтобы сервер начал прослушивать входящих клиентов.

server.begin();

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

Загрузка кода и файлов (образ файловой системы)

Теперь вам нужно загрузить файлы и код на вашу плату. Следуйте инструкциям ниже.

1) Сохраните ваш скетч Arduino.

2) Перейдите в Sketch > Show Sketch folder. Откроется папка, в которой сохранён ваш скетч.

ESP32 LittleFS веб-сервер Show Sketch Folder

3) Внутри этой папки создайте папку с именем data.

ESP32 веб-сервер создание папки Data

4) Сохраните файлы HTML и CSS внутри этой папки data.

Организация папок ESP32 LittleFS веб-сервер

5) Убедитесь, что у вас выбрана правильная плата (Tools > Board) и COM-порт (Tools > Port).

6) В зависимости от выбранной платы ESP32, вам может потребоваться выбрать нужный размер флэш-памяти (у некоторых плат нет этой опции, не беспокойтесь). В Arduino IDE в Tools > Flash size выберите нужный размер флэш-памяти (например, 4MB SPIFFS).

7) Затем загрузите файлы на плату ESP32. Нажмите [Ctrl] + [Shift] + [P] в Windows или [Cmd] + [Shift] + [P] на MacOS, чтобы открыть палитру команд. Найдите команду Upload LittleFS to Pico/ESP8266/ESP32 и нажмите на неё.

Upload LittleFS to Pico/ESP8266/ESP32

Важно: убедитесь, что Serial Monitor закрыт. В противном случае загрузка не удастся.

Через несколько секунд вы должны увидеть сообщение «Completed upload.». Файлы были успешно загружены в файловую систему ESP32.

LittleFS загрузка завершена

8) Теперь загрузите код на ESP32, нажав кнопку загрузки.

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

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

После загрузки кода откройте Serial Monitor на скорости 115200 бод.

Открытие Serial Monitor Arduino IDE 2 на скорости 115200 бод

Нажмите встроенную кнопку «RST» на ESP32. Должен отобразиться IP-адрес ESP32.

ESP32 LittleFS веб-сервер - получение IP-адреса в Serial Monitor

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

Демонстрация ESP32 LittleFS веб-сервер

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

ESP32 веб-сервер с файлами из LittleFS - управление выходами и мониторинг датчиков

Поздравляем! Вы успешно создали веб-сервер с файлами, сохранёнными в файловой системе LittleFS.

Устранение неполадок — Страница не найдена

Если вы получаете эту ошибку, вероятно, вы не загрузили файлы в файловую систему ESP32 LittleFS или они находятся в неправильном месте.

Вернитесь к разделу Загрузка кода и файлов (образ файловой системы) и убедитесь, что вы выполнили все шаги.

Заключение

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

То, что вы узнали здесь, можно применить к другим веб-серверам, использующим библиотеку ESPAsyncWebServer. Не забудьте создать папку с именем data внутри папки вашего скетча. Затем внутри этой папки сохраните файлы, которые хотите загрузить в файловую систему. Затем не забудьте загрузить образ файловой системы с помощью плагина LittleFS uploader.

Вот другие руководства, которые могут вам понравиться:

Примечание

Источник: Random Nerd Tutorials - ESP32 Web Server using LittleFS Filesystem. Авторы: Rui Santos & Sara Santos.