From dc2b194465014bfc328531ecf578c0070ca0dcdf Mon Sep 17 00:00:00 2001 From: Martin Verges Date: Mon, 6 Jan 2025 13:21:38 -0400 Subject: [PATCH] add a build in UI --- README.md | 12 +- documentation/ui.png | Bin 0 -> 38884 bytes examples/src/main.cpp | 3 +- wifimanager.cpp | 406 ++++++++++++++++++++++++++++++++++++++++++ wifimanager.h | 6 +- 5 files changed, 422 insertions(+), 5 deletions(-) create mode 100644 documentation/ui.png diff --git a/README.md b/README.md index 8a0607c..0d9d7a6 100644 --- a/README.md +++ b/README.md @@ -29,12 +29,18 @@ It is only made and tested it on my ESP32 Microcontroller. ### More detailed flow diagram -Flow diagram +Flow diagram ## What do I need to do? -If you want to use this wifi manager, you have to create your own Web UI for it! -It won't give you a premade styled UI to configure the SSID credentials. +If you want to use this wifi manager, you can create your own Web UI or use a prebuild one available at `/wifi`! + +## Build in UI + +The UI route is only loaded to `/wifi` if you execute `attachUI()` inside your script. + +Build in UI + ## APIs diff --git a/documentation/ui.png b/documentation/ui.png new file mode 100644 index 0000000000000000000000000000000000000000..4d96ab353add49025ec5ed7258cd49954269500f GIT binary patch literal 38884 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 - * @copyright 2022 + * @copyright 2022-2025 * * Licensed under CC BY-NC-SA 4.0 * (Attribution-NonCommercial-ShareAlike 4.0 International) @@ -24,6 +24,7 @@ void setup() { WifiManager.startBackgroundTask(); // Run the background task to take care of our Wifi WifiManager.fallbackToSoftAp(true); // Run a SoftAP if no known AP can be reached WifiManager.attachWebServer(&webServer); // Attach our API to the Webserver + WifiManager.attachUI(); // Attach the UI to the Webserver // Run the Webserver and add your webpages to it webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ diff --git a/wifimanager.cpp b/wifimanager.cpp index 401ef39..6b7c310 100644 --- a/wifimanager.cpp +++ b/wifimanager.cpp @@ -770,3 +770,409 @@ void WIFIMANAGER::attachWebServer(WebServer * srv) { #endif }); } + +/** + * @brief Attach the WebServer to the WifiManager to register the RESTful API + * @param srv WebServer object + */ +void WIFIMANAGER::attachUI() { + +#if ASYNC_WEBSERVER == true + webServer->on((uiPrefix).c_str(), HTTP_GET, [](AsyncWebServerRequest* request) { +#else + webServer->on((uiPrefix).c_str(), HTTP_GET, [&]() { +#endif + + String html = R"html( + + + + + + ESP32 WiFi Manager + + + +
+
+

ESP32 WiFi Manager

+
+ + +
+ +
+

Available Networks

+
+
+ +
+

Saved Networks

+
+
+
+ + + + + + +)html"; + +#if ASYNC_WEBSERVER == true + request->send(200, "text/html", html); +#else + webServer->send(200, "text/html", html); +#endif + + }); +} \ No newline at end of file diff --git a/wifimanager.h b/wifimanager.h index 87037f0..99a9ef2 100644 --- a/wifimanager.h +++ b/wifimanager.h @@ -1,6 +1,6 @@ /** * Wifi Manager - * (c) 2022 Martin Verges + * (c) 2022-2025 Martin Verges * * Licensed under CC BY-NC-SA 4.0 * (Attribution-NonCommercial-ShareAlike 4.0 International) @@ -35,6 +35,7 @@ class WIFIMANAGER { WebServer * webServer; // The Webserver to register routes on #endif String apiPrefix = "/api/wifi"; // Prefix for all IP endpionts + String uiPrefix = "/wifi"; // Prefix for all UI endpionts Preferences preferences; // Used to store AP credentials to NVS char * NVS; // Name used for NVS preferences @@ -90,6 +91,9 @@ class WIFIMANAGER { void attachWebServer(WebServer * srv); #endif + // Attach an UI + void attachUI(); + // Add another AP to the list of known WIFIs bool addWifi(String apName, String apPass, bool updateNVS = true);