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: два одинаковых места под прошивкупрошивка (сейчас)1,25 МБпрошивка (новая)1,25 МБфайлы1,38 МБВсего на плате: 3,96 МБслужебное — настройки, счётчик обновлений, аварийный дамппрошивка (сейчас) — здесь живёт та программа, которая работаетпрошивка (новая) — сюда пишется обновление, пока старое работаетфайлы — картинки, страницы, настройки — если они вам нужныСкетч не может быть больше 1 310 720 байт, сколько бы памяти ни было на плате: втораятакая же область зарезервирована под обновление. Это записано в разметке, которую ядрокладёт в каждую плату.
Отсюда растёт знаменитое «скетч слишком большой» на плате с четырьмя мегабайтами памяти. Половина этой памяти не потеряна — она зарезервирована ровно для того, чтобы обновление по воздуху было безопасным.

Логика простая и правильная: пока новая прошивка едет по сети, старая обязана работать. Значит, в памяти должны одновременно поместиться обе. У 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 удобнее: разметка памяти с двумя местами под прошивку задана изначально, а запаса хватает и на программу, и на страницу обновления, и на защищённое соединение.

690 ₽
Открыть карточку
арт. 1453 · цена и наличие на 24.08.2026

WeMos D1 mini на ESP8266

Тоже умеет обновляться по воздуху, только следите за размером: скетч должен быть меньше половины области, отведённой под программу. Для небольшой поделки этого хватает с запасом.

290 ₽
Открыть карточку
арт. 867 · цена и наличие на 24.08.2026

Источник питания 5 В, 2 А

Обновление — самый неудачный момент для просадки питания. Устройству, которое живёт в корпусе и обновляется по сети, отдельный источник нужен обязательно.

986 ₽
Открыть карточку
арт. 491 · цена и наличие на 24.08.2026

Дальше по теме

Частые вопросы

Можно ли прошить 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 берёт эти пакеты с нашего зеркала. Сетевой порт появляется в общем списке портов, рядом с обычными.

Что почитать рядом: подключение к сети, веб-сервер, память платы и разбор ошибок сборки.