|
В экосистеме ESP-IDF реализация captive portal — это популярный и хорошо документированный подход для первоначальной настройки Wi-Fi на устройстве. Существует несколько готовых решений, от официальных примеров до специализированных компонентов, каждое со своими особенностями.
[Основной принцип работы]
Большинство решений для captive portal в ESP-IDF работают по следующему сценарию:
1. Попытка подключения: при загрузке устройство пытается подключиться к сохраненной в энергонезависимой памяти (NVS) Wi-Fi сети в режиме станции (STA). 2. Запуск точки доступа: если подключение не удалось или данных нет, устройство переключается в режим точки доступа (SoftAP) и создает собственную Wi-Fi сеть. 3. Перехват трафика: запускается DNS-сервер, который отвечает на все запросы IP-адресом самого устройства. Это заставляет операционные системы (Android, iOS, Windows) распознать наличие captive portal и автоматически открыть окно для входа. 4. Настройка через веб-интерфейс: пользователь подключается к точке доступа устройства, его автоматически перенаправляет на встроенную веб-страницу. На этой странице он выбирает свой домашний Wi-Fi из списка и вводит пароль. 5. Сохранение и перезагрузка: введенные данные сохраняются в NVS, и устройство перезагружается, чтобы подключиться к указанной сети уже в режиме станции.
[Обзор доступных решений]
Вот несколько проверенных компонентов и примеров, которые можно использовать в проекте.
| Название / Решение |
Ключевые особенности |
Способ установки / Примечания |
| Официальный пример ESP-IDF |
Базовый пример, демонстрирующий работу DNS и HTTP серверов для captive portal. Хорошая отправная точка для понимания принципов. |
Входит в состав ESP-IDF. Ищите в папке examples/ каталога установки ESP-IDF (например ~/esp/v5.4.1/esp-idf/examples/protocols/http_server/captive_portal/). |
| nordesems/esp-captive-portal |
Минималистичный компонент для перехвата запросов от всех основных ОС (iOS, Android, Windows). Требует только одного вызова функции и не имеет внешних зависимостей. |
Устанавливается через компонентный менеджер: idf.py add-dependency "nordesems/esp-captive-portal^1.0.0". |
| MichMich/esp-idf-wifi-provisioner |
Полноценный менеджер с автоматическим переключением между режимами, богатыми настройками через menuconfig (текст страниц, таймауты) и возможностью менять конфигурацию во время выполнения. |
Устанавливается через компонентный менеджер. |
| tuanpmt/esp_wifi_manager |
Очень функциональное решение с поддержкой нескольких сетей, веб-интерфейсом на Preact (~10КБ), REST API и даже BLE для настройки. |
Устанавливается через компонентный менеджер. Поддерживает mDNS для доступа по локальному имени. |
| Dwarf1er/esp-wifi-provisioning |
Решение на языке Rust, построенное на базе esp-idf-svc. Отличный вариант, если проект разрабатывается на Rust для ESP32. |
Устанавливается через cargo. |
Выбор зависит от требований вашего проекта:
● Для обучения и простого проекта: начните с официального примера ESP-IDF. Он поможет разобраться в деталях реализации. ● Для быстрой интеграции минимального функционала: используйте nordesems/esp-captive-portal — он легковесен и максимально прост в подключении. ● Для типового IoT-продукта: отличным выбором будет MichMich/esp-idf-wifi-provisioner или tuanpmt/esp_wifi_manager. Они предоставляют готовый пользовательский интерфейс, надежную логику работы и гибкие настройки. ● Для проекта на Rust: стоит обратить внимание на esp-wifi-provisioning.
Все эти решения используют стандартные компоненты ESP-IDF и предоставляют удобный способ внедрить удобную настройку Wi-Fi в ваше устройство.
[Запуск стандартного http_server/captive_portal]
Здесь по шагам описан процесс запуска официального примера ESP-IDF из каталога ~/esp/v5.4.1/esp-idf/examples/protocols/http_server/captive_portal/.
Шаг 1. Скопируйте пример в папку с вашими проектами (например, это папка ~/myproj).
cp -r ~/esp/v5.4.1/esp-idf/examples/protocols/http_server/captive_portal ~/myproj
Шаг 2. Выберите целевой процессор для проекта (например ESP32-S3).
cd ~/myproj/captive_portal . $HOME/esp/v5.4.1/esp-idf/export.sh idf.py set-target esp32s3
Шаг 3. Настройте проект (командой idf.py menuconfig - опционально).
При необходимости вы можете изменить параметры точки доступа и портала через меню конфигурации. Обычно они находятся в разделе Example Configuration. Запустите конфигуратор командой:
idf.py menuconfig
Перейдите в раздел Example Configuration. Здесь вы сможете настроить параметры точки доступа.

Шаг 4. Сборка и прошивка проекта.
idf.py build flash monitor -p /dev/ttyACM0
После прошивки устройство запустится. Если у него нет сохраненных учетных данных для Wi-Fi, оно создаст точку доступа (SoftAP). Подключитесь к ней с телефона или компьютера, и портал захвата должен открыться автоматически и открыть заданную страницу. В этом простом примере откроется страничка приветствия (но это может быть и другая страница, например показывающее управление настройками Wi-Fi):

[Проблема Captive Portal на некоторых OS]
На устройстве Android при подключении к точке доступа esp32_ssid автоматически открылся браузер со стартовой страницей:
ESP Captive Portal Hello World, this is ESP32!
Но на операционной системе Kubuntu 24.04 при подключении к точке доступа браузер не запустился, пришлось вручную вбивать в строке адреса http://192.168.4.1, только после этого открылась та же страница. То же самое на Ubuntu 24.04.4 LTS. Почему?
Наблюдаемое поведение связано не с ошибкой в вашем ESP32, а с различиями в том, как операционные системы и браузеры обнаруживают captive-порталы. Android настроен на автоматическое открытие страницы входа, а Kubuntu — нет. Вот почему это происходит.
Когда Android подключается к новой Wi-Fi сети, он автоматически отправляет запрос на специальный проверочный URL-адрес, например http://connectivitycheck.gstatic.com/generate_204.
Ожидаемый ответ: если сеть имеет доступ в интернет, этот URL должен вернуть HTTP-статус `204 No Content`.
Обнаружение портала: ваш ESP32 перехватывает этот запрос (так как он является шлюзом для этой сети) и возвращает не `204`, а либо страницу входа (код `200`), либо перенаправление (код `302`) на страницу `http://192.168.4.1`.
Реакция системы: Android распознает этот неожиданный ответ как сигнал о том, что за этим Wi-Fi скрывается captive-портал, и автоматически открывает браузер для прохождения аутентификации.
Почему Kubuntu не делает этого автоматически: ваша система Kubuntu, скорее всего, использует NetworkManager с окружением рабочего стола KDE Plasma. Механизм автоматического открытия порталов в таких дистрибутивах работает иначе и часто менее надежно.
Основная причина в том, как работает проверка соединения в Kubuntu:
1. Проверочный URL: вместо generate_204 ваша система может использовать другой URL для проверки интернета, например http://connectivity-check.ubuntu.com/ (для Ubuntu) или специальный .txt-файл для вашего дистрибутива.
2. Проблема с перехватом: некоторые версии NetworkManager, особенно в связке с KDE, при обнаружении портала пытаются открыть не IP-адрес шлюза (192.168.4.1), а тот же самый проверочный URL-адрес, с которым возникла проблема. Так как ESP32 часто настроен на перехват и перенаправление только определенных, "стандартных" URL-адресов (например, `generate_204`), он может не обработать запрос к `connectivity-check.ubuntu.com` должным образом. В итоге, проверка соединения не запускает автоматическое открытие браузера.
Кроме того, плазма-апплет KDE может использовать для открытия портала URL, который оканчивается на `.txt` (например, для Arch Linux — `https://ping.archlinux.org/nm-check.txt`). Многие реализации серверов для captive-порталов, включая ваш ESP32, не обрабатывают перенаправления для запросов к `.txt`-файлам так, как для обычных веб-страниц, что также мешает автоматическому открытию.
Как это исправить в Kubuntu. Проблема на стороне вашей ОС, и ее можно решить несколькими способами.
1. Ручное открытие: способ, который вы уже пробовали — вручную ввести в браузере адрес http://192.168.4.1 — является самым простым и универсальным решением.
2. Скрипт NetworkManager (рекомендуемое решение): можно создать скрипт, который будет автоматически открывать браузер на ссылке `http://192.168.4.1`, как только NetworkManager обнаружит состояние `PORTAL`. Это стандартное решение для Linux.
Как это сделать:
● Создайте файл скрипта, например, с помощью команды:
sudo nano /etc/NetworkManager/dispatcher.d/90-open_captive_portal
● Вставьте в этот файл следующий код (это адаптированная версия скрипта с [Arch Wiki](https://wiki.archlinux.org/title/NetworkManager#Captive_portals)):
#!/bin/sh -e # Скрипт для обработки событий NetworkManager
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
if [ -x "/usr/bin/logger" ]; then logger="/usr/bin/logger -s -t captive-portal" else logger=":" fi
wait_for_process() { PNAME=$1 while [ -z "$(/usr/bin/pgrep $PNAME)" ]; do sleep 3 done }
start_browser() { local user="$1" local display="$2" export DISPLAY="$display" wait_for_process nm-applet export XAUTHORITY="/home/$user/.Xauthority" $logger "Запуск браузера для пользователя '$user' с дисплеем '$display' для входа в captive-портал" # Открываем IP-адрес шлюза, который почти всегда является адресом портала sudo -u "$user" --preserve-env=DISPLAY,XAUTHORITY -H xdg-open http://192.168.4.1 2>&1 > /dev/null }
case "$2" in connectivity-change) $logger -p user.debug "Скрипт запущен из-за изменения подключения: $CONNECTIVITY_STATE" if [ "$CONNECTIVITY_STATE" = "PORTAL" ]; then who | awk '$NF ~ /\(:[0-9]+\)/ { print $1 " " substr($NF, 2, length($NF)-2) };' | \ while read user display; do start_browser $user $display || $logger -p user.err "Не удалось \ для пользователя: '$user' дисплей: '$display'" done fi ;; *) exit 0 ;; esac
● Сделайте файл исполняемым:
sudo chmod +x /etc/NetworkManager/dispatcher.d/90-open_captive_portal
● Перезапустите NetworkManager или перезагрузите систему:
sudo systemctl restart NetworkManager
После этого, при подключении к вашему ESP32, браузер должен открываться автоматически.
Заключение: ваш ESP32 работает корректно, автоматически открывая портал для Android. Отсутствие такой же реакции в Kubuntu — особенность его системы обнаружения порталов. Создание простого скрипта-обработчика NetworkManager решит эту проблему и сделает работу с порталом на Linux такой же удобной, как на Android.
[Ссылки]
1. ESP-IDF HTTP Server. |