• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Автооткрытие страницы при подключении к WiFi

Thest

New member
Всех приветствую, накатал небольшой скетч, штрудируя просторы форумов и видеоуроков.
Прошу помощи в доработке, ткнуть носом нужную кучу.. информации.
Скетч создаёт точку доступа и при подключении к ней на андроиде либо автоматом открывается веб-интерфейс, либо всплывает уведомление, нажав на которое - открывается интерфейс.
Так вот, на яблочной мобилке это не работает, может кто знает в чём причина?
Суть кода - перенаправление любого веб запроса на интерфейс, можно в браузере вбить любой адрес (хоть "йух.рф") откроет интерфейс ЕСП. Т.е. андроид при подключении к новой сети пингует что-то и вместо этого перенаправляется на интерфейс ЕСПхи.
Интерфейс можно залить любой через ФТП, главное чтобы назывался index.html (Спасибо за это каналу iomoio)
Логопас от ФТП "login","pass"
IP Esp изменён на 192, 168, 10, 1

Код:
#include <ESP8266WiFi.h>                                                // Библиотека для создания Wi-Fi подключения (клиент или точка доступа)
#include <ESP8266WebServer.h>                                           // Библиотека для управления устройством по HTTP (например из браузера)
#include <FS.h>                                                         // Библиотека для работы с файловой системой
#include <ESP8266FtpServer.h>                                           // Библиотека для работы с SPIFFS по FTP
#include <DNSServer.h>
#include <ESP8266mDNS.h>

unsigned int status = WL_IDLE_STATUS;
const byte DNS_PORT = 53;
const char *ssid = "MyWiFi";                      

IPAddress apIP(192, 168, 10, 1);
DNSServer dnsServer;
ESP8266WebServer HTTP(80);                                              // Определяем объект и порт сервера для работы с HTTP
FtpServer ftpSrv;                                                       // Определяем объект для работы с модулем по FTP (для отладки HTML)

void setup() {

WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP(ssid);  
  dnsServer.setTTL(300);// Создаём точку доступа
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(DNS_PORT, "*", apIP);
   
  SPIFFS.begin();                                                       // Инициализируем работу с файловой системой                        
  HTTP.begin();                                                         // Инициализируем Web-сервер
  ftpSrv.begin("login","pass");                                        // Поднимаем FTP-сервер для удобства отладки работы HTML (логин: relay, пароль: relay)

  delay(500);


HTTP.on("/generate_204", handleRoot);
 
  HTTP.onNotFound([](){                                                 // Описываем действия при событии "Не найдено"
  if(!handleFileRead(HTTP.uri()))                                       // Если функция handleFileRead (описана ниже) возвращает значение false в ответ на поиск файла в файловой системе
      HTTP.send(404, "text/plain", "Not Found");                        // возвращаем на запрос текстовое сообщение "File isn't found" с кодом 404 (не найдено)
  });

}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
      MDNS.update();}
   dnsServer.processNextRequest();
    HTTP.handleClient();                                                // Обработчик HTTP-событий (отлавливает HTTP-запросы к устройству и обрабатывает их в соответствии с выше описанным алгоритмом)
    ftpSrv.handleFTP();                                                 // Обработчик FTP-соединений


}

void handleRoot() {

  HTTP.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  HTTP.sendHeader("Pragma", "no-cache");
  HTTP.sendHeader("Expires", "-1");
handleFileRead("/");
}




bool handleFileRead(String path){                                       // Функция работы с файловой системой
  if(path.endsWith("/")) path += "index.html";                          // Если устройство вызывается по корневому адресу, то должен вызываться файл index.html (добавляем его в конец адреса)
  String contentType = getContentType(path);                            // С помощью функции getContentType (описана ниже) определяем по типу файла (в адресе обращения) какой заголовок необходимо возвращать по его вызову
  if(SPIFFS.exists(path)){                                              // Если в файловой системе существует файл по адресу обращения
    Serial.println("settings");
    File file = SPIFFS.open(path, "r");                                 //  Открываем файл для чтения
    size_t sent = HTTP.streamFile(file, contentType);                   //  Выводим содержимое файла по HTTP, указывая заголовок типа содержимого contentType
    file.close();                                                       //  Закрываем файл
    return true;                                                        //  Завершаем выполнение функции, возвращая результатом ее исполнения true (истина)
  }
  return false;                                                         // Завершаем выполнение функции, возвращая результатом ее исполнения false (если не обработалось предыдущее условие)
}

String getContentType(String filename){                                 // Функция, возвращающая необходимый заголовок типа содержимого в зависимости от расширения файла
  if (filename.endsWith(".html")) return "text/html";                   // Если файл заканчивается на ".html", то возвращаем заголовок "text/html" и завершаем выполнение функции
  else if (filename.endsWith(".css")) return "text/css";                // Если файл заканчивается на ".css", то возвращаем заголовок "text/css" и завершаем выполнение функции
  else if (filename.endsWith(".js")) return "application/javascript";   // Если файл заканчивается на ".js", то возвращаем заголовок "application/javascript" и завершаем выполнение функции
  else if (filename.endsWith(".png")) return "image/png";               // Если файл заканчивается на ".png", то возвращаем заголовок "image/png" и завершаем выполнение функции
  else if (filename.endsWith(".jpg")) return "image/jpeg";              // Если файл заканчивается на ".jpg", то возвращаем заголовок "image/jpg" и завершаем выполнение функции
  else if (filename.endsWith(".gif")) return "image/gif";               // Если файл заканчивается на ".gif", то возвращаем заголовок "image/gif" и завершаем выполнение функции
  else if (filename.endsWith(".ico")) return "image/x-icon";            // Если файл заканчивается на ".ico", то возвращаем заголовок "image/x-icon" и завершаем выполнение функции
  return "text/plain";                                                  // Если ни один из типов файла не совпал, то считаем что содержимое файла текстовое, отдаем соответствующий заголовок и завершаем выполнение функции
}
 

Thest

New member
Вот тут нашёл, человек объясняет, почему мой код работает.
В кратце запрос у гугла есть "/generate_204" который узнаёт есть ли интернет, если ответ от другого сервера, то открывается страница вашего оператора (например закинь денег на счёт и вернём интернет)
Нужен яблочный аналог, кто в курсе? или как промониторить входящие запросы от мобилки?

HTTP.on("/generate_204", handleRoot);

Тут идёт сверка запроса когда знаешь результат заранее, а как вывести в Serial если неивестен запрос? Кто-нибудь знаком с этими библиотеками?
 

Thest

New member
Нагуглил, что то что мне нужно называется "Captive Portal". Продолжаю копать... Пока всё что я нашёл, примерно как и у меня, за исключением FTP. и работает так же на андроиде и линухе.. Винда и Аппле не работат.. копаем дальше..
 

enjoynering

Well-known member
если нужен "Captive Portal" на AP_MODE, то пропишите Gateway такой же как у AP (в arduino это 192.168.4.1). на винде такое точно работает, а вот с android помоему не очень (сильно не тестил). имнно так сделанно в проекте WLED.
 
Сверху Снизу