Руководства · 15 мин чтения

ESP32 не подключается к Wi-Fi? Коды WiFi.status() и рабочие решения

ESP32 не подключается к Wi-Fi? Разбираем WiFi.status() и коды причин, решаем проблемы с 2,4 GHz и паролем, просадками питания, setTxPower, переподключением, статическим IP и eduroam.

ESP32 не подключается к Wi-Fi, а монитор порта всё печатает и печатает точки? Почти никогда дело не в сломанной плате. Обычные подозреваемые: попытка подключиться к сети 5 GHz, крошечная опечатка в имени сети или пароле, слабое питание, которое проседает в момент включения Wi-Fi, настройки безопасности и канала на роутере или корпоративная сеть в школе или на работе. Хорошая новость: ESP32 уже сообщает, что пошло не так. Нужно только уметь читать значение WiFi.status() и код причины (reason), который она выдаёт при обрыве соединения.

В этом руководстве сначала разберём, через какие шаги проходит ESP32 при подключении к сети и какой код статуса она выдаёт на каждом из них. Дальше идут диагностический скетч, который печатает коды статуса и причины, сканер, показывающий сети вокруг, требование 2,4 GHz и двухдиапазонные роутеры, просадки питания и решение через setTxPower, скетч переподключения, который восстанавливает связь без твоего участия, статический IP, подключение к школьным сетям WPA2-Enterprise и тест с точкой доступа на телефоне, который за несколько минут показывает, в чём проблема: в роутере или в плате. Скетчи работают с версиями 2.x и 3.x ядра ESP32 для Arduino IDE, а в конце есть ещё тестовый скрипт для Raspberry Pi Pico W и MicroPython.

Отладочная плата ESP32 и антенна на печатной плате
Отладочная плата ESP32: зигзагообразная дорожка на краю модуля с металлическим экраном и есть антенна на печатной плате. Металл, аккумулятор или провода над этой областью или прямо рядом с ней заметно ослабляют связь.

Как ESP32 подключается к сети Wi-Fi?

При вызове WiFi.begin() ESP32 в фоне выполняет четыре шага. Сначала она сканирует каналы в поисках сети с заданным именем (SSID). Если сеть нашлась, плата проходит аутентификацию и ассоциацию с роутером. В сетях WPA2 затем следует 4-этапное рукопожатие (4-way handshake): именно в этот момент становится ясно, верный ли пароль. Наконец, ESP32 запрашивает IP-адрес у DHCP-сервера роутера. WiFi.status() возвращает WL_CONNECTED только после того, как завершён и этот последний шаг. Если известно, на каком шаге всё застряло, причина по большей части тоже понятна:

ШагЧто происходит?Статус и причина, если застряло
1. СканированиеESP32 ищет имя сети на каналах 2,4 GHzWL_NO_SSID_AVAIL (1), причина 201
2. Аутентификация и ассоциацияРоутер принимает или отклоняет ESP32WL_CONNECT_FAILED (4) или WL_DISCONNECTED (6), причина 202 или 203
3. 4-этапное рукопожатиеСравниваются ключи, полученные из пароляWL_DISCONNECTED (6) с причиной 15; WL_CONNECTION_LOST (5) с причиной 204
4. DHCPРоутер выдаёт ESP32 IP-адресЗависает на WL_IDLE_STATUS (0)
После подключенияРоутер продолжает отправлять пакеты-маяки (beacon)Если они пропадают: WL_CONNECTION_LOST (5), причина 200

Что означают коды WiFi.status()

WiFi.status() возвращает значение типа wl_status_t. Если вывести его прямо в монитор порта, видно только число. В таблице ниже показано, что означает каждое число в ядре ESP32 для Arduino. Внимание: значения от 0 до 6 называются так же, как в старой библиотеке Arduino WiFi, но на ESP32 появляются в немного других ситуациях. Например, сразу после WiFi.begin() статус равен 6, а не 0; он меняется на 0, когда плата подключилась к роутеру и ждёт IP, и на 3, когда IP получен.

КодКонстантаЗначениеЧто проверить сначала
0WL_IDLE_STATUSПодключена к роутеру, но IP-адреса ещё нетНесколько секунд это нормально; если затягивается, DHCP
1WL_NO_SSID_AVAILСеть с таким именем не найденаИмя сети, диапазон 2,4 GHz, расстояние
2WL_SCAN_COMPLETEDСканирование сетей завершеноК подключению не относится
3WL_CONNECTEDПодключена и имеет IP-адресВсё в порядке
4WL_CONNECT_FAILEDРоутер отклонил подключениеПароль, режим безопасности, MAC-фильтр
5WL_CONNECTION_LOSTУстановленное соединение оборвалосьУровень сигнала, питание, антенна
6WL_DISCONNECTEDНе подключена; попытка ещё идёт или не удаласьКод причины
254WL_STOPPEDСтанция Wi-Fi остановлена (ядро 3.x)Вызови WiFi.mode(WIFI_STA)
255WL_NO_SHIELDWi-Fi ещё не запущен (ядро 2.x)Вызови WiFi.mode() или WiFi.begin()
При неверном пароле большинство ждёт WL_CONNECT_FAILED (4), но ESP32 часто показывает WL_DISCONNECTED (6) и продолжает попытки в фоне. Дело в том, что многие роутеры при неверном пароле просто дают рукопожатию истечь по таймауту (причина 15). Ещё одна классическая ошибка: вызывать WiFi.begin() снова и снова внутри цикла ожидания. Каждый вызов перезапускает текущую попытку, и плата часто так и не подключается. Вызови begin() один раз, а потом только читай статус.

Диагностический скетч: вывод статуса и кода причины в монитор порта

Скетч ниже 20 секунд пытается подключиться, при каждом изменении статуса печатает его код с названием и при каждом обрыве соединения показывает код причины из ESP-IDF. Если подключение удалось, он выводит IP-адрес, шлюз, уровень сигнала (RSSI) и канал; в любом случае показывает и MAC-адрес платы. Замени имя сети и пароль на свои, загрузи скетч и открой монитор порта на скорости 115200 бод. Если скетч даже не загружается, сначала прочитай руководство об ошибках загрузки.

C++ (Arduino IDE)
1#include <WiFi.h>
2
3const char* WIFI_ADI   = "EvAgi_2G";    // Wi-Fi adı, büyük-küçük harfe duyarlı / network name, case-sensitive
4const char* WIFI_SIFRE = "sifre1234";   // Wi-Fi şifresi / Wi-Fi password
5
6// Durum kodunu adına çevir / turn the status code into its name
7const char* durumAdi(wl_status_t durum) {
8  switch (durum) {
9    case WL_IDLE_STATUS:     return "WL_IDLE_STATUS";
10    case WL_NO_SSID_AVAIL:   return "WL_NO_SSID_AVAIL";
11    case WL_SCAN_COMPLETED:  return "WL_SCAN_COMPLETED";
12    case WL_CONNECTED:       return "WL_CONNECTED";
13    case WL_CONNECT_FAILED:  return "WL_CONNECT_FAILED";
14    case WL_CONNECTION_LOST: return "WL_CONNECTION_LOST";
15    case WL_DISCONNECTED:    return "WL_DISCONNECTED";
16    default:                 return "WL_NO_SHIELD / WL_STOPPED";
17  }
18}
19
20// Bağlantı her koptuğunda sebep kodunu yaz / print the reason code on every disconnect
21void koptugunda(arduino_event_id_t olay, arduino_event_info_t bilgi) {
22  Serial.printf("Koptu / Disconnected, reason: %d\n", (int)bilgi.wifi_sta_disconnected.reason);
23}
24
25void setup() {
26  Serial.begin(115200);
27  delay(1000);
28  WiFi.onEvent(koptugunda, ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
29  WiFi.mode(WIFI_STA);                         // istasyon modu / station mode
30  WiFi.begin(WIFI_ADI, WIFI_SIFRE);            // begin() yalnızca bir kez / call begin() only once
31
32  wl_status_t onceki = WL_NO_SHIELD;
33  unsigned long baslangic = millis();
34  while (WiFi.status() != WL_CONNECTED && millis() - baslangic < 20000) {
35    wl_status_t simdi = WiFi.status();
36    if (simdi != onceki) {                     // yalnızca değişince yaz / print only when it changes
37      Serial.printf("Durum / Status: %d %s\n", (int)simdi, durumAdi(simdi));
38      onceki = simdi;
39    }
40    delay(500);
41  }
42
43  if (WiFi.status() == WL_CONNECTED) {
44    Serial.print("Bagli / Connected, IP: ");
45    Serial.println(WiFi.localIP());
46    Serial.print("Ag gecidi / Gateway: ");
47    Serial.println(WiFi.gatewayIP());
48    Serial.printf("RSSI: %d dBm, kanal / channel: %d\n", (int)WiFi.RSSI(), (int)WiFi.channel());
49  } else {
50    wl_status_t son = WiFi.status();
51    Serial.printf("Baglanamadi / Failed, son durum / last status: %d %s\n", (int)son, durumAdi(son));
52  }
53  Serial.print("MAC: ");
54  Serial.println(WiFi.macAddress());           // MAC filtresi için / for MAC filtering
55}
56
57void loop() {}

Сначала увидеть Durum / Status: 6 WL_DISCONNECTED нормально. Если подключение удаётся, статус ненадолго меняется на 0, а затем на 3. Если он остаётся равным 1, сеть так и не найдена; если одна за другой идут строки вроде Koptu / Disconnected, reason: 15, скорее всего, неверный пароль. Чтобы получить ещё больше подробностей, выбери в Arduino IDE Инструменты › Core Debug Level (Tools › Core Debug Level) значение Warn или Info: тогда ядро при каждом обрыве печатает и название причины, например Reason: 201 - NO_AP_FOUND. Вот коды причин, которые встречаются чаще всего:

ПричинаНазваниеЧто это значит?Решение
2AUTH_EXPIREИстекло время аутентификацииСлабый сигнал или перегруженный роутер; подойди ближе, перезагрузи роутер
5ASSOC_TOOMANYДостигнут лимит клиентов роутераОтключи ненужные устройства или увеличь лимит
8ASSOC_LEAVEESP32 сама покинула сетьКод вызывает WiFi.disconnect(); это нормально
154WAY_HANDSHAKE_TIMEOUTНе удалось завершить рукопожатие с паролемЧаще всего неверный пароль; проверь его и режим безопасности
200BEACON_TIMEOUTМаяки от роутера перестали приходитьСлабый сигнал или просадка напряжения; антенна, питание, setTxPower
201NO_AP_FOUNDСеть с этим именем не найденаНаписание SSID, сеть 5 GHz, расстояние, скрытая сеть, каналы 12 и 13
202AUTH_FAILАутентификация отклоненаПароль или несовместимый режим безопасности, например Enterprise
203ASSOC_FAILРоутер отклонил ассоциациюMAC-фильтр или беспроводной режим вроде «только 802.11ax»
204HANDSHAKE_TIMEOUTИстекло время рукопожатияНеверный пароль или очень слабый сигнал
210, 211NO_AP_FOUND_W_COMPATIBLE_SECURITY, NO_AP_FOUND_IN_AUTHMODE_THRESHOLDСеть найдена, но её режим безопасности несовместим или ниже допустимого минимума (ядро 3.x)Переключи роутер на WPA2-Personal (AES) или понизь минимум через WiFi.setMinSecurity()

Требование 2,4 GHz: ESP32 не видит сети 5 GHz

Классическая ESP32, ESP32-S2, ESP32-S3, ESP32-C3 и ESP32-C6 работают только в диапазоне 2,4 GHz. Сеть, вещающую на 5 GHz, они при сканировании не видят никогда, и результат всегда WL_NO_SSID_AVAIL. Большинство домашних роутеров вещают в обоих диапазонах. Если у роутера для каждого диапазона своё имя (например, MyWiFi и MyWiFi_5G), всегда указывай ESP32 имя сети 2,4 GHz. Если у обоих диапазонов одно и то же имя (Smart Connect, band steering или mesh-системы), ESP32 обычно без проблем подключается к стороне 2,4 GHz, ведь сигнал 5 GHz она всё равно не видит. Проблемы начинаются, когда диапазон 2,4 GHz выключен или роутер пытается перевести клиентов на 5 GHz: ESP32 подключается, через несколько секунд отваливается, и всё повторяется по кругу. В таком случае раздели диапазоны в настройках роутера или создай гостевую сеть, которая вещает только на 2,4 GHz.

ПлатаДиапазон Wi-FiПримечание
ESP32 (WROOM-32, DevKit), ESP32-S2, ESP32-S3Только 2,4 GHz802.11 b/g/n
ESP32-C3Только 2,4 GHzДешёвым платам Super Mini может понадобиться пониженная мощность передатчика
ESP32-C6Только 2,4 GHzПоддерживает Wi-Fi 6 (802.11ax), но всё равно только на 2,4 GHz
ESP32-C52,4 GHz и 5 GHzПервый двухдиапазонный чип Espressif
ESP8266 (NodeMCU, Wemos D1 mini, ESP-01)Только 2,4 GHz802.11 b/g/n
Raspberry Pi Pico W и Pico 2 WТолько 2,4 GHzБеспроводной чип CYW43439
Arduino Uno R4 WiFiТолько 2,4 GHzЗа Wi-Fi отвечает встроенная ESP32-S3

Если диапазон верный, а сеть всё равно не находится, проверь настройки канала и режима на роутере. С региональной настройкой ESP32 по умолчанию каналы с 1 по 11 сканируются активно, а каналы 12 и 13 только прослушиваются пассивно. Видимые сети на этих каналах обычно всё же находятся, но скрытую сеть (вещание SSID выключено) на канале 12 или 13 ESP32 не найдёт. Самый надёжный вариант: переключить канал с автоматического на фиксированный 1, 6 или 11. Классическая ESP32, S2, S3 и C3 не могут подключиться к роутеру, настроенному только на 802.11ax (Wi-Fi 6); переключи режим на b/g/n или смешанный b/g/n/ax. По безопасности самые совместимые варианты: WPA2-Personal (AES) или смешанный режим WPA2/WPA3. По умолчанию ядро Arduino отклоняет всё, что слабее WPA2 (WEP и старый WPA-TKIP); если действительно нужно подключиться к очень старой сети, добавь WiFi.setMinSecurity(WIFI_AUTH_WEP) перед begin(). Прежде чем менять настройки, посмотри с помощью этого сканера, что на самом деле видит ESP32:

C++ (Arduino IDE)
1#include <WiFi.h>
2
3// Güvenlik türünü yazıya çevir / turn the security type into text
4const char* guvenlikAdi(wifi_auth_mode_t tur) {
5  switch (tur) {
6    case WIFI_AUTH_OPEN:          return "Acik / Open";
7    case WIFI_AUTH_WEP:           return "WEP";
8    case WIFI_AUTH_WPA_PSK:       return "WPA";
9    case WIFI_AUTH_WPA2_PSK:      return "WPA2";
10    case WIFI_AUTH_WPA_WPA2_PSK:  return "WPA/WPA2";
11    case WIFI_AUTH_WPA3_PSK:      return "WPA3";
12    case WIFI_AUTH_WPA2_WPA3_PSK: return "WPA2/WPA3";
13    default:                      return "Diger / Other (Enterprise)";
14  }
15}
16
17void setup() {
18  Serial.begin(115200);
19  WiFi.mode(WIFI_STA);
20  WiFi.disconnect();                            // temiz tarama için bağlantıyı kes / disconnect for a clean scan
21  delay(100);
22}
23
24void loop() {
25  Serial.println("Taraniyor / Scanning...");
26  int adet = WiFi.scanNetworks();               // engelleyen tarama, 2-4 sn / blocking scan, 2-4 s
27  if (adet <= 0) {
28    Serial.println("Ag bulunamadi / No networks found");
29  }
30  for (int i = 0; i < adet; i++) {
31    Serial.printf("%2d | %-32s | %4d dBm | kanal/ch %2d | %s\n",
32                  i + 1, WiFi.SSID(i).c_str(), (int)WiFi.RSSI(i),
33                  (int)WiFi.channel(i), guvenlikAdi(WiFi.encryptionType(i)));
34  }
35  WiFi.scanDelete();                            // sonuçları bellekten sil / free the results
36  Serial.println();
37  delay(10000);                                 // 10 sn sonra yeniden tara / scan again in 10 s
38}

Если имени твоей сети вообще нет в списке, проблема возникает ещё до кода: сеть на 5 GHz, скрытая или ESP32 слишком далеко. Если имя есть, посмотри на его RSSI: от -30 до -60 dBm отлично, от -60 до -70 dBm хорошо; между -70 и -80 dBm плата подключается, но может терять связь, а ниже -80 dBm надёжного соединения не жди. Если одно и то же имя встречается несколько раз, у роутера или mesh-системы больше одной точки доступа. При быстром сканировании по умолчанию ESP32 подключается к первому найденному совпадению; если нужно, чтобы она выбирала самый сильный сигнал, добавь WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN) перед begin(). Скопируй имя ровно так, как оно показано в результатах сканирования, и вставь в скетч: это раз и навсегда исключает опечатки.

Ошибки в имени сети (SSID) и пароле

Если диагностический скетч сообщает причину 201 или 15, проблема обычно в двух строках кода. SSID может занимать до 32 байт, пароль WPA2 должен содержать от 8 до 63 символов, и оба чувствительны к регистру. Вот ошибки, которые чаще всего остаются незамеченными:

  • Заглавные и строчные буквы: к сети, которая в роутере называется MyWiFi, не подключиться, если написать mywifi. То же правило действует для пароля.
  • Невидимые пробелы: пробел в конце имени сети или пароля либо скрытый символ, попавший при копировании откуда-то, ломает совпадение.
  • Специальные символы: буквы с диакритикой, кириллицу или символы в имени сети роутер может хранить в другой кодировке. Самое надёжное решение: переименовать сеть, используя только латинские буквы и цифры.
  • Типографский апостроф: на iPhone имя точки доступа совпадает с именем телефона, и в нём часто стоит изогнутый ’ вместо прямого ' с клавиатуры, поэтому имя в коде не совпадает.
  • Обратная косая черта и кавычки: если в пароле есть \ или ", в строке C++ их нужно записать как \\ и \"; иначе компилятор изменит пароль или скетч не скомпилируется.
  • Открытая сеть: для подключения к сети без пароля пароль не указывается вовсе; достаточно WiFi.begin(имя). Если передать пароль для открытой сети, ядро ищет WPA2 и не находит сеть.
  • Скрытая сеть: к сетям с выключенным вещанием SSID можно подключиться, указав точное имя, но при сканировании они не видны; если возникают трудности, на время тестов включи вещание.
Прежде чем менять пароль, выясни, в чём проблема: в имени или в пароле. Если пришла причина 201, сеть так и не найдена, и возиться с паролем бессмысленно. Если пришла причина 15, 202 или 204, сеть найдена, но пароль или режим безопасности не принят.

Питание и просадка напряжения (brownout): почему плата перезагружается при запуске Wi-Fi?

Модуль ESP32 в среднем потребляет около 80 mA, но пока работает передатчик Wi-Fi, ток кратковременно подскакивает до 250–400 mA. Самые большие пики обычно бывают во время калибровки радио при старте и при первом подключении. Поэтому Espressif рекомендует источник питания, способный выдать не меньше 500 mA. Если источник не справляется с этими пиками, шина 3,3 V на мгновение проседает, срабатывает детектор просадки питания (brownout) в чипе, и плата перезагружается с сообщением Brownout detector was triggered в мониторе порта. Симптом очень знакомый: код нормально работает до строки с Wi-Fi, на WiFi.begin() плата сбрасывается, и всё превращается в бесконечный цикл. Эту ошибку мы подробно разбираем в статье об ошибках brownout и Guru Meditation на ESP32.

Стабилизатор напряжения AMS1117 на 3,3 V
AMS1117: именно этот стабилизатор понижает 5 V до 3,3 V на большинстве отладочных плат ESP32. Для нормальной работы ему нужна разница примерно 1,1–1,3 V между входом и выходом.
Источник питанияПодходит?Почему?
USB-порт на задней панели компьютера, короткий толстый кабельОбычно даПорт USB 2.0 выдаёт 500 mA; короткий кабель уменьшает потери напряжения
USB на передней панели, USB-хаб или длинный тонкий кабельМожет вызывать проблемыСопротивление кабеля и контактов роняет напряжение во время пиков тока
Зарядка для телефона на 5 V, не меньше 1 AДаОставляет хороший запас для пиков тока
Пин 3.3V на Arduino UnoНетЭтот пин выдаёт всего около 50 mA
Li-ion аккумулятор 3,7 V напрямую на пин 5V платыНетИз-за падения напряжения на AMS1117 выход опускается ниже 3 V
Li-ion аккумулятор с повышающим преобразователем на 5 V или стабилизатором 3,3 V с малым падением напряжения (LDO)ДаДаёт стабильные 3,3 V даже по мере разряда аккумулятора
Выход 3,3 V модуля питания для макетной платы MB102Чаще всего даПитай его от адаптера с достаточным током и добавь конденсатор
В проектах с Wi-Fi поставь электролитический конденсатор 100–470 µF между пинами 3V3 и GND платы как можно ближе к ней, а рядом ещё керамический конденсатор на 100 nF. Длинная ножка (+) электролита идёт на 3V3, а сторона с полосой на корпусе на GND; электролит, установленный наоборот, греется и может взорваться. Как работают конденсаторы, читай в статье Что такое конденсатор?, а как правильно запитать плату, в руководстве Питание Arduino.

Решение через setTxPower: снижение мощности передатчика

На некоторых платах даже при хорошем питании ESP32 видит сеть, но не может подключиться, или соединение постоянно рвётся. Особенно на дешёвых платах ESP32-C3 Super Mini и некоторых клонах ESP32 антенная цепь и стабилизатор не справляются с максимальной мощностью передатчика. По умолчанию ESP32 передаёт примерно на 19,5–20 dBm. Снижение мощности через WiFi.setTxPower() уменьшает пики тока и на таких платах часто сразу исправляет подключение. Вызывай её сразу после WiFi.begin(): до запуска Wi-Fi, то есть до WiFi.mode() или begin(), она не работает.

КонстантаМощностьКогда использовать
WIFI_POWER_19_5dBm19,5 dBmБлизко к значению по умолчанию; максимальная дальность
WIFI_POWER_15dBm15 dBmПервая попытка при небольших проблемах
WIFI_POWER_11dBm11 dBmОбычно хватает, если роутер в той же комнате
WIFI_POWER_8_5dBm8,5 dBmЗначение, которое чаще всего советуют для ESP32-C3 Super Mini
WIFI_POWER_5dBm5 dBmДля тестов прямо рядом с роутером

Каждое снижение на 3 dB вдвое уменьшает мощность передатчика, так что дальность тоже сокращается. Начни с 15 dBm; если проблема остаётся, спустись до 11, а затем до 8,5 dBm. Если снижение мощности исправляет подключение, настоящая причина обычно в питании или конструкции антенны, поэтому в долгосрочной перспективе добавь ещё и более качественный источник питания с конденсатором. Текущую настройку платы можно прочитать через WiFi.getTxPower(); значение выражено в единицах 0,25 dBm, так что 78 означает 19,5 dBm.

Скетч автоматического переподключения

ESP32 теряет соединение, когда роутер перезагружается, когда после отключения возвращается электричество или когда сигнал на время пропадает. В ядре ESP32 WiFi.setAutoReconnect(true) включён по умолчанию, и после большинства обрывов плата подключается снова без посторонней помощи. Но при некоторых причинах, например 202 AUTH_FAIL, ядро сдаётся после одной повторной попытки, и плата остаётся без сети до сброса. Поэтому в проекте, который должен работать месяцами, стоит добавить собственную проверку. Скетч ниже обходится без delay() и с помощью millis() каждые 15 секунд проверяет соединение, переподключается, если оно оборвалось, и перезагружает плату, если подключиться не удаётся 5 минут:

C++ (Arduino IDE)
1#include <WiFi.h>
2
3const char* WIFI_ADI   = "EvAgi_2G";    // Wi-Fi adı / network name
4const char* WIFI_SIFRE = "sifre1234";   // Wi-Fi şifresi / Wi-Fi password
5
6const unsigned long KONTROL_ARALIGI = 15000;  // 15 sn'de bir kontrol / check every 15 s
7const int EN_FAZLA_DENEME = 20;               // 20 x 15 sn = 5 dk / 20 x 15 s = 5 min
8unsigned long sonKontrol = 0;
9int basarisizSayac = 0;                       // üst üste başarısız kontrol / consecutive failed checks
10
11void wifiBaslat() {
12  WiFi.mode(WIFI_STA);
13  WiFi.setAutoReconnect(true);                // çekirdeğin kendi yeniden bağlanması / core auto-reconnect
14  WiFi.begin(WIFI_ADI, WIFI_SIFRE);
15  WiFi.setTxPower(WIFI_POWER_15dBm);          // gerekirse 8_5dBm'e kadar düşür / lower to 8_5dBm if needed
16  WiFi.setSleep(false);                       // modem uykusunu kapat / disable modem sleep
17}
18
19void setup() {
20  Serial.begin(115200);
21  wifiBaslat();
22}
23
24void loop() {
25  if (millis() - sonKontrol >= KONTROL_ARALIGI) {
26    sonKontrol = millis();
27    if (WiFi.status() == WL_CONNECTED) {
28      basarisizSayac = 0;
29      Serial.printf("Bagli / Connected, IP: %s, RSSI: %d dBm\n",
30                    WiFi.localIP().toString().c_str(), (int)WiFi.RSSI());
31    } else {
32      basarisizSayac++;
33      Serial.printf("Bagli degil / Not connected (%d/%d), yeniden baglaniyor / reconnecting\n",
34                    basarisizSayac, EN_FAZLA_DENEME);
35      WiFi.disconnect();
36      WiFi.reconnect();
37      if (basarisizSayac >= EN_FAZLA_DENEME) {
38        Serial.println("Yeniden baslatiliyor / Restarting");
39        delay(100);
40        ESP.restart();                        // son çare: kartı yeniden başlat / last resort: restart the board
41      }
42    }
43  }
44
45  // Projenin kodu buraya; uzun delay() kullanma / your project code here; avoid long delay()
46}

Строка WiFi.setSleep(false) выключает modem sleep: режим, в котором ESP32 во время подключения периодически ненадолго выключает радио. С некоторыми роутерами это уменьшает обрывы, а на веб-сервере снижает задержку; взамен плата потребляет на несколько десятков mA больше. В проектах на батарейках эту строку можно убрать и рассчитать, сколько проработает батарея, в калькуляторе времени работы от батареи. Строку setTxPower оставляй, только если есть проблемы из предыдущего раздела. Добавляя код проекта в loop(), избегай долгих вызовов delay(), потому что проверка соединения выполняется только пока loop() крутится. Если удобнее вводить данные Wi-Fi с телефона, а не прописывать их в коде, посмотри библиотеку WiFiManager.

Настройка статического IP на ESP32

Обычно роутер выдаёт ESP32 адрес по DHCP, и он может каждый раз меняться. Если ты делаешь веб-сервер, который всегда будешь открывать с телефона по одному и тому же адресу, или DHCP роутера работает с ошибками (статус застревает на 0), жизнь упрощает статический IP. Запомни три правила: WiFi.config() нужно вызывать до WiFi.begin(); выбранный адрес должен быть в сети роутера, но вне его пула DHCP (если роутер раздаёт 192.168.1.2–100, бери что-то вроде 192.168.1.200); шлюз — это собственный адрес роутера. Чтобы узнать адрес роутера, один раз запусти диагностический скетч с DHCP: он печатает и шлюз.

C++ (Arduino IDE)
1#include <WiFi.h>
2
3const char* WIFI_ADI   = "EvAgi_2G";      // Wi-Fi adı / network name
4const char* WIFI_SIFRE = "sifre1234";     // Wi-Fi şifresi / Wi-Fi password
5
6IPAddress sabitIP(192, 168, 1, 200);      // DHCP havuzunun dışında bir adres / an address outside the DHCP pool
7IPAddress agGecidi(192, 168, 1, 1);       // modemin adresi / router address
8IPAddress altAgMaskesi(255, 255, 255, 0); // alt ağ maskesi / subnet mask
9IPAddress dns1(1, 1, 1, 1);               // birinci DNS / primary DNS
10IPAddress dns2(8, 8, 8, 8);               // ikinci DNS / secondary DNS
11
12void setup() {
13  Serial.begin(115200);
14  WiFi.mode(WIFI_STA);
15  // config() mutlaka begin()'den önce / config() must come before begin()
16  if (!WiFi.config(sabitIP, agGecidi, altAgMaskesi, dns1, dns2)) {
17    Serial.println("Statik IP ayarlanamadi / Static IP config failed");
18  }
19  WiFi.begin(WIFI_ADI, WIFI_SIFRE);
20
21  unsigned long baslangic = millis();
22  while (WiFi.status() != WL_CONNECTED && millis() - baslangic < 15000) {
23    delay(500);
24    Serial.print('.');
25  }
26  Serial.println();
27  Serial.print("IP: ");
28  Serial.println(WiFi.localIP());             // 192.168.1.200 olmalı / should be 192.168.1.200
29}
30
31void loop() {}
На ESP32 порядок параметров такой: IP, шлюз, маска подсети, DNS1, DNS2, и он отличается от некоторых библиотек Arduino WiFi (IP, DNS, шлюз, подсеть). Если перепутать порядок, ESP32 подключается к сети, но не может выйти в интернет. Советуем также заполнить адреса DNS: если DNS не работает, ESP32 видна в роутере, но не может разрешать доменные имена и поэтому не достучится до сервисов вроде погодных API, NTP или Telegram. Если дать один и тот же IP двум устройствам, оба будут случайным образом терять соединение.

Школьные и корпоративные сети: подключение к WPA2-Enterprise (eduroam)

eduroam в университетах, сети компаний и некоторые школьные сети используют WPA2-Enterprise (802.1X): вместо одного общего пароля у каждого пользователя свои логин и пароль. Обычный WiFi.begin(имя, пароль) в таких сетях всегда завершается неудачей, а в сканере их тип безопасности отображается как Diger / Other (Enterprise). Версии 2.x и 3.x ядра ESP32 для Arduino предлагают готовую форму begin() для PEAP, самого распространённого метода:

C++ (Arduino IDE)
1#include <WiFi.h>
2
3const char* AG_ADI        = "eduroam";               // kurum ağının adı / enterprise network name
4const char* EAP_KIMLIK    = "[email protected]";   // kimlik, çoğu zaman kullanıcı adıyla aynı / identity, usually same as username
5const char* EAP_KULLANICI = "[email protected]";   // kullanıcı adı / username
6const char* EAP_SIFRE     = "kurum_sifren";          // kurum şifresi / enterprise password
7
8void setup() {
9  Serial.begin(115200);
10  WiFi.disconnect(true);                              // önceki bağlantıyı kapat / close any previous connection
11  WiFi.mode(WIFI_STA);
12  // PEAP (MSCHAPv2) ile bağlan, CA doğrulaması yok / connect with PEAP (MSCHAPv2), no CA check
13  WiFi.begin(AG_ADI, WPA2_AUTH_PEAP, EAP_KIMLIK, EAP_KULLANICI, EAP_SIFRE);
14
15  unsigned long baslangic = millis();
16  while (WiFi.status() != WL_CONNECTED && millis() - baslangic < 30000) {
17    delay(500);
18    Serial.print('.');
19  }
20  Serial.println();
21  if (WiFi.status() == WL_CONNECTED) {
22    Serial.print("Bagli / Connected, IP: ");
23    Serial.println(WiFi.localIP());
24  } else {
25    Serial.printf("Baglanamadi / Failed, durum / status: %d\n", (int)WiFi.status());
26  }
27}
28
29void loop() {}

В большинстве организаций identity (идентификатор) совпадает с именем пользователя; некоторые требуют анонимный внешний идентификатор вроде [email protected]. Этот скетч не проверяет сертификат сервера (CA): соединение работает, но поддельная точка доступа может перехватить пароль. Поэтому, прежде чем записывать личный пароль в ESP32, посоветуйся с ИТ-отделом и по возможности попроси учётную запись или сеть для устройств. Если организация требует сертификат, CA-файл можно передать шестым параметром begin(). Сети, которые открывают страницу входа в браузере (captive portal), как в отелях, общежитиях и кафе, — отдельная проблема: ESP32 не умеет заполнять такую страницу. Некоторые школы также требуют заранее регистрировать MAC-адреса устройств; отправь в ИТ-отдел MAC-адрес, который печатает диагностический скетч. В таких сетях самое практичное решение: точка доступа на телефоне или маленький карманный роутер.

Тест с точкой доступа на телефоне: виноват роутер или ESP32?

Быстрее всего сузить круг причин, подключив ESP32 к сети, настройки которой полностью под твоим контролем. Точка доступа на телефоне идеально для этого подходит:

  1. Дай точке доступа короткое имя только из латинских букв и цифр (например, esptest) и задай простой пароль не короче 8 символов (например, test12345).
  2. На Android в настройках точки доступа выбери диапазон (на некоторых телефонах пункт называется «Диапазон точки доступа» или «Скорость и совместимость») 2,4 GHz, а в качестве типа защиты WPA2-Personal.
  3. На iPhone открой Настройки › Режим модема (Settings › Personal Hotspot) и включи Разрешать другим (Allow Others to Join). На новых моделях включи ещё Максимальная совместимость (Maximize Compatibility): это переводит точку доступа на 2,4 GHz. Имя точки доступа совпадает с именем телефона, поэтому упрости его в Настройки › Основные › Об этом устройстве › Имя и держи экран «Режим модема» открытым, пока ESP32 не подключится.
  4. Замени имя сети и пароль в диагностическом скетче на данные точки доступа, положи телефон в 1–2 м от ESP32 и загрузи скетч.
  5. Прочитай коды статуса и причины в мониторе порта, а затем попробуй тот же скетч с данными домашнего роутера.

Результат толкуй так: если ESP32 подключается к точке доступа, но не к домашнему роутеру, с кодом, платой и питанием всё в порядке; проблема в настройках роутера: диапазоне, канале, безопасности, MAC-фильтре или лимите клиентов. Если к точке доступа подключиться тоже не удаётся, проблема на стороне ESP32: смени источник питания и кабель, снизь мощность через setTxPower, убедись, что перед антенной нет металла, и ещё раз проверь код. Тест с точкой доступа также самый быстрый способ доказать, что проект, который не подключается в школе, на самом деле работает.

Тест Wi-Fi на Raspberry Pi Pico W и MicroPython

Raspberry Pi Pico W и Pico 2 W тоже поддерживают только 2,4 GHz; все советы этой статьи про диапазон, пароль, питание и точку доступа относятся и к этим платам. В MicroPython коды статуса читаются через константы модуля network. Скрипт ниже без изменений работает в Thonny и на ESP32, и на Pico W. На Pico W он сразу прекращает ожидание, если сеть не найдена или пароль неверный; на ESP32 MicroPython после некоторых ошибок продолжает попытки, поэтому через 20 секунд скрипт печатает последний статус:

Python
1import network, time
2
3AG_ADI = "EvAgi_2G"       # Wi-Fi adı / network name
4SIFRE = "sifre1234"       # Wi-Fi şifresi / Wi-Fi password
5
6wlan = network.WLAN(network.STA_IF)
7wlan.active(True)
8if wlan.isconnected():
9    wlan.disconnect()     # eski bağlantıyı kapat / close the previous connection
10    time.sleep(1)
11wlan.connect(AG_ADI, SIFRE)
12
13durum = wlan.status()
14for saniye in range(20):  # en fazla 20 sn bekle / wait up to 20 s
15    durum = wlan.status()
16    print(saniye, "durum / status:", durum)
17    if durum in (network.STAT_GOT_IP, network.STAT_NO_AP_FOUND, network.STAT_WRONG_PASSWORD):
18        break             # sonuç belli, beklemeyi bırak / result is known, stop waiting
19    time.sleep(1)
20
21if durum == network.STAT_GOT_IP:
22    print("Bagli / Connected, IP:", wlan.ifconfig()[0])
23    print("RSSI:", wlan.status("rssi"), "dBm")
24elif durum == network.STAT_NO_AP_FOUND:
25    print("Ag bulunamadi / Network not found (SSID, 2.4 GHz)")
26elif durum == network.STAT_WRONG_PASSWORD:
27    print("Sifre yanlis / Wrong password")
28else:
29    print("Baglanamadi / Failed, durum / status:", durum)

На Pico W числовые значения статуса другие: 3 означает «подключено, IP получен», 2 — «подключено, ждёт IP», -1 — общая ошибка, -2 — сеть не найдена, а -3 — неверный пароль. На ESP32 вместо этого во время подключения будет 1001, после получения IP 1010, а при проблемах коды причин ESP-IDF вроде 201 и 202. Чтобы на Pico W не было проблем с каналами 12 и 13, перед подключением укажи код страны (rp2.country('GB') или на новых прошивках network.country('GB'), подставив свою страну); если соединение время от времени рвётся, энергосбережение можно выключить через wlan.config(pm=0xa11140). Как сделать веб-сервер на Pico W, смотри в статье Веб-сервер Wi-Fi на Pico W, а если MicroPython для тебя в новинку, загляни в руководство Основы MicroPython.

Частые проблемы и решения

СимптомВероятная причинаРешение
Мусорные символы в мониторе портаНе совпадает скорость (бод)Выставь в мониторе порта 115200 бод
Статус 1, причина 201Неверное имя сети, сеть 5 GHz или слишком далекоЗапусти сканер и точно скопируй имя сети 2,4 GHz
Статус 6, причина 15 снова и сноваНеверный парольВведи пароль заново, следя за регистром и специальными символами
Статус 4 или 6; причина 202, 210 или 211Несовместимый режим безопасностиПереключи роутер на WPA2-Personal (AES) или смешанный WPA2/WPA3
Застревает на статусе 0Подключена к роутеру, но не получает IP по DHCPПерезагрузи роутер, расширь пул DHCP или используй статический IP
Сброс на WiFi.begin() с сообщением Brownout detector was triggeredИсточник питания не справляется с пиками токаКороткий кабель, адаптер не меньше 1 A, 470 µF между 3V3 и GND
Подключается, а через несколько минут отваливается (причина 200)Слабый сигнал, modem sleep или проблема с питаниемsetSleep(false), setTxPower, скетч переподключения, ближе к роутеру
На столе работает, в корпусе не подключаетсяМеталлический корпус или аккумулятор перед антеннойРазмести антенну у края корпуса, наружу, используй пластиковый корпус
Подключено, но веб-страница не открывается на телефонеТелефон в другой сети или в гостевой сети включена изоляция клиентовПодключи оба устройства к одной сети и возьми IP из монитора порта
Значения analogRead() портятся при включённом Wi-FiДатчик на пине ADC2, а Wi-Fi использует ADC2Перенеси датчик на пины ADC1, GPIO 32–39
Дальность в несколько сантиметров на ESP32-CAM или плате с внешней антеннойВыбрана внешняя антенна, но она не подключенаПодключи антенну к разъёму IPEX или проверь резистор 0 Ω выбора антенны на плате
При поиске неисправности держись порядка: сначала тестом с точкой доступа определи, в чём проблема, в роутере или в плате, затем сканером проверь, видна ли сеть, потом прочитай статус и код причины из диагностического скетча и только после этого переходи к питанию и настройкам роутера. Меняй что-то одно за раз. Если есть подозрение на выбор пинов, схему выводов своей платы можно посмотреть в утилите распиновки; если используется ESP32-CAM, подробности об антенне есть в статье ESP32-CAM.

Подключение есть: что теперь можно собрать?

  • Веб-сервер и живая панель: сделай веб-сервер на ESP32 с WebSocket, который в реальном времени показывает значения датчиков на телефоне.
  • Интернет-часы: получай время с NTP-сервера и выводи его на дисплей.
  • Погодный дисплей: получай температуру и влажность в своём городе через погодный API.
  • Уведомления на телефон: отправляй сообщение через Telegram-бота, когда открывается дверь.
  • Умный дом: подключи ESP32 к Home Assistant через MQTT.
  • Связь без роутера: пусть две платы ESP32 общаются по ESP-NOW, не подключаясь ни к какой сети.
  • Беспроводная загрузка: когда плата уже запечатана в корпусе, отправляй новый код по Wi-Fi с помощью обновления OTA.

ESP32, которая не подключается к Wi-Fi, поначалу сбивает с толку, но коды статуса и причины всегда подсказывают, на каком шаге проблема: 1 и 201 означают, что сеть не найдена, 15 и 202 указывают на пароль или режим безопасности, 0 на DHCP, а 200 или внезапные перезагрузки на сигнал или питание. Если ESP32 для тебя в новинку, основы найдёшь в статье Что такое ESP32?. В приложении BlueGrays есть и проекты вроде подключения ESP32 к Wi-Fi, веб-сервера, mDNS, часов с NTP, метеостанции, обновления OTA и сигнализации в Telegram, каждый с пошаговыми схемами подключения и готовым кодом.

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

Почему ESP32 не подключается к Wi-Fi?

Самые частые причины: попытка подключиться к сети 5 GHz, опечатка в имени сети или пароле, слабое питание, напряжение которого проседает при запуске Wi-Fi, и настройки безопасности роутера. Выведи значение WiFi.status() и код причины, который приходит при обрыве, и сразу станет видно, что именно. Если сеть не найдена, будут 1 и 201; при неверном пароле обычно 6 и 15.

Может ли ESP32 подключиться к Wi-Fi 5 GHz?

Классическая ESP32, ESP32-S2, S3, C3 и C6 поддерживают только 2,4 GHz и при сканировании никогда не видят сети 5 GHz. Двухдиапазонная модель — ESP32-C5. Если роутер вещает два диапазона под разными именами, укажи ESP32 имя сети 2,4 GHz.

Что означает WiFi.status() 6 на ESP32?

6 означает WL_DISCONNECTED: плата не подключена, а попытка подключения либо ещё идёт, либо не удалась. На ESP32 неверный пароль часто даёт это значение вместо 4 (WL_CONNECT_FAILED). Чтобы увидеть настоящую причину, проверь код причины в событии ARDUINO_EVENT_WIFI_STA_DISCONNECTED.

Почему ESP32 постоянно отключается от Wi-Fi?

Основные причины повторяющихся обрывов: слабый сигнал, питание, которое не справляется с пиками тока Wi-Fi, металл или аккумулятор перед антенной и настройки band steering на роутере. Поставь плату ближе к роутеру, добавь конденсатор 100–470 µF между 3V3 и GND и выключи modem sleep через WiFi.setSleep(false). И напиши код так, чтобы он восстанавливался после обрыва соединения без посторонней помощи.

Может ли ESP32 подключиться к точке доступа на телефоне?

Да, если точка доступа вещает на 2,4 GHz. На Android выбери для точки доступа диапазон 2,4 GHz, на iPhone включи «Максимальная совместимость» и оставь имя точки доступа простым. Тест с точкой доступа быстрее всего показывает, в чём проблема: в домашнем роутере или в ESP32.

Может ли ESP32 подключиться к eduroam или школьной сети?

ESP32 может подключаться к сетям WPA2-Enterprise вроде eduroam с помощью формы WiFi.begin(name, WPA2_AUTH_PEAP, identity, username, password) из ядра ESP32 для Arduino. Но в сетях, которые открывают страницу входа в браузере (captive portal), ESP32 не может заполнить эту страницу. Перед использованием сети организации лучше посоветоваться с ИТ-отделом и по возможности попросить отдельную учётную запись для устройств.

Все проекты
Подключение ESP32 к Wi-Fi в режиме STA (с экраном LCD)
#127Продвинутый

Подключение ESP32 к Wi-Fi в режиме STA (с экраном LCD)

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

4.4(21)
34
Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)
#129Продвинутый

Асинхронный веб-сервер на ESP32 (с выводом IP на LCD)

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

4.8(16)
26
mDNS на ESP32: доступ к устройству через bluegrays-esp.local (с экраном LCD)
#131Продвинутый
Premium

mDNS на ESP32: доступ к устройству через bluegrays-esp.local (с экраном LCD)

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

4.8(14)
23
Точное время из интернета через NTP на ESP32
#128Продвинутый
Premium

Точное время из интернета через NTP на ESP32

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

4.5(13)
21
ESP32 HTTPClient + API погоды (с экраном LCD)
#133Продвинутый
Premium

ESP32 HTTPClient + API погоды (с экраном LCD)

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

4.7(13)
20
Обновление ESP32 по воздуху (OTA): беспроводная установка прошивки (с экраном LCD)
#132Продвинутый
Premium

Обновление ESP32 по воздуху (OTA): беспроводная установка прошивки (с экраном LCD)

В этом проекте ты узнаешь, как загружать новую прошивку в ESP32 по Wi-Fi без USB-кабеля. С библиотекой ArduinoOTA ESP32 становится видна в сети и автоматически появляется как bluegrays-ota на вкладке «Сетевой порт» в Arduino IDE. Первая загрузка выполняется по USB, а все следующие обновления — без проводов: это важно для устройств в эксплуатации. I2C LCD показывает состояние Wi-Fi, IP-адрес, имя хоста, процент загрузки OTA и сообщения об ошибках.

4.6(14)
22
Счётчик на WebSocket с ESP32 (2 кнопки + LCD + веб в реальном времени)
#130Продвинутый
Premium

Счётчик на WebSocket с ESP32 (2 кнопки + LCD + веб в реальном времени)

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

4.5(14)
23
Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)
#145Продвинутый
Premium

Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)

Умная охранная сигнализация, которая при обнаружении движения PIR-датчиком включает зуммер и светодиод и одновременно сразу отправляет владельцу уведомление в Telegram. В ней есть 30-секундная пауза, ограничивающая частоту повторных тревог; этот механизм не проверяет срабатывания PIR и не устраняет ложные тревоги. Подходит для дома, гаража, склада или мастерской. С ESP32-CAM можно добавить уведомления с фото, а с обычной ESP32 DevKit V1 приходят текстовые.

0.0(0)
9