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()и переподключайтесь.