Обновление ESP32 по воздуху (OTA): загрузка кода по Wi-Fi через ArduinoOTA
ESP32 OTA позволяет загружать код по Wi-Fi без USB-кабеля: сетевой порт ArduinoOTA, веб-страница ElegantOTA, пароль, схема разделов и прерванные загрузки.
ESP32 OTA (Over-The-Air, обновление по воздуху) — это загрузка нового кода в плату по Wi-Fi вместо подключения USB-кабеля. Представь датчик под потолком, контроллер полива в саду или релейную плату, спрятанную в электрощитке: вместо того чтобы ради каждой мелкой правки тащить стремянку, снимать плату и подключать её к компьютеру, новая версия отправляется из Arduino IDE или браузера за несколько секунд. Плата в фоне записывает новую программу в память, проверяет её и сама перезагружается.
В этом руководстве шаг за шагом разберём, как OTA устроено внутри ESP32, три разных способа (ArduinoOTA для Arduino IDE, ElegantOTA для браузера и HTTPUpdate для загрузки с сервера), как выбрать правильную схему разделов, как защитить загрузку паролем, что будет, если загрузка прервётся, и как не потерять OTA в следующем скетче. Весь код скомпилирован и проверен на ядре ESP32 для Arduino.

Что такое ESP32 OTA и как оно работает?
Флеш-память ESP32 — не один сплошной блок: она разбита на части по карте, которая называется таблицей разделов. В таблице разделов с поддержкой OTA есть две одинаковые области для программы: app0 (ota_0) и app1 (ota_1). Пока плата работает из одной из них, новая программа записывается в другую. Маленький раздел otadata хранит, какая область запустится при следующей загрузке. Благодаря этому работающая программа во время загрузки не затрагивается, и плата не расстаётся со старой программой, пока новый код не будет полностью записан и проверен.
- Новая программа (скомпилированный файл .bin) приходит на плату по Wi-Fi, кусок за куском.
- ESP32 записывает каждый кусок в раздел программы, который сейчас не используется; работающий код тем временем продолжает делать своё дело.
- Когда весь файл получен, проверяются заголовок образа и контрольная сумма; повреждённый или неполный файл отклоняется.
- Если проверка прошла успешно, обновляется otadata: при следующей загрузке запустится новый раздел.
- Плата перезагружается и стартует с новой программой. Следующее обновление пойдёт в другой раздел; две области используются по очереди.
| Способ | Откуда отправляется код? | Лучше всего подходит для | Дополнительная библиотека |
|---|---|---|---|
| ArduinoOTA | Через сетевой порт в Arduino IDE | Разработки за рабочим столом в той же сети | Не нужна (входит в ядро) |
| ElegantOTA | Выбором .bin на странице /update в браузере | Обновления без IDE (другим человеком), загрузки с телефона | ElegantOTA |
| HTTPUpdate | Плата сама скачивает файл .bin с сервера | Многих устройств, удалённых устройств, автообновлений | Не нужна (входит в ядро) |
Схема разделов и объём флеш-памяти
Это самое недооценённое требование OTA: нужна вторая свободная область, куда записывать новую программу. Поэтому самая большая программа, которую можно загрузить по OTA, меньше даже половины флеш-памяти. Таблица разделов выбирается в Arduino IDE в меню Инструменты › Partition Scheme (схема разделов). На распространённых платах ESP32 DevKit с 4 МБ флеш-памяти (ESP32 Dev Module) доступны такие варианты:
| Partition Scheme (схема разделов) | Область программы | OTA | Файловая система (SPIFFS/LittleFS) |
|---|---|---|---|
| Default 4MB with spiffs | 2 × 1,25 МБ (1 310 720 байт) | Да | 1,375 МБ |
| Minimal SPIFFS (1.9MB APP with OTA) | 2 × 1,875 МБ (1 966 080 байт) | Да | 128 КБ |
| No OTA (2MB APP/2MB SPIFFS) | 1 × 2 МБ | Нет | 1,875 МБ |
| Huge APP (3MB No OTA/1MB SPIFFS) | 1 × 3 МБ | Нет | 896 КБ |
| Minimal (1.3MB APP/700KB SPIFFS) | 1 × 1,25 МБ (для плат с 2 МБ флеш-памяти) | Нет | 640 КБ |
Сколько места занимает программа, видно в выводе компиляции: наш первый пример с Wi-Fi и ArduinoOTA выводит «Sketch uses 758685 bytes (57%) … Maximum is 1310720 bytes» (скетч занимает 758685 байт из максимума 1310720). Максимум здесь — размер одной области программы в выбранной схеме. Если занято больше 90%, готовься скоро переходить на Minimal SPIFFS. И ещё одно важное правило: таблицу разделов нельзя изменить по OTA. Если схема изменилась, эту загрузку нужно сделать по USB; следующие обновления по OTA работают уже с новой таблицей. На платах с 8 МБ или 16 МБ флеш-памяти (например, на многих моделях ESP32-S3) правильный объём в меню Flash Size даёт гораздо более просторные области для OTA.
Чтобы увидеть, из какого раздела плата на самом деле работает и сколько места остаётся для OTA, загрузи небольшой скетч ниже. Библиотеки ему не нужны, он напрямую использует OTA-функции ESP-IDF:
1#include <esp_ota_ops.h>
2
3void setup() {
4 Serial.begin(115200);
5 delay(1000);
6 const esp_partition_t* running = esp_ota_get_running_partition();
7 const esp_partition_t* next = esp_ota_get_next_update_partition(NULL);
8
9 Serial.printf("Flash boyutu / Flash size: %u KB\n", ESP.getFlashChipSize() / 1024);
10 Serial.printf("Program boyutu / Sketch size: %u KB\n", ESP.getSketchSize() / 1024);
11 Serial.printf("OTA icin bos alan / Free space for OTA: %u KB\n", ESP.getFreeSketchSpace() / 1024);
12 Serial.printf("Calisan bolum / Running partition: %s (0x%06x)\n", running->label, running->address);
13 if (next != NULL) {
14 Serial.printf("Siradaki OTA bolumu / Next OTA partition: %s (0x%06x)\n", next->label, next->address);
15 } else {
16 Serial.println("OTA bolumu yok: bolum tablosunu degistir / No OTA partition: change the partition scheme");
17 }
18}
19
20void loop() {
21}Со схемой по умолчанию после первой загрузки по USB в выводе будет «Running partition: app0 (0x010000)» (текущий раздел) и «Next OTA partition: app1 (0x150000)» (следующий раздел OTA). Запусти код ещё раз после обновления по OTA, и будет видно, что теперь он работает из app1. Значение ESP.getFreeSketchSpace() — это размер самой большой программы, которую можно загрузить по OTA; если новый файл .bin больше, обновление не начнётся.
Способ 1: беспроводная загрузка из Arduino IDE через ArduinoOTA
Библиотека ArduinoOTA входит в ядро ESP32, так что устанавливать ничего не нужно. Подключившись к сети, плата сообщает о себе через mDNS; Arduino IDE это видит и добавляет в меню «Порт» сетевой порт. При нажатии «Загрузка» (Upload) IDE отправляет программу через этот сетевой порт вместо USB. На ESP32 служба OTA по умолчанию слушает порт 3232. Скетч ниже подключается к Wi-Fi, запускает OTA с паролем и в доказательство мигает встроенным светодиодом:
1#include <WiFi.h>
2#include <ArduinoOTA.h>
3
4const char* WIFI_SSID = "AgAdi"; // Wi-Fi adın / your Wi-Fi name
5const char* WIFI_PASS = "AgSifresi"; // Wi-Fi şifren / your Wi-Fi password
6const int LED_PIN = 2; // çoğu DevKit'te dahili LED / onboard LED on most DevKits
7
8unsigned long lastBlink = 0;
9
10void setup() {
11 Serial.begin(115200);
12 pinMode(LED_PIN, OUTPUT);
13
14 WiFi.mode(WIFI_STA);
15 WiFi.begin(WIFI_SSID, WIFI_PASS);
16 while (WiFi.status() != WL_CONNECTED) { // bağlanana kadar bekle / wait until connected
17 delay(500);
18 Serial.print(".");
19 }
20 Serial.println();
21 Serial.print("IP: ");
22 Serial.println(WiFi.localIP());
23
24 ArduinoOTA.setHostname("bluegrays-esp32"); // IDE'de görünen ad / name shown in the IDE
25 ArduinoOTA.setPassword("ota1234"); // yükleme parolası / upload password
26
27 ArduinoOTA.onStart([]() {
28 // Güncelleme başlıyor: motorları, röleleri güvenli konuma al / update starting: put motors and relays in a safe state
29 String type = (ArduinoOTA.getCommand() == U_FLASH) ? "program" : "dosya sistemi / filesystem";
30 Serial.println("OTA basladi / started: " + type);
31 });
32 ArduinoOTA.onEnd([]() {
33 Serial.println("\nOTA bitti, yeniden baslatiliyor / done, rebooting");
34 });
35 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
36 Serial.printf("Ilerleme / Progress: %u%%\r", progress * 100 / total);
37 });
38 ArduinoOTA.onError([](ota_error_t error) {
39 Serial.printf("Hata / Error[%u]: ", error);
40 if (error == OTA_AUTH_ERROR) Serial.println("parola / auth failed");
41 else if (error == OTA_BEGIN_ERROR) Serial.println("baslatilamadi, yer yok / begin failed, no space");
42 else if (error == OTA_CONNECT_ERROR) Serial.println("baglanti / connect failed");
43 else if (error == OTA_RECEIVE_ERROR) Serial.println("veri alinamadi / receive failed");
44 else if (error == OTA_END_ERROR) Serial.println("bitirilemedi / end failed");
45 });
46
47 ArduinoOTA.begin(); // OTA hizmetini başlat / start the OTA service
48}
49
50void loop() {
51 ArduinoOTA.handle(); // her turda çağır, unutma / call on every pass, never forget
52
53 // delay() yerine millis(): OTA isteklerini kaçırmamak için / millis() instead of delay() so OTA requests aren't missed
54 if (millis() - lastBlink >= 500) {
55 lastBlink = millis();
56 digitalWrite(LED_PIN, !digitalRead(LED_PIN));
57 }
58}| Строка | Что делает? |
|---|---|
| ArduinoOTA.setHostname("bluegrays-esp32") | Имя, которое видно в списке портов IDE и в сети. Если плат несколько, дай каждой своё имя. |
| ArduinoOTA.setPassword("ota1234") | Без пароля любой в твоей сети может загрузить код в твою плату. IDE спрашивает этот пароль перед загрузкой. |
| onStart / onEnd | Вызываются в начале и в конце обновления. Идеальное место, чтобы остановить моторы, выключить реле или вывести «Updating» на дисплей. |
| onProgress | Сообщает процент выполнения; по нему можно рисовать индикатор прогресса на LCD или OLED. |
| onError | Сообщает тип ошибки: пароль, нехватка места, соединение, приём или завершение. |
| ArduinoOTA.handle() | Проверяет входящие OTA-запросы. Если не вызывать её часто внутри loop(), плата не сможет ответить IDE. |
Шаг за шагом: первая загрузка по OTA
- Впиши в код значения WIFI_SSID и WIFI_PASS своей сети. ESP32 подключается только к сетям 2,4 GHz.
- В меню «Инструменты» выбери плату (например, ESP32 Dev Module) и Partition Scheme с поддержкой OTA (Default или Minimal SPIFFS).
- Первую загрузку сделай по USB-кабелю. Этот шаг обязателен, потому что в плате ещё нет кода OTA.
- Открой монитор порта на скорости 115200 бод и запиши IP-адрес, который выводит плата.
- Отключи USB-кабель и при желании запитай плату от другого источника. Через 10–20 секунд в меню «Инструменты › Порт» в разделе сетевые порты (network ports) появится строка вроде «bluegrays-esp32 at 192.168.1.x»; выбери её.
- Измени в коде задержку светодиода с 500 на 100 и нажми «Загрузка». Когда IDE спросит пароль, введи «ota1234».
- В панели «Вывод» (Output) появится процент выполнения, а в конце строка вроде «Done» или «Result: OK». Плата перезагрузится, и светодиод начнёт мигать быстро.
Есть одно ограничение, о котором стоит знать: сетевой порт служит только для загрузки, и монитор порта по беспроводной связи не работает. Чтобы видеть сообщения платы, либо снова подключи USB, либо выводи состояние на веб-страницу, дисплей или в MQTT-сообщения. При разработке за столом плату можно оставить на USB и всё равно загружать код по сети; так получаются и быстрые загрузки, и монитор порта одновременно.
Защита паролем и безопасность
Плата с открытой службой OTA — это дверь, через которую любой в твоей сети может загрузить код. В ArduinoOTA функция setPassword() хранит пароль в коде открытым текстом; если код будет выложен в общий доступ, можно передать MD5-хеш пароля через setPasswordHash(), и самого пароля в исходнике не будет. ElegantOTA защищает страницу /update именем пользователя и паролем (HTTP Basic Auth).
- Дай каждому устройству свой сложный пароль: значения вроде «1234» или «admin» пробуют первыми.
- Не открывай плату в интернет: выставлять OTA или страницу /update наружу через проброс портов на роутере — серьёзный риск; эти способы работают по незашифрованному HTTP.
- Для удалённых устройств используй HTTPUpdate: плата сама запрашивает обновление, поэтому достаточно исходящего соединения; если файл скачивается через интернет, лучше использовать HTTPS с WiFiClientSecure.
- На время обновления переходи в безопасное состояние: внутри onStart останавливай моторы и выключай реле нагревателей и насосов. Перезагрузка занимает несколько секунд, и всё это время состояние пинов может быть неопределённым.
Способ 2: загрузка .bin из браузера через ElegantOTA
ElegantOTA добавляет к веб-серверу на ESP32 аккуратную страницу /update. Её можно открыть с телефона или с любого компьютера без Arduino IDE, выбрать скомпилированный файл .bin и загрузить его; индикатор прогресса показывается прямо в браузере. Это самый практичный способ, когда устройство передаётся другому человеку или обновляется на месте установки.
- В Arduino IDE открой «Менеджер библиотек» (Library Manager), найди ElegantOTA (Ayush Sharma) и установи её.
- Отредактируй код ниже и в первый раз загрузи его по USB.
- Открой в браузере адрес, который выводится в монитор порта (например, http://192.168.1.42/update), и войди с именем пользователя «admin» и паролем «ota1234».
- Оставь режим Firmware (прошивка) и перетащи файл .bin; когда загрузка закончится, плата сама перезагрузится.
1#include <WiFi.h>
2#include <WebServer.h>
3#include <ElegantOTA.h>
4
5const char* WIFI_SSID = "AgAdi"; // Wi-Fi adın / your Wi-Fi name
6const char* WIFI_PASS = "AgSifresi"; // Wi-Fi şifren / your Wi-Fi password
7
8WebServer server(80);
9unsigned long otaProgressMillis = 0;
10
11void onOTAStart() {
12 Serial.println("OTA basladi / OTA started"); // röleleri kapat / switch relays off
13}
14
15void onOTAProgress(size_t current, size_t final) {
16 if (millis() - otaProgressMillis > 1000) { // saniyede bir yaz / print once per second
17 otaProgressMillis = millis();
18 Serial.printf("%u / %u bayt / bytes\n", current, final);
19 }
20}
21
22void onOTAEnd(bool success) {
23 Serial.println(success ? "OTA basarili / OTA successful" : "OTA hatasi / OTA failed");
24}
25
26void setup() {
27 Serial.begin(115200);
28 WiFi.mode(WIFI_STA);
29 WiFi.begin(WIFI_SSID, WIFI_PASS);
30 while (WiFi.status() != WL_CONNECTED) {
31 delay(500);
32 Serial.print(".");
33 }
34 Serial.println();
35 Serial.print("Adres / Address: http://");
36 Serial.print(WiFi.localIP());
37 Serial.println("/update");
38
39 server.on("/", []() {
40 server.send(200, "text/plain", "BlueGrays ESP32 - surum / version 1.0");
41 });
42
43 ElegantOTA.begin(&server, "admin", "ota1234"); // /update sayfası + kullanıcı/parola / /update page + user/password
44 ElegantOTA.onStart(onOTAStart);
45 ElegantOTA.onProgress(onOTAProgress);
46 ElegantOTA.onEnd(onOTAEnd);
47
48 server.begin();
49}
50
51void loop() {
52 server.handleClient(); // web isteklerini işle / handle web requests
53 ElegantOTA.loop(); // başarılı yüklemeden sonra yeniden başlatır / reboots after a successful upload
54}По умолчанию ElegantOTA работает с синхронным классом WebServer, который входит в ядро, поэтому вызовы server.handleClient() и ElegantOTA.loop() в loop() обязательны. Если в проекте уже используется ESPAsyncWebServer, можно выставить опцию библиотеки ELEGANTOTA_USE_ASYNC_WEBSERVER в 1 и работать с асинхронным сервером; как его настроить, рассказано в статье асинхронный веб-сервер и WebSocket на ESP32. Режим Filesystem (файловая система) на странице обновляет не программу, а образ LittleFS или SPIFFS (файлы веб-страницы, файлы настроек).
Где взять файл .bin: экспорт скомпилированного бинарного файла
Для ElegantOTA и HTTPUpdate нужен скомпилированный файл программы. В Arduino IDE выбери Скетч › Экспорт скомпилированного бинарного файла (Sketch › Export Compiled Binary). IDE скомпилирует программу и положит несколько файлов в папку build внутри папки скетча. Для OTA подходит только один из них:
| Файл | Содержимое | Для OTA? |
|---|---|---|
| myproject.ino.bin (файл приложения) | Только приложение (твоя программа) | Да, загружать нужно именно его |
| myproject.ino.bootloader.bin (файл загрузчика) | Загрузчик | Нет |
| myproject.ino.partitions.bin (файл таблицы разделов) | Таблица разделов | Нет |
| myproject.ino.merged.bin (ядро 3.x, объединённый файл) | Загрузчик, таблица и программа вместе | Нет, его записывают только по USB по адресу 0x0 |
Способ 3: автоматические обновления с сервера через HTTPUpdate
Представь, что по дому расставлены пять плат с датчиками. Вместо того чтобы загружать код в каждую из IDE, новый файл .bin кладётся на сервер, а платы скачивают его сами. Библиотека HTTPUpdate, которая входит в ядро ESP32, делает это одной строкой. В примере ниже обновление начинается по нажатию кнопки BOOT (GPIO 0) на плате:
1#include <WiFi.h>
2#include <HTTPUpdate.h>
3
4const char* WIFI_SSID = "AgAdi";
5const char* WIFI_PASS = "AgSifresi";
6// Bilgisayarındaki ya da sunucundaki .bin dosyası / the .bin file on your computer or server
7const char* FIRMWARE_URL = "http://192.168.1.50:8000/firmware.bin";
8const int BUTTON_PIN = 0; // karttaki BOOT butonu / the BOOT button on the board
9
10void setup() {
11 Serial.begin(115200);
12 pinMode(BUTTON_PIN, INPUT_PULLUP);
13 WiFi.begin(WIFI_SSID, WIFI_PASS);
14 while (WiFi.status() != WL_CONNECTED) delay(500);
15 Serial.println("Hazir: guncellemek icin BOOT'a bas / Ready: press BOOT to update");
16}
17
18void loop() {
19 if (digitalRead(BUTTON_PIN) == LOW) { // butona basıldı / button pressed
20 WiFiClient client;
21 httpUpdate.rebootOnUpdate(true); // başarılıysa yeniden başlat / reboot on success
22 t_httpUpdate_return ret = httpUpdate.update(client, FIRMWARE_URL);
23
24 switch (ret) {
25 case HTTP_UPDATE_FAILED:
26 Serial.printf("Hata / Error (%d): %s\n", httpUpdate.getLastError(),
27 httpUpdate.getLastErrorString().c_str());
28 break;
29 case HTTP_UPDATE_NO_UPDATES:
30 Serial.println("Guncelleme yok / No update");
31 break;
32 case HTTP_UPDATE_OK:
33 Serial.println("Tamam / OK"); // buraya genelde gelinmez, kart yeniden başlar / usually not reached, the board reboots
34 break;
35 }
36 delay(1000);
37 }
38}Чтобы попробовать, положи файл .bin в папку на компьютере под именем firmware.bin и запусти в этой папке команду python3 -m http.server 8000; IP-адрес в коде замени на локальный IP своего компьютера. В реальном применении кнопку заменяют таймером: например, раз в час плата читает небольшой файл «version.txt» и, если номер версии на сервере выше её собственного, запускает обновление. Так она ещё и не застрянет, раз за разом скачивая один и тот же файл и перезагружаясь.
Что будет, если связь оборвётся во время OTA?
Короткий ответ: плата не превратится в кирпич. Новая программа записывается в неиспользуемый раздел, а загрузочный раздел переключается только после проверки всего файла, поэтому прерванная загрузка оставляет плату работать со старой программой. В IDE появится «Error Uploading», в ArduinoOTA — OTA_RECEIVE_ERROR, в ElegantOTA — неудачный результат; устрани причину и повтори загрузку. Если посреди загрузки пропадёт питание, история та же: плата загрузит старую программу. Единственный реальный риск — ошибка в самой новой программе: если загрузить программу, которая не подключается к Wi-Fi или не содержит кода OTA, для следующего обновления снова понадобится кабель.
- Слабый сигнал Wi-Fi: если загрузка зависает где-то на 30–60%, поднеси плату ближе к роутеру или возьми модуль с внешней антенной. Если WiFi.RSSI() в мониторе порта хуже -75 dBm, жди обрывов; подробности в статье ESP32 не подключается к Wi-Fi.
- Не хватает питания: запись во флеш и передача по Wi-Fi потребляют ток одновременно. Слабый USB-порт или тонкий кабель могут перезагрузить плату во время загрузки; это проявляется как ошибка просадки питания (brownout). Используй надёжный источник 5 V, способный выдать не меньше 500 mA.
- Долгие ожидания внутри loop(): задержки вроде delay(5000) откладывают вызов handle(), и IDE сообщает «No response from the ESP» (ESP не отвечает). Отсчитывай время через millis().
- Брандмауэр: в ArduinoOTA при старте загрузки ESP32 сама подключается обратно к компьютеру. Если брандмауэр Windows или антивирус блокирует это входящее соединение, загрузка сразу же срывается; в окне разрешений, которое появляется при первой попытке, разреши доступ для частных сетей.
Как сохранить OTA в каждом новом скетче
Самое частое разочарование с OTA выглядит так: по OTA загружается совсем другой проект, в нём нет кода ArduinoOTA, и плата больше не появляется как сетевой порт. Новая программа полностью заменяет старую; OTA — не что-то, что «остаётся на плате», каждая программа должна нести его сама. Чтобы снова не лезть на стремянку к устройству под потолком, сделай привычкой эти правила:
- Используй шаблон: вынеси подключение к Wi-Fi и настройки ArduinoOTA в отдельную функцию (например, setupOTA()) и начинай каждый новый проект с этого файла.
- Ставь вызов handle() в самое начало loop() и никогда не оставляй внутри loop() циклов, которые надолго всё блокируют.
- Переподключайся, если Wi-Fi пропал: используй WiFi.setAutoReconnect(true) или регулярно проверяй соединение; плата без связи не может получить обновление.
- Добавь окно обслуживания в проекты с глубоким сном: спящая плата не слышит OTA-запрос. Напиши режим, в котором плата перед сном 60 секунд ждёт OTA, если при старте зажата кнопка или пришёл флаг по MQTT. О режимах сна читай в статье глубокий сон ESP32 (Deep Sleep).
- Сначала проверь на второй плате на столе: перед отправкой на устройство на месте установки запусти тот же код на плате рядом; если она подключается к Wi-Fi и появляется как сетевой порт, отправлять безопасно.
- Выводи номер версии: держи константу FW_VERSION в начале кода и показывай её на веб-странице или дисплее; так всегда будет понятно, какая версия работает на какой плате.
OTA на ESP8266 и Raspberry Pi Pico W
Код ArduinoOTA и ElegantOTA из этого руководства с небольшими изменениями работает и на платах ESP8266 (NodeMCU, Wemos D1 Mini): вместо WiFi.h используется ESP8266WiFi.h, вместо WebServer — ESP8266WebServer, а порт OTA — 8266. На платах ESP8266 с 4 МБ флеш-памяти выбирай в Flash Size вариант, который оставляет достаточно места для программы под OTA. На Raspberry Pi Pico W поддержку ArduinoOTA даёт ядро arduino-pico; там новая программа сначала скачивается в файловую систему LittleFS и при загрузке копируется на своё место. Поэтому на Pico W в меню Flash Size нужно зарезервировать под файловую систему область больше, чем программа. В MicroPython готового инструмента для OTA нет; можно написать небольшие скрипты, которые скачивают и заменяют файлы .py по сети, но это не проверяемое обновление с двумя разделами, как на ESP32.
Идеи проектов с OTA
- Датчик на потолке или стене: меняй пороги платы, которая измеряет температуру, влажность и движение, не прикасаясь к кабелю.
- Реле для умного дома: обновляй по OTA правила расписания платы реле в электрощитке; внутри onStart переводи реле в безопасное состояние.
- Устройства для Home Assistant: добавляй по сети новые функции датчикам, подключённым к Home Assistant по MQTT.
- Контроллер полива в саду: меняй время полива и порог влажности почвы, не открывая водонепроницаемый корпус.
- Индикатор прогресса на LCD: выводи значение onProgress в процентах и полоской на LCD 16x2; именно это делает проект «Обновление ESP32 по воздуху (OTA)» в BlueGrays.
- Обновление парка устройств: пусть несколько плат каждую ночь проверяют через HTTPUpdate один и тот же сервер на наличие новой версии.
Частые ошибки и как их исправить
| Симптом | Вероятная причина | Решение |
|---|---|---|
| В меню «Порт» нет сетевого порта | Плата в другой сети, mDNS заблокирован, в коде не вызывается ArduinoOTA.begin() | Используй одну и ту же сеть 2,4 GHz, перезапусти IDE, проверь, что IP выводится в монитор порта |
| «No response from the ESP» (ESP не отвечает) | Долгий delay() в loop(), плата занята или мешает брандмауэр | Используй millis() вместо delay(), разреши IDE в брандмауэре |
| «Authentication Failed» (ошибка аутентификации) | Неверный пароль OTA | Введи значение setPassword из кода; если пароль забыт, один раз загрузи код по USB |
| «Not Enough Space» / Begin Failed | Схема Huge APP или No OTA, программа не помещается во вторую область | Выбери Minimal SPIFFS и один раз загрузи код по USB; уменьши программу |
| Загрузка останавливается на полпути | Слабый сигнал, просадка питания, обрыв соединения | Поднеси плату ближе к роутеру, возьми надёжный источник 5 V, попробуй ещё раз; старая программа продолжает работать |
| После загрузки плата не подключается к сети | В новом коде нет Wi-Fi или OTA, неверный SSID | Исправь по USB; дальше начинай каждый проект с OTA-шаблона |
| «Wrong Magic Byte» или ошибка активации в ElegantOTA | Выбран merged.bin, bootloader.bin или файл, скомпилированный для другого чипа | Загружай только файл myproject.ino.bin |
OTA — ключ к тому, чтобы снять проекты на ESP32 со стола и установить их в реальном месте: если один раз всё правильно настроить, исправления, новые функции и изменения порогов приходят по воздуху за секунды. В приложении BlueGrays есть проект «Обновление ESP32 по воздуху (OTA)» (с выводом IP и прогресса на LCD), а также проекты с подключением к Wi-Fi, асинхронным веб-сервером, mDNS и NTP — у каждого есть схема подключения и код, шаг за шагом.
Частые вопросы
Что такое ESP32 OTA?
OTA (Over-The-Air, по воздуху) — это загрузка новой программы в ESP32 по Wi-Fi вместо USB-кабеля. Плата записывает новый код в неиспользуемый раздел программы, проверяет его и перезагружается с новой версией. Первый скетч с поддержкой OTA нужно один раз загрузить по USB.
Почему сетевой порт ESP32 не появляется в Arduino IDE?
Чаще всего причина в том, что компьютер и плата в разных сетях, гостевая сеть изолирует устройства или вызов ArduinoOTA.begin() в коде так и не выполняется. Проверь в мониторе порта, что плата получила IP, перезапусти IDE и подожди несколько секунд.
Какую схему разделов выбрать для ESP32 OTA?
На платах с 4 МБ флеш-памяти выбирай Default (область программы 2 × 1,25 МБ) или, если программа большая, Minimal SPIFFS (2 × 1,875 МБ). В Huge APP и No OTA нет второй области программы, поэтому OTA с ними не работает. Первую загрузку после смены схемы нужно сделать по USB.
Может ли прерванная загрузка по OTA превратить ESP32 в кирпич?
Нет. Новая программа записывается в пустой раздел, а загрузочный раздел переключается только после проверки всего файла. Если пропадёт связь или питание, плата загрузит старую программу, и загрузку можно просто повторить.
Можно ли пользоваться монитором порта при загрузке по OTA?
Сетевой порт служит только для загрузки кода; монитор порта по беспроводной связи не работает. Чтобы видеть сообщения, можно оставить плату подключённой к USB или выводить информацию на веб-страницу, дисплей или через MQTT.
Как задать пароль OTA на ESP32?
В ArduinoOTA перед begin() вызывается ArduinoOTA.setPassword("password"); IDE спрашивает этот пароль перед загрузкой. Если пароль не должен быть виден в коде, передай его MD5-хеш через setPasswordHash(). В ElegantOTA страница защищается вызовом begin(&server, "user", "password").
Что собрать после прочтения
Все проекты
Обновление ESP32 по воздуху (OTA): беспроводная установка прошивки (с экраном LCD)
В этом проекте ты узнаешь, как загружать новую прошивку в ESP32 по Wi-Fi без USB-кабеля. С библиотекой ArduinoOTA ESP32 становится видна в сети и автоматически появляется как bluegrays-ota на вкладке «Сетевой порт» в Arduino IDE. Первая загрузка выполняется по USB, а все следующие обновления — без проводов: это важно для устройств в эксплуатации. I2C LCD показывает состояние Wi-Fi, IP-адрес, имя хоста, процент загрузки OTA и сообщения об ошибках.

Подключение ESP32 к Wi-Fi в режиме STA (с экраном LCD)
В этом проекте ESP32 надёжно и устойчиво к сбоям подключается к домашней сети Wi-Fi в режиме станции (STA). SSID и пароль хранятся в отдельном файле secrets.h, чтобы не утекли в Git; настроено автоматическое переподключение, а уровень сигнала RSSI и IP-адрес выводятся на I2C LCD-экран. Встроенный светодиод служит индикатором состояния. Это менеджер подключения уровня реальных устройств.

Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)
В этом проекте ESP32 превращается в асинхронный веб-сервер, которым можно управлять с телефона или компьютера в той же сети Wi-Fi. Благодаря библиотеке ESPAsyncWebServer сервер может обрабатывать несколько запросов одновременно (в отличие от классического WebServer.h, который блокируется на одном запросе). Открыв IP-адрес ESP32 в браузере, ты нажимаешь кнопки ON/OFF (маршруты /on и /off) и включаешь и выключаешь светодиод на GPIO 5.

mDNS на ESP32: доступ к устройству через bluegrays-esp.local (с экраном LCD)
В этом проекте к ESP32 добавляется служба mDNS (Multicast DNS), и к устройству можно обращаться по понятному имени вроде bluegrays-esp.local вместо IP-адреса. Даже если IP, выданный DHCP, меняется, устройство всегда доступно по одному имени. На устройстве также работает маленький веб-сервер, через который по адресу http://bluegrays-esp.local/ из браузера отправляются команды светодиоду. I2C LCD показывает имя хоста, IP-адрес и состояние светодиода.

Счётчик на WebSocket с ESP32 (2 кнопки + LCD + веб в реальном времени)
В этом проекте две кнопки, подключённые к ESP32 (GPIO 5 увеличивает, GPIO 4 уменьшает), меняют счётчик. Значение сразу обновляется и на I2C LCD 16x2, и — через поддержку WebSocket в ESPAsyncWebServer — во всех подключённых браузерах без перезагрузки страницы. Вместо опроса по HTTP используется одно постоянное соединение, и ESP32 отправляет новое значение всем через ws.textAll().

Точное время из интернета через NTP на ESP32
ESP32 подключается к Wi-Fi и получает точное время с точностью до миллисекунд от серверов NTP (Network Time Protocol). Благодаря функции configTzTime() автоматически применяется часовой пояс Турции (TRT, UTC+3), а в странах с летним временем переходы обрабатываются автоматически по строке POSIX TZ. Время выводится в монитор порта и на необязательный I2C LCD. configTzTime() запускает службу SNTP, которая периодически пересинхронизирует часы.

ESP32 HTTPClient + API погоды (с экраном LCD)
В этом проекте ESP32 через HTTPClient.h делает вызов REST API к сервису погоды (wttr.in) через интернет. Полученный ответ в JSON разбирается с помощью ArduinoJson v7, а город, температура, влажность, погода и ветер выводятся на I2C LCD на турецком и английском. wttr.in бесплатен и не требует ключа API — достаточно указать любое название города, чтобы получить текущую погоду. Данные автоматически обновляются каждые 30 минут.

Глубокий сон ESP32: экономия батареи (OLED + счётчик в RTC RAM)
Режим глубокого сна (Deep Sleep) у ESP32 снижает потребление до ~10 µA, выключая процессор и большую часть периферии, — это важно для IoT-устройств на батарейках. В этом проекте используются три источника пробуждения: таймер (15 секунд), внешний пин (EXT0 — кнопка GPIO 33) и касание (T0/GPIO 4). Переменные с RTC_DATA_ATTR сохраняются во время глубокого сна — счётчики загрузок, пробуждений по таймеру и по кнопке ведутся непрерывно.
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

