Описание
В этой лабораторной мы поднимем web сервер на esp8266
и сделаем на его основе "интернет-вещь" (IoT)

Теория
Микроконтроллеры семейства ESP
В наборе вы найдете плату разработчика с микроконтроллером esp8266
. Официально, он устарел в пользу esp32-C2
, но все еще продается и благодаря большой базе знаний будет актуален еще долго.
Важные практические особенности esp8266
:
- Цена - миска риса.
- wifi на борту (+ bluetooth для
esp32
) - БОльшая производительность относительно atmega.
За это приходится платить: - GPIO мало и ведут они себя странно - например некоторые пины требуют определенного логического сигнала на них при старте МК (иначе он не запустится).
- Большая часть пинов выдает сигнал при запуске. Единственными спокойными пинами являются
D1
иD2
- если вы управляете, скажем, нагрузкой, это ваш единственный безопасный вариант. - Номера пинов не совпадают с номерами GPIO (e.g GPIO12 = D6), в Arduino среде лучше обращаться к ним по константе:
digitalWrite(D6, LOW);
- Ужасный АЦП. Еще хуже он работает при включенном wifi.
Для работы c esp в Arduino IDE, ее нужно настроить
WiFi
WiFi может работать в режимах:
AP (Access Point)
- МК поднимет свою точку доступа, к которой мы сможем подключитьсяStation (STA)
- МК подключится к нашей точке доступа.
Точка поднимается элементарно:
#include <ESP8266WiFi.h>
void setup() {
...
WiFi.mode(WIFI_AP);
WiFi.softAP("SSID", "PASSWORD"); // ❗️парольн не меньше 8 символов
}
МК доступен по 192.168.4.1
.
WebServer

Когда мы вводим
192.168.4.1
в адресную строку, браузер отправляет http GET запрос на микроконтроллер. МК смотрит в свою файловую систему и возвращает index.html
- UI проекта, который мы заранее подготовили и загрузили - для простоты соберем в этом файле разметку (html) логику работы (js) и стилизацию (css). Теперь браузеру есть что показать. С этого момента страница контролирует все запросы к серверу самостельно.Изначально, страница не знает текущее состояние МК. Это мы предусмотрели, поэтому, первым делом javascript отправляет GET запрос на эндпоинт /state
, используя метод fetch(). На этот раз, сервер отвечает нам не файлом, а текстовыми данными, сериализованными в формате json
- как только мы их получили, подставляем их в нужные прямоугольники на экране.
Чтобы управлять микроконтроллером, javascript навешивает обработчики событий (например onClick()
) на кнопки. Обработчик посылает POST запрос (традиционно, запросы, которые хотят изменить состояние сервера, используют метод POST) так же с помощью метода fetch()
.
Такой подход называется SPA (single page application) - мы скачиваем приложение (тот самый index.html
) и оно живет своей жизнью - отправляет запросы на сервер, обновляет свое содержимое.
Реализация сервера
Мы будем использовать библиотеку ESPAsyncWebServer
Для парсинга json применяем ArduinoJson
Все подобные библиотеки выделяют методы для настройки эндпоинтов(часть url запроса) и их обработчиков:
// передаем обработчик как лямбду
server.on("/hi", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Hello, world");
});
// или передаем обработчик как объект
server.addHandler(handler);
// Не забываем про cors
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Content-Type");
Реализация клиента
Разработка браузерных приложений выходит за рамки курса. Для лабораторной подготовлен шаблон, который можно подправить под ваши нужды или взять как-есть (в этом случае, api вашего сервера должно строго соответствовать клиенту).
WebSocket
Представим теперь, что мы хотим управлять умным устройством с телефона, компьютера и дашборда прибитого к стене. Как дашборд узнает, что мы щелкнули реле с телефона и состояние изменилось?
Приложение может опрашивать сервер с некоторым интервалом (polling) - грустно и неэффективно. Гораздо интереснее, если бы сервер мог сам оповестить всех клиентов и произошедшем событии. Для этого существует протокол WebSocket
. Железка поднимает websocket-сервер, все наши браузерные приложения к нему подключаются. Если железяка обновила свое состояние, она отправляет сообщение с сериализованным состояниям (для простоты будем отправлять целиком) всем клиентам системы (в нашем случае всем открытым вкладкам с приложением), которые в свою очередь обновляют содержимое прямоугольников на экране.
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
...
void setup() {
...
server.addHandler(&ws);
...
}
void loop() {
...
if(state.changed) {
serializeState();
ws.textAll(buffer);
state.changed = false;
}
}
Задачи
5.1 - Поднимаем сервер
Поднять на esp8266
WiFi точку доступа и Web-сервер. GET запрос на эндпоинты /switch1
/switch2
должен включать/выключать соответствующие светодиоды и возвращать json true
/false
(boolean - это валидный json) - в какое состояние переключились. GET запрос на /state
должен возвращать сериализованное в json общее состояние МК:
{"switch1":false,"switch2":false,"rgb":{"r":0,"g":0,"b":0},"lightSensor":0}
Проверяем curl'ом или httpie.
5.2 - POST Запрос
Поднимаем POST
endpoint /rgb
который в теле запроса будет принимать json следующего содержания:
{r: 0-255, g: 0-255, b: 0-255}
И отображать этот цвет на ленте. С 3.3V логикой лента работает нестабильно, по-хорошему нужен конвертер логических уровней. На практике достаточно вызвать FastLED.show()
несколько раз подряд.
5.3 - WebSocket
Любое изменение состояния должно сериализовываться и отправляться всем подключенным ws клиентам. Изменение может порождать как один из клиентов (кнопки на UI), так и сам МК - для этого подключим к нему две кнопки.
5.4 - Железяки
Нужно подключить реле и датчик освещенности. Последний опрашивать в некотором интервале и оповещать всех участников по ws. Реле должны щелкать как по GET запросу, так и при нажатии по кнопкам, подключенным к МК.
5.5 - Загрузка файла
Нужно научиться загружать html
файл (наше приложение) на микроконтроллер. Для этого выводим отдельный эндпоинт /upload
. GET запрос на него должен вернуть захардкоженую форму с кнопкой upload. Загрузку файла по кнопке обработает POST метод сервера, который запишет файл на файловую систему используя LittleFS
. Теперь GET запрос на 192.168.4.1
должен возвращать наше приложение, которое микроконтроллер вытащил со своей файловой системы.