ESP32 OTA с порталом захвата SPIFFS
Мне нужна помощь в модификации моего текущего кода для поддержки интерфейса Captive Portal, а также библиотеки ElegantOTA, которую я использую. Моя текущая проблема заключается в том, что я не могу получить доступ к странице ElegantOTA, когда у меня активен код авторизованного портала. Что мне удалось сделать после загрузки скетча, так это получить доступ к порталу авторизации, но не к странице ElegantOTA/update. Вместо этого он просто перенаправлял меня на страницу index.html при добавлении /update к URL-адресу авторизованного портала esp32.
У меня закончились идеи, потому что я не могу перейти на страницу /update, работающую на моей плате разработки ESP32 (я использую плату DOIT DEVKIT V1, чтобы прояснить ситуацию на случай возникновения путаницы). Если бы кто-нибудь мог помочь мне понять, что не так с моим кодом и почему он продолжает перенаправлять меня на index.html вместо страницы /update, я был бы очень признателен.
Вот вся папка .ino плюс папка с данными, если вы хотите попробовать загрузить все:
CaptivePortal-OTA.zip
Вот код, который я пытаюсь исправить:
// Добавляем необходимые библиотеки для корректной работы
#include <AsyncTCP.h>
#include <DNSServer.h>
#include <ESPAsyncWebServer.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <AsyncElegantOTA.h>
// Библиотеки SPI Flash File System для загрузки html-файлов в ESP32
#include <FS.h>
#include <SPIFFS.h>
// Последовательные контакты, необходимые для передачи полученных команд от SPIFFS к Arduino Uno
#define RXp2 16
#define TXp2 17
DNSServer dnsServer;
AsyncWebServer server(80);
// Сетевые учетные данные, используемые для создания локальной сети WiFi:
// SSID сети и пароль авторизованного портала.
const char ssid[] = "ESP32 Access Point";
const char password[] = "PasswordWasChanged";
/**
* @brief List SPIFFS directory in Serial Monitor for storage mounting.
*
* @param fs File system handle.
* @param dirname Directory name.
* @param levels Maximum number of subdirectories to recurse into.
*/
void listDir(fs::FS &fs, const char* dirname, uint8_t levels)
{
Serial.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if (!root)
{
Serial.println("− failed to open directory");
return;
}
if (!root.isDirectory())
{
Serial.println(" − not a directory");
return;
}
File file = root.openNextFile();
while (file)
{
if (file.isDirectory())
{
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels)
{
listDir(fs, file.name(), levels - 1);
}
}
else
{
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
/**
* @brief Captive Request Handler for Captive Portal.
*
* Main calls for all files go in this class.
*/
class CaptiveRequestHandler : public AsyncWebHandler
{
public:
CaptiveRequestHandler();
virtual ~CaptiveRequestHandler() = default;
/**
* @brief Is this class able to handle asynchronous requests?
*
* @param request Asynchronous request to check whether we can process it.
* @return true The client will automatically download the page.
* @return false The client must manually download the page.
*/
bool canHandle(AsyncWebServerRequest* request);
/**
* @brief When a client connects, this request should send them the main page.
* @param request Asynchronous request to process.
*/
void handleRequest(AsyncWebServerRequest* request);
};
CaptiveRequestHandler::CaptiveRequestHandler()
{
// Определяет все основные HTML-страницы, которые будут возвращены как один из асинхронных ответов.
// Предоставляем страницу 404 на случай, если страница не может быть найдена.
server.onNotFound([] (AsyncWebServerRequest* request)
{
// Этот файл намеренно отсутствует.
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/notFound.html", "text/html");
request->send(response);
});
// Каталог .data/ является корневым каталогом сервера SPIFFS и содержит следующие файлы.
server.on("/", HTTP_GET, [] (AsyncWebServerRequest* request)
{
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/index.html", "text/html");
request->send(response);
Serial.println("Client Connected and Requested Main Page");
});
server.on("/lightswitch.html", HTTP_GET, [] (AsyncWebServerRequest* request)
{
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/lightswitch.html", "text/html");
request->send(response);
Serial.println("Client Requested Lightswitch Page");
});
server.on("/whistle.html", HTTP_GET, [] (AsyncWebServerRequest* request)
{
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/whistle.html", "text/html");
request->send(response);
Serial.println("Client Requested Whistle Page");
});
server.on("/stereo.html", HTTP_GET, [] (AsyncWebServerRequest* request)
{
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/stereo.html", "text/html");
request->send(response);
Serial.println("Client Requested Stereo Page");
});
// Определение всех файлов CSS и PNG
server.on("/web.css", HTTP_GET, [] (AsyncWebServerRequest* request)
{
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/web.css", "text/css");
request->send(response);
});
server.on("/layout.css", HTTP_GET, [] (AsyncWebServerRequest* request)
{
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/layout.css", "text/css");
request->send(response);
});
server.on("/header-line.png", HTTP_GET, [] (AsyncWebServerRequest* request)
{
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/header-line.png", "image/png");
request->send(response);
});
}
bool CaptiveRequestHandler::canHandle(AsyncWebServerRequest* request)
{
return true;
}
void CaptiveRequestHandler::handleRequest(AsyncWebServerRequest* request)
{
// Когда кто-то подключается (клиент), какую страницу ему следует предоставить (index.html) и следует ли ее загружать (false)
request->send(SPIFFS, "/index.html", String(), false);
}
/**
* @brief Defines the actions that the buttons on the various pages perform when clicked.
*
* When a button is pressed, send a command through Serial2 to the listening Arduino Uno.
* Example: Flip the lightswitch on or off, or create a shrill whistling sound.
*/
void setupServer()
{
// Обработка при нажатии одной из кнопок Lightswitch.
server.on("/on", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("ON"); });
server.on("/off", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("OFF"); });
server.on("/lock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("LOCK"); });
server.on("/unlock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("UNLOCK"); });
server.on("/rlock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("LOCK REMOTE"); });
server.on("/runlock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("UNLOCK REMOTE"); });
server.on("/hlock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("HIDDEN LOCK"); });
server.on("/hunlock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("HIDDEN UNLOCK"); });
server.on("/alock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("LOCK ALL"); });
server.on("/aunlock", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("UNLOCK ALL"); });
// Обработка при нажатии одной из кнопок свистка.
server.on("/TooterTutor", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("TooterTutor"); });
server.on("/AndOrButt", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("AndOrButt"); });
server.on("/DieSpiderDie", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("DieSpiderDie"); });
server.on("/StompGoblin", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("StompGoblin"); });
// Обработка при нажатии одной из кнопок Stereo.
// Передает серию ИК-информации на стереосистему с ИК-управлением.
// Все еще в процессе!
server.on("/stereo_power", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_power"); });
server.on("/stereo_cd", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_cd"); });
server.on("/stereo_mute", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_mute"); });
server.on("/stereo_aux", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_aux"); });
server.on("/stereo_bt", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_bt"); });
server.on("/stereo_fm", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_fm"); });
server.on("/stereo_rr", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_rr"); });
server.on("/stereo_play", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_play"); });
server.on("/stereo_ff", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_ff"); });
server.on("/stereo_rpt", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_rpt"); });
server.on("/stereo_stop", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_stop"); });
server.on("/stereo_prog", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_prog"); });
server.on("/stereo_voldown", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_voldown"); });
server.on("/stereo_bass", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_bass"); });
server.on("/stereo_volup", HTTP_GET, [] (AsyncWebServerRequest* request) { Serial2.write("stereo_volup"); });
}
/**
* @brief Set up the Serial and Serial2 loggers, as well as SPIFFS and so forth.
*/
void setup()
{
// Запускаем как Serial (последовательный монитор), так и Serial2 (связь с Arduino Uno)
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXp2, TXp2);
// Начните с IR_SEND_PIN в качестве вывода отправки, и если NO_LED_FEEDBACK_CODE НЕ определено, включите светодиод обратной связи на выводе светодиода обратной связи по умолчанию
//IrSender.begin();
// Если SPIFFS не смонтирована, выдать ошибку в Serial Monitor.
if (!SPIFFS.begin(true))
{
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
// Список содержимого SPIFFS в Serial Monitor.
listDir(SPIFFS, "/", 0);
// Запуск режима точки доступа с ssid и паролем, определенными ранее, и вывод информации
Serial.println();
Serial.println("Setting up AP Mode");
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
auto wifi_ip_address = WiFi.softAPIP();
// Выводим IP-адрес точки доступа, а затем настраиваем асинхронный веб-сервер
Serial.print("AP IP address: ");
Serial.println(wifi_ip_address);
Serial.println("Setting up Async WebServer");
setupServer();
// Запускаем DNS-сервер и добавляем CaptiveRequestHandler, который был определен ранее
Serial.println("Starting DNS Server");
dnsServer.start(53, "*", wifi_ip_address);
// Только при запросе от точки доступа
// server.addHandler(новый CaptiveRequestHandler()).setFilter(ON_AP_FILTER);
// Запускаем ElegantOTA
AsyncElegantOTA.begin(&server);
// Запускаем сервер
server.begin();
Serial.println("All Done!");
}
void loop()
{
dnsServer.processNextRequest();
}
@Panda Tutor, 👍-1
Обсуждение0
- Почему OTA не работает с платой ESP32-CAM Ai-Thinker?
- Загрузка данных SPIFFS в Arduino IDE 2.0.0-rc3 (ESP32 & TTGO) - Ubuntu
- ОТА-программа SPIFFS на ESP8266
- Как записать и прочитать из файла SPIFFS как данные объекта на ESP8266
- ESP32 - ошибка при использовании LITTLEFS.h после обновления ядра до 2.0.4
- ESP-32 Загрузка файлов в SPIFFS через браузер
- Esp32: совместим ли OTA с FREERTOS
- ESP32 AsyncWebServer SPIFFS проблема со страницей загрузки
слово **обновление** отсутствует в вашем коде, @jsotola