Wi-Fi · обновление
Прошивка по воздуху: обновление Arduino без кабеля
Устройство вмуровано в стену, стоит на чердаке или уехало к заказчику — а программу надо поправить. Разбираем, как плата обновляется по Wi-Fi: три способа, чем это ограничено, что происходит при обрыве связи и почему из четырёх мегабайтов памяти скетчу достаётся один. Три скетча собраны компилятором.
Короткий ответ. Плата с Wi-Fi умеет принимать новую программу по сети: в среде она появляется как ещё один порт, и «Загрузить» работает как обычно. Три условия. Первое: самый первый скетч всё равно заливается кабелем. Второе: Arduino Uno и Nano так не умеют — нужна плата на ESP. Третье: скетч должен быть меньше половины отведённой ему памяти, потому что старая прошивка остаётся на месте, пока новая не принята целиком.
Зачем это нужно и чем ограничено
Пока поделка лежит на столе, кабель никому не мешает. Ценность обновления по воздуху становится очевидной в тот момент, когда устройство переезжает на своё место: в корпус, за шкаф, на чердак, в теплицу. Открывать корпус ради одной правки в программе — занятие, которое быстро отбивает желание что-либо улучшать.
Ограничений пять, и все они разумные.
| Ограничение | Что за ним стоит |
|---|---|
| Первый раз — только кабелем | Плата умеет принимать прошивку по воздуху только тогда, когда в ней уже работает программа, которая это умеет. Значит, самый первый скетч всё равно заливается проводом |
| Только платы с Wi-Fi | На Arduino Uno, Nano и Mega обновления по воздуху не бывает: у них нет ни радио, ни свободной памяти под вторую прошивку |
| Скетч не больше половины памяти | Старая прошивка должна оставаться на месте, пока новая не принята полностью. Отсюда потолок размера и знаменитое «скетч слишком большой» |
| Обновляется программа, а не всё подряд | Файлы (картинки, страницы, настройки) лежат отдельно и заливаются отдельным действием. Их обновление тоже возможно, но это другой файл и другая кнопка |
| Плата должна быть в сети и не занята | Если программа висит в долгом цикле и не даёт себя обслужить, плата не услышит, что её хотят перепрошить |
Отдельно про Arduino Uno, потому что вопрос задают постоянно. Обновить её по воздуху нельзя, и дело не в отсутствии Wi-Fi: даже если приделать к ней радио, места под вторую прошивку в её тридцати двух килобайтах просто нет. Если нужна возможность обновлять устройство удалённо — берите плату на ESP сразу.
Куда девается память: почему из 4 МБ скетчу достаётся один
Это главное недоумение темы. На плате написано «4 МБ», а среда ругается, что скетч размером в мегабайт слишком большой. Никакого обмана здесь нет.
Логика простая и правильная: пока новая прошивка едет по сети, старая обязана работать. Значит, в памяти должны одновременно поместиться обе. У ESP32 для этого заранее отведены два одинаковых места, у ESP8266 новая прошивка пишется в свободное место над старой — но требование то же самое.
У ESP8266 есть и вторая, более жёсткая причина. Сам чип видит код через окно размером примерно в мегабайт, поэтому скетч больше мегабайта не соберётся вообще — хоть с обновлением по воздуху, хоть без него, хоть на плате с шестнадцатью мегабайтами памяти. Подробнее про это — на странице ESP8266.
Практический вывод: если скетч подобрался к половине доступной памяти, у вас есть три выхода. Уменьшить программу (обычно помогает вынести страницы и картинки в файлы). Выбрать в настройках платы схему памяти с меньшей файловой системой. Или отказаться от обновления по воздуху и выбрать схему, где вся память отдана программе — такие варианты в списке тоже есть.
Подробный разбор того, куда вообще уходит память платы, есть в отдельной статье, а особенности памяти ESP8266 — на её странице.
Три способа обновиться без кабеля
Разница между ними не в технологии, а в том, кто будет нажимать кнопку. Пока устройство ваше и вы его дорабатываете — удобнее всего среда. Когда устройство отдано человеку, который не программирует, — страница в браузере. Когда устройств много и они разбросаны — пусть проверяют обновления сами.
Способ первый: плата как сетевой порт
Самый привычный. Один раз заливаете кабелем скетч, в котором есть поддержка обновления, — и дальше плата видна в списке портов рядом с обычными, только помечена как сетевая. Выбираете её, нажимаете «Загрузить», вводите пароль.
// Обновление прошивки по воздуху. После заливки этого скетча кабелем
// плата появляется в среде как сетевой порт, и дальше её можно
// перепрошивать по Wi-Fi.
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <ArduinoOTA.h>
const char WIFI_SSID[] = "имя вашей сети";
const char WIFI_PASS[] = "пароль от сети";
// Под этим именем плата будет видна в списке портов.
const char OTA_NAME[] = "plata-kuhnya";
// Пароль обязателен: без него перепрошить вашу плату сможет любой,
// кто находится в той же сети.
const char OTA_PASS[] = "pridumayte-svoy";
void setup() {
Serial.begin(115200);
delay(200);
Serial.println();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Адрес платы: ");
Serial.println(WiFi.localIP());
ArduinoOTA.setHostname(OTA_NAME);
ArduinoOTA.setPassword(OTA_PASS);
ArduinoOTA.onStart([]() {
Serial.println("Приём новой прошивки начался");
});
ArduinoOTA.onProgress([](unsigned int done, unsigned int total) {
Serial.print(done * 100 / total);
Serial.println(" процентов");
});
ArduinoOTA.onEnd([]() {
Serial.println("Готово, перезапускаюсь");
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.print("Ошибка обновления: ");
if (error == OTA_AUTH_ERROR) {
Serial.println("не принят пароль");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("не хватило места во флеш-памяти");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("не установилось соединение");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("оборвалась передача");
} else {
Serial.println("не удалось завершить запись");
}
});
ArduinoOTA.begin();
Serial.println("Готов принимать прошивку по воздуху");
}
void loop() {
// Без этой строчки плата не услышит, что её хотят перепрошить.
ArduinoOTA.handle();
}
Два момента, которые определяют, будет ли это работать. Первый: ArduinoOTA.handle() обязан вызываться в loop() постоянно. Если программа надолго уходит в свои дела, плата просто не услышит, что её вызывают. Второй: пароль не роскошь. Без него залить в вашу плату любую программу сможет каждый, кто подключён к той же сети, — включая гостя, которому вы дали пароль от Wi-Fi.
Имя, заданное в скетче, — это то, под которым плата покажется в списке. Если плат несколько, давайте им разные имена: иначе выбрать нужную будет решительно невозможно.
Способ второй: страница обновления в браузере
Тот случай, когда устройство отдано человеку, у которого нет ни среды, ни желания в ней разбираться. Он открывает адрес платы, выбирает присланный файл и нажимает кнопку. Всё.
Скетч ниже опирается на обычный веб-сервер, про который написано в предыдущей статье, и добавляет к нему приём файла.
// Обновление через страницу в браузере: открываете адрес платы,
// выбираете файл прошивки и нажимаете кнопку. Среда не нужна вовсе -
// обновить устройство сможет и человек, который не программирует.
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
#else
#include <WiFi.h>
#include <WebServer.h>
#include <Update.h>
WebServer server(80);
#endif
const char WIFI_SSID[] = "имя вашей сети";
const char WIFI_PASS[] = "пароль от сети";
// Логин и пароль на страницу обновления. Без них файл в вашу плату
// сможет залить любой, кто есть в этой же сети.
const char USER[] = "admin";
const char PASS[] = "pridumayte-svoy";
// Внутри страницы только одинарные кавычки - экранировать нечего.
const char FORM_HTML[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang='ru'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Обновление платы</title>
<style>body{font-family:sans-serif;margin:24px;max-width:420px}</style>
</head>
<body>
<h1>Обновление прошивки</h1>
<p>Выберите файл с расширением bin, собранный для этой платы.</p>
<form method='POST' action='/update' enctype='multipart/form-data'>
<input type='file' name='firmware' accept='.bin'>
<p><input type='submit' value='Залить'></p>
</form>
</body>
</html>
)rawliteral";
bool allowed() {
if (server.authenticate(USER, PASS)) {
return true;
}
server.requestAuthentication();
return false;
}
void handleForm() {
if (!allowed()) {
return;
}
server.send_P(200, "text/html; charset=utf-8", FORM_HTML);
}
// Ответ отправляем ПОСЛЕ приёма файла: если запись прошла, плата
// перезагрузится и уже с новой прошивкой.
void handleDone() {
if (!allowed()) {
return;
}
bool ok = !Update.hasError();
server.send(200, "text/plain", ok ? "Готово, перезапускаюсь" : "Не получилось");
delay(500);
ESP.restart();
}
// Сюда файл приходит кусками, по мере загрузки.
void handleUpload() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.print("Принимаю файл: ");
Serial.println(upload.filename);
#if defined(ESP8266)
uint32_t room = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
Update.begin(room);
#else
Update.begin(UPDATE_SIZE_UNKNOWN);
#endif
} else if (upload.status == UPLOAD_FILE_WRITE) {
Update.write(upload.buf, upload.currentSize);
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) {
Serial.println("Записано");
} else {
Serial.println("Запись не удалась");
}
}
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Страница обновления по адресу: ");
Serial.println(WiFi.localIP());
server.on("/", handleForm);
server.on("/update", HTTP_POST, handleDone, handleUpload);
server.begin();
}
void loop() {
server.handleClient();
}
Логин и пароль здесь не украшение: страница, которая принимает и запускает произвольную программу, без защиты превращается в открытую дверь. Проверка занимает три строчки и делается встроенными средствами, отдельная библиотека не нужна.
Файл прошивки — это тот самый bin, который среда собирает при компиляции. В Trema IDE он лежит рядом с проектом; путь показывается в окне сборки, если включить подробный вывод.
Способ третий: плата проверяет обновления сама
Когда устройств много или они далеко, ходить к каждому не хочется даже браузером. Тогда плата раз в сутки заходит на ваш сервер и спрашивает: «нет ли для меня чего-то нового?»
// Плата сама раз в сутки заходит на ваш сервер и проверяет,
// не появилась ли новая прошивка. Так обновляют устройства,
// до которых физически не добраться.
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#define UPDATER ESPhttpUpdate
#else
#include <WiFi.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#define UPDATER httpUpdate
#endif
const char WIFI_SSID[] = "имя вашей сети";
const char WIFI_PASS[] = "пароль от сети";
// Адрес обычного веб-сервера, на котором лежит файл прошивки.
// Хост и путь заданы отдельно - так не нужен полный адрес строкой.
const char FW_HOST[] = "192.168.1.10";
const int FW_PORT = 80;
const char FW_PATH[] = "/proshivka.bin";
const unsigned long CHECK_MS = 24UL * 60UL * 60UL * 1000UL; // раз в сутки
unsigned long lastCheck = 0;
void checkUpdate() {
WiFiClient client;
// Плата сообщает серверу свою текущую версию. Умный сервер по ней
// решает, отдавать файл или ответить «обновлений нет».
UPDATER.setLedPin(-1);
t_httpUpdate_return result = UPDATER.update(client, FW_HOST, FW_PORT, FW_PATH, "1.0.0");
if (result == HTTP_UPDATE_FAILED) {
Serial.print("Не обновился, код ");
Serial.print(UPDATER.getLastError());
Serial.print(": ");
Serial.println(UPDATER.getLastErrorString());
} else if (result == HTTP_UPDATE_NO_UPDATES) {
Serial.println("Обновлений нет");
}
// Случая HTTP_UPDATE_OK здесь не будет: после успешной записи
// плата перезагружается сама и до этой строчки не доходит.
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
checkUpdate();
lastCheck = millis();
}
void loop() {
if (millis() - lastCheck > CHECK_MS) {
lastCheck = millis();
if (WiFi.status() == WL_CONNECTED) {
checkUpdate();
}
}
}
Плата сообщает серверу свою текущую версию, и сервер решает, отдавать файл или ответить «обновлений нет». В простейшем случае сервером может быть обычная папка, раздаваемая домашним компьютером.
Осторожность тут нужна другая, не техническая: неудачная прошивка уедет сразу на все платы. Поэтому обновление сначала кладут для одного устройства, ждут сутки и только потом раздают остальным.
Что будет, если связь оборвётся посередине
Это главный страх, из-за которого многие не решаются попробовать. Разберём его по шагам — и он окажется меньше, чем кажется.
Порядок такой: сначала новая прошивка целиком принимается в свободное место, потом плата проверяет её контрольную сумму, и только если всё сошлось — переключается на неё и перезапускается. До последнего шага работающая программа лежит нетронутой.
Поэтому обрыв связи, выключенный свет посреди передачи и битый файл заканчиваются одинаково безобидно: плата остаётся на старой прошивке, а обновление можно повторить.
Опасен ровно один случай: файл целый, запись прошла, а программа в нём с ошибкой — например, забыли строчку подключения к сети. Плата переключилась и стала недоступна. Отсюда правило, которое стоит соблюдать всегда: новую прошивку сначала проверяют на такой же плате на столе, а уже потом отправляют в ту, что вмурована в стену.
И второе правило: не обновляйте устройство, до которого сложно добраться, вечером пятницы.
Что делать, если не работает
| Что видно | Что на самом деле | Что сделать |
|---|---|---|
| Сетевой порт не появляется в списке портов | Плата не объявила себя в сети или компьютер её объявления не слышит | Проверьте, что скетч с обновлением по воздуху действительно залит и плата в той же сети. Компьютер и плата должны быть в одном сегменте: гостевая сеть и подключение через мобильный модем не годятся |
| Ошибка «не принят пароль» | Пароль в скетче и пароль, введённый при загрузке, не совпали | Проверьте раскладку и регистр. После смены пароля плату надо один раз перепрошить кабелем |
| Ошибка «не хватило места» | Новая прошивка не помещается рядом со старой | Уменьшите скетч или выберите схему памяти с меньшей файловой системой. На ESP32 — схему разметки с большими областями под программу |
| Передача идёт и обрывается на середине | Слабый сигнал или плата занята долгой работой | Поднесите плату ближе к роутеру, уберите из loop() всё, что выполняется дольше нескольких миллисекунд |
| После обновления плата не отвечает | В новой прошивке нет подключения к сети или нет обработчика обновления | Подключите кабель и залейте рабочую версию. Впредь проверяйте новую прошивку на такой же плате на столе |
| «Скетч слишком большой», хотя на плате 4 МБ | Скетчу отведена не вся память: вторая половина зарезервирована под обновление | Смотрите схему памяти в настройках платы. Разбор — в разделе про память на этой странице |
| Страница обновления открывается, но файл не принимается | Выбран не тот файл: не bin или собранный для другой платы | Возьмите файл, собранный именно для этой платы. Плата проверяет контрольную сумму и чужой файл не примет |
| Обновление проходит, но плата возвращается к старой программе | Запись не завершилась успешно, и переключения не произошло | Посмотрите монитор порта: там будет строчка о том, на каком шаге всё встало |
Честно про безопасность
Обновление по воздуху — это возможность запустить на вашей плате чужую программу. Относиться к ней стоит соответственно.
- Пароль обязателен всегда. И на сетевом порту, и на странице обновления. Без него достаточно быть в одной сети с платой.
- Пароль лежит в прошивке открытым текстом. Тот, у кого плата окажется в руках, прочитает его. Не используйте здесь пароль, которым пользуетесь где-то ещё.
- Не выставляйте страницу обновления в интернет. Это относится и к пробросу порта на роутере: снаружи должна быть недоступна даже страница с паролем.
- Файл прошивки едет открытым текстом. В домашней сети это приемлемо; если устройство работает в чужой сети — обновляйте его через ваш сервер с защищённым соединением, как в третьем способе, но с портом 443.
Что купить
Проверено 24 августа 2026 года: каждая карточка открыта отдельно, цена и артикул взяты со страницы товара. Того, чего нет в наличии, в подборке нет.
Piranha ESP32 v2
Для обновления по воздуху ESP32 удобнее: разметка памяти с двумя местами под прошивку задана изначально, а запаса хватает и на программу, и на страницу обновления, и на защищённое соединение.
WeMos D1 mini на ESP8266
Тоже умеет обновляться по воздуху, только следите за размером: скетч должен быть меньше половины области, отведённой под программу. Для небольшой поделки этого хватает с запасом.
Источник питания 5 В, 2 А
Обновление — самый неудачный момент для просадки питания. Устройству, которое живёт в корпусе и обновляется по сети, отдельный источник нужен обязательно.
Дальше по теме
- Wi-Fi для Arduino — с чего начинается вся серия.
- Веб-сервер на плате — на нём построена страница обновления.
- MQTT и умный дом — как поделка живёт в системе умного дома.
- Память Arduino — куда она девается и почему её всегда мало.
- Скетч не загружается — разбор обычной загрузки по кабелю.
Частые вопросы
Можно ли прошить Arduino Uno по Wi-Fi?
Нет, и дело даже не в отсутствии радио. Обновление по воздуху требует, чтобы в памяти одновременно поместились две прошивки: работающая и приезжающая. У Uno всего тридцать два килобайта флеш-памяти, и второй такой же программе там просто негде лежать. Даже если приделать к Uno модуль Wi-Fi, обновляться по воздуху она не начнёт. Если нужна возможность обновлять устройство удалённо — берите плату на ESP8266 или ESP32 сразу.
Почему пишет «скетч слишком большой», если на плате 4 МБ памяти?
Потому что скетчу отведена не вся память. У ESP32 разметка по умолчанию выделяет под программу ровно 1 310 720 байт и столько же резервирует под обновление; остальное занимают файлы и служебные области. У ESP8266 отдельных областей нет, но правило то же: новая прошивка пишется в свободное место над старой, и обе должны поместиться до начала файловой системы. Выходов три: уменьшить программу, выбрать в настройках платы схему памяти с меньшей файловой системой или отказаться от обновления по воздуху в пользу схемы, где вся память отдана программе.
Что будет, если связь оборвётся посреди обновления?
Ничего страшного. Новая прошивка сначала целиком принимается в свободное место, потом плата проверяет её контрольную сумму и только после этого переключается на неё. До последнего шага работающая программа лежит нетронутой, поэтому обрыв связи, выключенный свет и битый файл заканчиваются одинаково: плата остаётся на старой прошивке, обновление можно повторить. Опасен ровно один случай — файл целый, но программа в нём сломана: например, забыли подключение к сети. Тогда поможет только кабель, и поэтому новую прошивку сначала проверяют на такой же плате на столе.
Нужна ли библиотека для обновления по воздуху?
Нет. ArduinoOTA входит в пакеты плат ESP8266 и ESP32, ставить отдельно ничего не надо. Для варианта со страницей в браузере тоже хватает встроенных средств: обычный веб-сервер ядра плюс класс записи прошивки, а защита логином и паролем делается двумя строчками. Единственное, что нужно, — один раз залить кабелем скетч, в котором эта поддержка есть.
Плата не появляется в списке портов как сетевая. Что не так?
Три обычные причины. Первая: скетч с поддержкой обновления не залит или залит не тот. Вторая: компьютер и плата в разных сетях — гостевая сеть, другой диапазон Wi-Fi или подключение компьютера через мобильный модем; объявление платы по сети до компьютера просто не доходит, а многие роутеры такие объявления ещё и режут. Третья: программа в плате занята и не вызывает обработчик обновления в каждом проходе цикла. Проверьте по монитору порта, что плата в сети и печатает свой адрес.
Обязательно ли ставить пароль на обновление?
Да. Обновление по воздуху — это возможность запустить на вашей плате любую программу, и без пароля ею может воспользоваться каждый, кто подключён к той же сети, включая гостя, которому вы дали пароль от Wi-Fi. Пароль ставится одной строчкой и на сетевом порту, и на странице обновления. Учтите только, что в прошивке он лежит открытым текстом: тот, у кого плата окажется в руках, его прочитает — поэтому не используйте здесь пароль, которым пользуетесь где-то ещё.
Что для этого нужно в среде
Библиотеки не нужны: поддержка обновления по воздуху входит в сами пакеты плат ESP8266 и ESP32, а Trema IDE берёт эти пакеты с нашего зеркала. Сетевой порт появляется в общем списке портов, рядом с обычными.
Что почитать рядом: подключение к сети, веб-сервер, память платы и разбор ошибок сборки.
