Добавить в избранное

ESP32 веб-сервер: страница управления устройством по Wi-Fi

Чтение ≈ 4 мин

Поднимаем веб-сервер на ESP32: подключение к Wi-Fi, WebServer-библиотека, HTML-страница с кнопками, REST-эндпоинты для управления светодиодом и чтения датчиков — полноценный интерфейс за полчаса.

ESP32 как веб-сервер

ESP32 — мощный микроконтроллер со встроенным Wi-Fi: двухъядерный 240 МГц, полмегабайта RAM, десятки GPIO. Подняв на нём веб-сервер, вы получаете управление устройством из браузера любого телефона в сети — без облаков и приложений.

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

#include <WiFi.h>

const char* SSID = "MyWiFi";
const char* PASS = "password";

void setup() {
    Serial.begin(115200);
    WiFi.begin(SSID, PASS);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.print("IP: ");
    Serial.println(WiFi.localIP());   // запоминаем — сюда пойдёт браузер
}

В сети устройство получает IP по DHCP — заходите на него из браузера. Для статического IP:

IPAddress ip(192,168,1,50), gw(192,168,1,1), mask(255,255,255,0);
WiFi.config(ip, gw, mask);
WiFi.begin(SSID, PASS);

Веб-сервер: страница с кнопками

Библиотека WebServer — встроенная, роутинг как у нормального фреймворка:

#include <WiFi.h>
#include <WebServer.h>

WebServer server(80);
const int LED = 2;          // встроенный светодиод ESP32

String page() {
    bool on = digitalRead(LED);
    String html = "<!DOCTYPE html><html><body>";
    html += "<h1>ESP32</h1>";
    html += "<p>LED: " + String(on ? "ON" : "OFF") + "</p>";
    html += "<a href='/on'><button>Вкл</button></a> ";
    html += "<a href='/off'><button>Выкл</button></a>";
    html += "</body></html>";
    return html;
}

void setup() {
    pinMode(LED, OUTPUT);
    WiFi.begin("SSID", "pass");
    while (WiFi.status() != WL_CONNECTED) delay(500);

    server.on("/", []() { server.send(200, "text/html", page()); });
    server.on("/on", []() {
        digitalWrite(LED, HIGH);
        server.sendHeader("Location", "/");
        server.send(303);
    });
    server.on("/off", []() {
        digitalWrite(LED, LOW);
        server.sendHeader("Location", "/");
        server.send(303);
    });
    server.begin();
}

void loop() {
    server.handleClient();   // обязательно в каждом цикле!
}

server.handleClient() обрабатывает входящие запросы — без него сервер мёртв.

REST API для AJAX

Для «умного» интерфейса без перезагрузки страницы отдают JSON:

server.on("/api/led", HTTP_GET, []() {
    server.send(200, "application/json",
        "{\"state\":" + String(digitalRead(LED)) + "}");
});

server.on("/api/led", HTTP_POST, []() {
    String body = server.arg("plain");
    digitalWrite(LED, body.indexOf("\"on\"") >= 0 ? HIGH : LOW);
    server.send(200, "application/json", "{\"ok\":true}");
});

На странице — fetch('/api/led', {method:'POST', body:'{"on":1}'}) — и интерфейс реагирует мгновенно.

Чтение датчика через API

server.on("/api/sensors", []() {
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    server.send(200, "application/json",
        "{\"temp\":" + String(t,1) + ",\"hum\":" + String(h,0) + "}");
});

Страница по таймеру опрашивает /api/sensors и обновляет цифры — простая панель мониторинга.

mDNS: имя вместо IP

Чтобы не запоминать IP, поднимите mDNS — устройство будет доступно как http://myesp32.local:

#include <ESPmDNS.h>
if (MDNS.begin("myesp32")) {
    Serial.println("http://myesp32.local");
}

Wi-Fi в режиме точки доступа

ESP32 может не подключаться к роутеру, а сам быть сетью:

WiFi.softAP("ESP32-Device", "12345678");
Serial.println(WiFi.softAPIP());   // 192.168.4.1 — заходить сюда

Удобно для устройств «в поле» без роутера — телефон цепляется прямо к ESP.

Типичные проблемы

  • server.handleClient() забыт — сервер не отвечает вообще.
  • Медленно/тормозит: String в HTML фрагментирует heap — для больших страниц используйте server.send чанками или PROGMEM.
  • IP меняется после перезагрузки: настройте статический WiFi.config или резервацию на роутере.
  • Телефон не находит .local: mDNS работает в Android только через браузеры с поддержкой; для надёжности используйте IP или hostname на роутере.
  • Падает при подключении клиентов: heap заканчивается — минимизируйте String, используйте char буферы.

Итог

ESP32 + WebServer — это Wi-Fi + HTTP за двадцать строк: роуты на /api/*, HTML-страница, JSON для AJAX и mDNS для имени. С этого начинается умный дом: лампа, розетка, термостат — всё с интерфейсом в браузере без всяких облаков.

Полный пример: веб-панель управления

#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>

WebServer server(80);
DHT dht(4, DHT22);
const int RELAY = 5;

const char* HTML = R"rawliteral(
<!DOCTYPE html><html><head>
<meta charset="utf-8"><title>ESP32</title>
<style>body{font-family:sans-serif;max-width:400px;margin:40px auto}</style>
</head><body>
<h1>Комната</h1>
<p>Температура: <b id="t">--</b>°C, влажность: <b id="h">--</b>%</p>
<button onclick="fetch('/relay/toggle')">Переключить реле</button>
<script>
setInterval(async () => {
    const r = await fetch('/api/sensors');
    const j = await r.json();
    document.getElementById('t').textContent = j.temp;
    document.getElementById('h').textContent = j.hum;
}, 2000);
</script>
</body></html>
)rawliteral";

void setup() {
    pinMode(RELAY, OUTPUT);
    dht.begin();
    WiFi.begin("SSID", "pass");
    while (WiFi.status() != WL_CONNECTED) delay(500);
    Serial.println(WiFi.localIP());

    server.on("/", []() { server.send(200, "text/html", HTML); });
    server.on("/api/sensors", []() {
        server.send(200, "application/json",
            "{\"temp\":" + String(dht.readTemperature(),1) +
            ",\"hum\":" + String(dht.readHumidity(),0) + "}");
    });
    server.on("/relay/toggle", []() {
        digitalWrite(RELAY, !digitalRead(RELAY));
        server.send(200, "text/plain", "ok");
    });
    server.begin();
}
void loop() { server.handleClient(); }

Аутентификация

Защитите страницу паролем:

server.on("/", []() {
    if (!server.authenticate("admin", "pass123"))
        return server.requestAuthentication();
    server.send(200, "text/html", HTML);
});

Базовая HTTP-аутентификация — минимум для устройства в сети.

SPIFFS/LittleFS для статики

Большие страницы — файлы во внутренней файловой системе:

server.serveStatic("/", LittleFS, "/index.html");
server.serveStatic("/style.css", LittleFS, "/style.css");

Websocket для реального времени

Для живого графика/лога — WebSocketsServer: браузер получает пуши от ESP без опроса.

Частые проблемы

  • server.handleClient() забыт — сервер мёртв.
  • String-конкатенация — фрагментация heap при больших страницах; PROGMEM/send_P.
  • IP меняется — WiFi.config статический или mDNS.
  • Wi-Fi обрывается — проверяйте WiFi.status() и переподключайтесь.
Поделиться
Понравился материал?

Комментарии

Добавить комментарий