From 7da7a6094cb75b6020ef26a6830a6c5f76d4a0fe Mon Sep 17 00:00:00 2001 From: Benjamin Kraus Date: Sun, 14 Dec 2025 20:04:07 -0500 Subject: [PATCH 1/6] Squashed commit of the following: commit 70fe1fc76d3d88947d4c9f8b43d58ea90f944230 Author: Benjamin Kraus Date: Fri Oct 31 20:52:13 2025 -0400 Added support for enterprise WiFi. --- platformio.ini | 4 ++-- wled00/cfg.cpp | 14 ++++++++++++++ wled00/const.h | 4 ++++ wled00/data/settings_wifi.htm | 21 ++++++++++++++++++-- wled00/fcn_declare.h | 9 ++++++++- wled00/set.cpp | 24 +++++++++++++++++++++++ wled00/wled.cpp | 36 +++++++++++++++++++++++++++++++++-- wled00/wled.h | 3 +++ wled00/xml.cpp | 7 +++++-- 9 files changed, 113 insertions(+), 9 deletions(-) diff --git a/platformio.ini b/platformio.ini index 98676c11e0..f3fbcd5a24 100644 --- a/platformio.ini +++ b/platformio.ini @@ -529,7 +529,7 @@ build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_ -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html -D DATA_PINS=25 lib_deps = ${esp32_idf_V4.lib_deps} - + [env:esp32c3dev] extends = esp32c3 platform = ${esp32c3.platform} @@ -639,7 +639,7 @@ monitor_filters = esp32_exception_decoder [env:esp32s3_4M_qspi] ;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi) -board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM +board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 47ba152c96..4678ba820d 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -114,6 +114,15 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { multiWiFi[n].staticIP = nIP; multiWiFi[n].staticGW = nGW; multiWiFi[n].staticSN = nSN; + byte encType = WIFI_ENCRYPTION_TYPE_PSK; + char anonIdent[65] = ""; + char ident[65] = ""; + CJSON(encType, wifi[F("enc_type")]); + getStringFromJson(anonIdent, wifi["e_anon_ident"], 65); + getStringFromJson(ident, wifi["e_ident"], 65); + multiWiFi[n].encryptionType = encType; + strlcpy(multiWiFi[n].enterpriseAnonIdentity, anonIdent, 65); + strlcpy(multiWiFi[n].enterpriseIdentity, ident, 65); if (++n >= WLED_MAX_WIFI_COUNT) break; } } @@ -870,6 +879,11 @@ void serializeConfig(JsonObject root) { wifi_gw.add(multiWiFi[n].staticGW[i]); wifi_sn.add(multiWiFi[n].staticSN[i]); } + wifi[F("enc_type")] = multiWiFi[n].encryptionType; + if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_ENTERPRISE) { + wifi[F("e_anon_ident")] = multiWiFi[n].enterpriseAnonIdentity; + wifi[F("e_ident")] = multiWiFi[n].enterpriseIdentity; + } } JsonArray dns = nw.createNestedArray(F("dns")); diff --git a/wled00/const.h b/wled00/const.h index 9067d9b16c..c00cc58ca8 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -208,6 +208,10 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h" #define USERMOD_ID_USER_FX 58 //Usermod "user_fx" +//Wifi encryption type +#define WIFI_ENCRYPTION_TYPE_PSK 0 //None/WPA/WPA2 +#define WIFI_ENCRYPTION_TYPE_ENTERPRISE 1 //WPA/WPA2-Enterprise + //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot #define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost) diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 65a04b9178..043e3e0bcd 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -89,7 +89,7 @@ select.appendChild(option); if (input.value === "" || input.value === "Your_Network" || found) input.replaceWith(select); - else select.remove(); + else select.remove(); } } @@ -118,11 +118,20 @@ gId("wifi_add").style.display = (i1) ? "inline":"none"; } - function addWiFi(ssid="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff) { // little endian + function addWiFi(type=0,ssid="",anon="",ident="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff) { // little endian var i = gId("wifi_entries").childNodes.length; if (i >= maxNetworks) return; var b = `

Network name (SSID${i==0?", empty to not connect":""}):
0?"required":""}>
+WiFi encryption type:
+
+
+Anonymous identity:

+Identity:

+
Network password:

BSSID (optional):

Static IP (leave at 0.0.0.0 for DHCP)${i==0?"
Also used by Ethernet":""}:
@@ -185,6 +194,14 @@ rC++; gId('+').style.display = gId("rml").childElementCount < 10 ? 'inline' : 'none'; // can't append to list anymore, hide button } + function E(i) { + const select = gId("ET"+i); + if (select.value === "0") { + gId("IDS"+i).style.display = "none"; + } else { + gId("IDS"+i).style.display = ""; + } + } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2346ee450b..256c90df0a 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -58,18 +58,25 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau typedef struct WiFiConfig { char clientSSID[33]; + byte encryptionType; char clientPass[65]; uint8_t bssid[6]; IPAddress staticIP; IPAddress staticGW; IPAddress staticSN; - WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF) // little endian + char enterpriseAnonIdentity[65]; + char enterpriseIdentity[65]; + WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF // little endian + , byte enc_type=WIFI_ENCRYPTION_TYPE_PSK, const char *ent_anon="", const char *ent_iden="") : staticIP(ip) , staticGW(gw) , staticSN(subnet) + , encryptionType(enc_type) { strncpy(clientSSID, ssid, 32); clientSSID[32] = 0; strncpy(clientPass, pass, 64); clientPass[64] = 0; + strncpy(enterpriseAnonIdentity, ent_anon, 64); enterpriseAnonIdentity[64] = 0; + strncpy(enterpriseIdentity, ent_iden, 64); enterpriseIdentity[64] = 0; memset(bssid, 0, sizeof(bssid)); } } wifi_config; diff --git a/wled00/set.cpp b/wled00/set.cpp index 087e9b39f2..d3a10707c2 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -21,7 +21,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) { unsigned cnt = 0; for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) { + char et[4] = "ET"; et[2] = 48+n; et[3] = 0; // WiFi encryption type char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID + char ea[4] = "EA"; ea[2] = 48+n; ea[3] = 0; //enterprise anonymous identity + char ei[4] = "EI"; ei[2] = 48+n; ei[3] = 0; //enterprise identity char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password char bs[4] = "BS"; bs[2] = 48+n; bs[3] = 0; //BSSID char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address @@ -29,13 +32,33 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask if (request->hasArg(cs)) { if (n >= multiWiFi.size()) multiWiFi.emplace_back(); // expand vector by one + byte oldType; oldType = multiWiFi[n].encryptionType; char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID); + char oldAnon[65]; strcpy(oldAnon, multiWiFi[n].enterpriseAnonIdentity); + char oldIden[65]; strcpy(oldIden, multiWiFi[n].enterpriseIdentity); char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass); + multiWiFi[n].encryptionType = request->arg(et).toInt(); + forceReconnect |= oldType != multiWiFi[n].encryptionType; strlcpy(multiWiFi[n].clientSSID, request->arg(cs).c_str(), 33); if (strlen(oldSSID) == 0 || !strncmp(multiWiFi[n].clientSSID, oldSSID, 32)) { forceReconnect = true; } + if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { + // PSK - Clear the anonymous identity and identity fields + multiWiFi[n].enterpriseAnonIdentity[0] = '\0'; + multiWiFi[n].enterpriseIdentity[0] = '\0'; + } else { + // WPA2-Enterprise + strlcpy(multiWiFi[n].enterpriseAnonIdentity, request->arg(ea).c_str(), 65); + strlcpy(multiWiFi[n].enterpriseIdentity, request->arg(ei).c_str(), 65); + } + if (!strncmp(multiWiFi[n].enterpriseAnonIdentity, oldAnon, 64)) { + forceReconnect = true; + } + if (!strncmp(multiWiFi[n].enterpriseIdentity, oldIden, 64)) { + forceReconnect = true; + } if (!isAsterisksOnly(request->arg(pw).c_str(), 65)) { strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65); forceReconnect = true; @@ -955,6 +978,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("NP")); //advances to next preset in a playlist if (pos > 0) doAdvancePlaylist = true; + //set brightness updateVal(req.c_str(), "&A=", bri); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 67aa0d0429..41fd502205 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -683,13 +683,45 @@ void WLED::initConnection() if (WLED_WIFI_CONFIGURED) { showWelcomePage = false; - + DEBUG_PRINTF_P(PSTR("Connecting to %s...\n"), multiWiFi[selectedWiFi].clientSSID); // convert the "serverDescription" into a valid DNS hostname (alphanumeric) char hostname[25]; prepareHostname(hostname); - WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times + if (multiWiFi[selectedWiFi].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { + DEBUG_PRINTF_P(PSTR("Using PSK\n")); +#ifndef WLED_DISABLE_WPA_ENTERPRISE +#ifdef ESP8266 + wifi_station_set_wpa2_enterprise_auth(0); + wifi_station_clear_enterprise_ca_cert(); + wifi_station_clear_enterprise_cert_key(); + wifi_station_clear_enterprise_identity(); + wifi_station_clear_enterprise_username(); + wifi_station_clear_enterprise_password(); +#endif +#endif + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times + } else { +#ifndef WLED_DISABLE_WPA_ENTERPRISE + DEBUG_PRINTF_P(PSTR("Using WPA2_AUTH_PEAP (Anon: %s, Ident: %s)\n"), multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity); +#ifdef ESP8266 + struct station_config sta_conf; + os_memset(&sta_conf, 0, sizeof(sta_conf)); + os_memcpy(sta_conf.ssid, multiWiFi[selectedWiFi].clientSSID, 32); + os_memcpy(sta_conf.password, multiWiFi[selectedWiFi].clientPass, 64); + wifi_station_set_config(&sta_conf); + wifi_station_set_wpa2_enterprise_auth(1); + wifi_station_set_enterprise_identity((u8*)(void*)multiWiFi[selectedWiFi].enterpriseAnonIdentity, os_strlen(multiWiFi[selectedWiFi].enterpriseAnonIdentity)); + wifi_station_set_enterprise_username((u8*)(void*)multiWiFi[selectedWiFi].enterpriseIdentity, os_strlen(multiWiFi[selectedWiFi].enterpriseIdentity)); + wifi_station_set_enterprise_password((u8*)(void*)multiWiFi[selectedWiFi].clientPass, os_strlen(multiWiFi[selectedWiFi].clientPass)); + wifi_station_connect(); +#else + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, WPA2_AUTH_PEAP, multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity, multiWiFi[selectedWiFi].clientPass); +#endif +#endif + } + #ifdef ARDUINO_ARCH_ESP32 WiFi.setTxPower(wifi_power_t(txPower)); diff --git a/wled00/wled.h b/wled00/wled.h index c76d48bf9b..b81d5d7810 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -77,6 +77,9 @@ #include #ifdef ESP8266 #include + #ifndef WLED_DISABLE_WPA_ENTERPRISE + #include "wpa2_enterprise.h" + #endif #include #include #include diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 194256d82e..18ae313fda 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -198,8 +198,11 @@ void getSettingsJS(byte subPage, Print& settingsScript) memset(fpass,'*',l); char bssid[13]; fillMAC2Str(bssid, multiWiFi[n].bssid); - settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X);"), + settingsScript.printf_P(PSTR("addWiFi(\"%u\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X);"), + multiWiFi[n].encryptionType, multiWiFi[n].clientSSID, + multiWiFi[n].enterpriseAnonIdentity, + multiWiFi[n].enterpriseIdentity, fpass, bssid, (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct @@ -413,7 +416,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifndef WLED_DISABLE_INFRARED printSetFormValue(settingsScript,PSTR("IR"),irPin); printSetFormValue(settingsScript,PSTR("IT"),irEnabled); -#endif +#endif printSetFormCheckbox(settingsScript,PSTR("MSO"),!irApplyToAllSelected); } From baee3c66b12fe26ee87e90009a8feed7746c6a36 Mon Sep 17 00:00:00 2001 From: Benjamin Kraus Date: Sun, 14 Dec 2025 21:27:07 -0500 Subject: [PATCH 2/6] Updated based on feedback from CodeRabbit. --- wled00/fcn_declare.h | 6 +++--- wled00/set.cpp | 6 +++--- wled00/wled.cpp | 9 ++++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 256c90df0a..ed27a536c1 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -68,10 +68,10 @@ typedef struct WiFiConfig { char enterpriseIdentity[65]; WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF // little endian , byte enc_type=WIFI_ENCRYPTION_TYPE_PSK, const char *ent_anon="", const char *ent_iden="") - : staticIP(ip) + : encryptionType(enc_type) + , staticIP(ip) , staticGW(gw) , staticSN(subnet) - , encryptionType(enc_type) { strncpy(clientSSID, ssid, 32); clientSSID[32] = 0; strncpy(clientPass, pass, 64); clientPass[64] = 0; @@ -334,7 +334,7 @@ class Usermod { static Print* oappend_shim; // old form of appendConfigData; called by default appendConfigData(Print&) with oappend_shim set up // private so it is not accidentally invoked except via Usermod::appendConfigData(Print&) - virtual void appendConfigData() {} + virtual void appendConfigData() {} protected: // Shim for oappend(), which used to exist in utils.cpp template static inline void oappend(const T& t) { oappend_shim->print(t); }; diff --git a/wled00/set.cpp b/wled00/set.cpp index d3a10707c2..54b7631da0 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -21,7 +21,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) { unsigned cnt = 0; for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) { - char et[4] = "ET"; et[2] = 48+n; et[3] = 0; // WiFi encryption type + char et[4] = "ET"; et[2] = 48+n; et[3] = 0; //WiFi encryption type char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID char ea[4] = "EA"; ea[2] = 48+n; ea[3] = 0; //enterprise anonymous identity char ei[4] = "EI"; ei[2] = 48+n; ei[3] = 0; //enterprise identity @@ -326,7 +326,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), buttons[i].pin, i); PinManager::deallocatePin(buttons[i].pin, PinOwner::Button); buttons[i].type = BTN_TYPE_NONE; - } + } #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so else touchAttachInterrupt(buttons[i].pin, touchButtonISR, touchThreshold << 4); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000) #endif @@ -979,7 +979,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("NP")); //advances to next preset in a playlist if (pos > 0) doAdvancePlaylist = true; - + //set brightness updateVal(req.c_str(), "&A=", bri); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 41fd502205..45a2af5345 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -173,7 +173,7 @@ void WLED::loop() if (millis() - heapTime > 15000) { uint32_t heap = getFreeHeapSize(); if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) { - DEBUG_PRINTF_P(PSTR("Heap too low! %u\n"), heap); + DEBUG_PRINTF_P(PSTR("Heap too low! %u\n"), heap); strip.resetSegments(); // remove all but one segments from memory if (!Update.isRunning()) forceReconnect = true; } else if (heap < MIN_HEAP_SIZE) { @@ -690,7 +690,7 @@ void WLED::initConnection() char hostname[25]; prepareHostname(hostname); if (multiWiFi[selectedWiFi].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { - DEBUG_PRINTF_P(PSTR("Using PSK\n")); + DEBUG_PRINTLN(F("Using PSK")); #ifndef WLED_DISABLE_WPA_ENTERPRISE #ifdef ESP8266 wifi_station_set_wpa2_enterprise_auth(0); @@ -702,7 +702,7 @@ void WLED::initConnection() #endif #endif WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times - } else { + } else { // WIFI_ENCRYPTION_TYPE_ENTERPRISE #ifndef WLED_DISABLE_WPA_ENTERPRISE DEBUG_PRINTF_P(PSTR("Using WPA2_AUTH_PEAP (Anon: %s, Ident: %s)\n"), multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity); #ifdef ESP8266 @@ -719,6 +719,9 @@ void WLED::initConnection() #else WiFi.begin(multiWiFi[selectedWiFi].clientSSID, WPA2_AUTH_PEAP, multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity, multiWiFi[selectedWiFi].clientPass); #endif +#else + DEBUG_PRINTLN(F("WPA2_AUTH_PEAP is disabled by WLED_DISABLE_WPA_ENTERPRISE, connecting using PSK.")); + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); #endif } From 8fb2d02b30ec47d3a47d6fda42da967b21e5a671 Mon Sep 17 00:00:00 2001 From: Benjamin Kraus Date: Sun, 14 Dec 2025 21:41:18 -0500 Subject: [PATCH 3/6] Fixed issue with strncmp identified by CodeRabbit. --- wled00/set.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/set.cpp b/wled00/set.cpp index 54b7631da0..6737b507ba 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -41,7 +41,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) multiWiFi[n].encryptionType = request->arg(et).toInt(); forceReconnect |= oldType != multiWiFi[n].encryptionType; strlcpy(multiWiFi[n].clientSSID, request->arg(cs).c_str(), 33); - if (strlen(oldSSID) == 0 || !strncmp(multiWiFi[n].clientSSID, oldSSID, 32)) { + if (strlen(oldSSID) == 0 || strncmp(multiWiFi[n].clientSSID, oldSSID, 32) != 0) { forceReconnect = true; } if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { @@ -53,10 +53,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strlcpy(multiWiFi[n].enterpriseAnonIdentity, request->arg(ea).c_str(), 65); strlcpy(multiWiFi[n].enterpriseIdentity, request->arg(ei).c_str(), 65); } - if (!strncmp(multiWiFi[n].enterpriseAnonIdentity, oldAnon, 64)) { + if (strncmp(multiWiFi[n].enterpriseAnonIdentity, oldAnon, 64) != 0) { forceReconnect = true; } - if (!strncmp(multiWiFi[n].enterpriseIdentity, oldIden, 64)) { + if (strncmp(multiWiFi[n].enterpriseIdentity, oldIden, 64) != 0) { forceReconnect = true; } if (!isAsterisksOnly(request->arg(pw).c_str(), 65)) { From 7ece8401c102d48f4f97193bf667b612d4236fcf Mon Sep 17 00:00:00 2001 From: Benjamin Kraus Date: Sun, 14 Dec 2025 21:50:02 -0500 Subject: [PATCH 4/6] Replaced split declaration-then-assignment with a single statement. --- wled00/set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/set.cpp b/wled00/set.cpp index 6737b507ba..456b42faf6 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -32,7 +32,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask if (request->hasArg(cs)) { if (n >= multiWiFi.size()) multiWiFi.emplace_back(); // expand vector by one - byte oldType; oldType = multiWiFi[n].encryptionType; + byte oldType = multiWiFi[n].encryptionType; char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID); char oldAnon[65]; strcpy(oldAnon, multiWiFi[n].enterpriseAnonIdentity); char oldIden[65]; strcpy(oldIden, multiWiFi[n].enterpriseIdentity); From b3b8065cf46c44390f774d52a0077ccd5c9d45e9 Mon Sep 17 00:00:00 2001 From: Benjamin Kraus Date: Sun, 21 Dec 2025 20:27:48 -0500 Subject: [PATCH 5/6] Revert whitespace only changes. --- platformio.ini | 4 ++-- wled00/data/settings_wifi.htm | 2 +- wled00/fcn_declare.h | 2 +- wled00/set.cpp | 5 ++--- wled00/wled.cpp | 4 ++-- wled00/xml.cpp | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/platformio.ini b/platformio.ini index f3fbcd5a24..98676c11e0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -529,7 +529,7 @@ build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_ -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html -D DATA_PINS=25 lib_deps = ${esp32_idf_V4.lib_deps} - + [env:esp32c3dev] extends = esp32c3 platform = ${esp32c3.platform} @@ -639,7 +639,7 @@ monitor_filters = esp32_exception_decoder [env:esp32s3_4M_qspi] ;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi) -board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM +board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 043e3e0bcd..4027dcf827 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -89,7 +89,7 @@ select.appendChild(option); if (input.value === "" || input.value === "Your_Network" || found) input.replaceWith(select); - else select.remove(); + else select.remove(); } } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ed27a536c1..7e7a7016bb 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -334,7 +334,7 @@ class Usermod { static Print* oappend_shim; // old form of appendConfigData; called by default appendConfigData(Print&) with oappend_shim set up // private so it is not accidentally invoked except via Usermod::appendConfigData(Print&) - virtual void appendConfigData() {} + virtual void appendConfigData() {} protected: // Shim for oappend(), which used to exist in utils.cpp template static inline void oappend(const T& t) { oappend_shim->print(t); }; diff --git a/wled00/set.cpp b/wled00/set.cpp index 456b42faf6..fb2e8f205c 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -326,7 +326,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), buttons[i].pin, i); PinManager::deallocatePin(buttons[i].pin, PinOwner::Button); buttons[i].type = BTN_TYPE_NONE; - } + } #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so else touchAttachInterrupt(buttons[i].pin, touchButtonISR, touchThreshold << 4); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000) #endif @@ -978,8 +978,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("NP")); //advances to next preset in a playlist if (pos > 0) doAdvancePlaylist = true; - - + //set brightness updateVal(req.c_str(), "&A=", bri); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 45a2af5345..c39d43877a 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -173,7 +173,7 @@ void WLED::loop() if (millis() - heapTime > 15000) { uint32_t heap = getFreeHeapSize(); if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) { - DEBUG_PRINTF_P(PSTR("Heap too low! %u\n"), heap); + DEBUG_PRINTF_P(PSTR("Heap too low! %u\n"), heap); strip.resetSegments(); // remove all but one segments from memory if (!Update.isRunning()) forceReconnect = true; } else if (heap < MIN_HEAP_SIZE) { @@ -683,7 +683,7 @@ void WLED::initConnection() if (WLED_WIFI_CONFIGURED) { showWelcomePage = false; - + DEBUG_PRINTF_P(PSTR("Connecting to %s...\n"), multiWiFi[selectedWiFi].clientSSID); // convert the "serverDescription" into a valid DNS hostname (alphanumeric) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 18ae313fda..064a04e236 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -416,7 +416,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifndef WLED_DISABLE_INFRARED printSetFormValue(settingsScript,PSTR("IR"),irPin); printSetFormValue(settingsScript,PSTR("IT"),irEnabled); -#endif +#endif printSetFormCheckbox(settingsScript,PSTR("MSO"),!irApplyToAllSelected); } From 5dd63a9244880dee21004b296c749be5b66ecb40 Mon Sep 17 00:00:00 2001 From: Benjamin Kraus Date: Sun, 21 Dec 2025 23:05:21 -0500 Subject: [PATCH 6/6] Move WPA enterprise behind a feature flag. --- wled00/cfg.cpp | 4 +++ wled00/const.h | 6 ++-- wled00/data/settings_wifi.htm | 14 +++++---- wled00/fcn_declare.h | 12 ++++++-- wled00/set.cpp | 56 +++++++++++++++++++++-------------- wled00/wled.cpp | 15 ++++------ wled00/wled.h | 2 +- wled00/xml.cpp | 16 ++++++++-- 8 files changed, 79 insertions(+), 46 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 4678ba820d..40ca751e76 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -114,6 +114,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { multiWiFi[n].staticIP = nIP; multiWiFi[n].staticGW = nGW; multiWiFi[n].staticSN = nSN; +#ifdef WLED_ENABLE_WPA_ENTERPRISE byte encType = WIFI_ENCRYPTION_TYPE_PSK; char anonIdent[65] = ""; char ident[65] = ""; @@ -123,6 +124,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { multiWiFi[n].encryptionType = encType; strlcpy(multiWiFi[n].enterpriseAnonIdentity, anonIdent, 65); strlcpy(multiWiFi[n].enterpriseIdentity, ident, 65); +#endif if (++n >= WLED_MAX_WIFI_COUNT) break; } } @@ -879,11 +881,13 @@ void serializeConfig(JsonObject root) { wifi_gw.add(multiWiFi[n].staticGW[i]); wifi_sn.add(multiWiFi[n].staticSN[i]); } +#ifdef WLED_ENABLE_WPA_ENTERPRISE wifi[F("enc_type")] = multiWiFi[n].encryptionType; if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_ENTERPRISE) { wifi[F("e_anon_ident")] = multiWiFi[n].enterpriseAnonIdentity; wifi[F("e_ident")] = multiWiFi[n].enterpriseIdentity; } +#endif } JsonArray dns = nw.createNestedArray(F("dns")); diff --git a/wled00/const.h b/wled00/const.h index c00cc58ca8..bfd8357ba9 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -209,8 +209,10 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define USERMOD_ID_USER_FX 58 //Usermod "user_fx" //Wifi encryption type -#define WIFI_ENCRYPTION_TYPE_PSK 0 //None/WPA/WPA2 -#define WIFI_ENCRYPTION_TYPE_ENTERPRISE 1 //WPA/WPA2-Enterprise +#ifdef WLED_ENABLE_WPA_ENTERPRISE + #define WIFI_ENCRYPTION_TYPE_PSK 0 //None/WPA/WPA2 + #define WIFI_ENCRYPTION_TYPE_ENTERPRISE 1 //WPA/WPA2-Enterprise +#endif //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 4027dcf827..47220c75d5 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -118,12 +118,12 @@ gId("wifi_add").style.display = (i1) ? "inline":"none"; } - function addWiFi(type=0,ssid="",anon="",ident="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff) { // little endian + function addWiFi(ssid="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff,type=-1,anon="",ident="") { // little endian var i = gId("wifi_entries").childNodes.length; if (i >= maxNetworks) return; - var b = `

-Network name (SSID${i==0?", empty to not connect":""}):
0?"required":""}>
-WiFi encryption type:
+ var encryptionTypeField = ""; + if (type >=0 && type < 2) { + encryptionTypeField = `WiFi encryption type:

Identity:

-
+
`; + } + var b = `

+Network name (SSID${i==0?", empty to not connect":""}):
0?"required":""}>
+${encryptionTypeField} Network password:

BSSID (optional):

Static IP (leave at 0.0.0.0 for DHCP)${i==0?"
Also used by Ethernet":""}:
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 7e7a7016bb..b511660770 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -58,25 +58,31 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau typedef struct WiFiConfig { char clientSSID[33]; - byte encryptionType; char clientPass[65]; uint8_t bssid[6]; IPAddress staticIP; IPAddress staticGW; IPAddress staticSN; +#ifdef WLED_ENABLE_WPA_ENTERPRISE + byte encryptionType; char enterpriseAnonIdentity[65]; char enterpriseIdentity[65]; WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF // little endian , byte enc_type=WIFI_ENCRYPTION_TYPE_PSK, const char *ent_anon="", const char *ent_iden="") - : encryptionType(enc_type) - , staticIP(ip) +#else + WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF) // little endian +#endif + : staticIP(ip) , staticGW(gw) , staticSN(subnet) { strncpy(clientSSID, ssid, 32); clientSSID[32] = 0; strncpy(clientPass, pass, 64); clientPass[64] = 0; +#ifdef WLED_ENABLE_WPA_ENTERPRISE + encryptionType = enc_type; strncpy(enterpriseAnonIdentity, ent_anon, 64); enterpriseAnonIdentity[64] = 0; strncpy(enterpriseIdentity, ent_iden, 64); enterpriseIdentity[64] = 0; +#endif memset(bssid, 0, sizeof(bssid)); } } wifi_config; diff --git a/wled00/set.cpp b/wled00/set.cpp index fb2e8f205c..71a04cf979 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -21,44 +21,26 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) { unsigned cnt = 0; for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) { - char et[4] = "ET"; et[2] = 48+n; et[3] = 0; //WiFi encryption type char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID - char ea[4] = "EA"; ea[2] = 48+n; ea[3] = 0; //enterprise anonymous identity - char ei[4] = "EI"; ei[2] = 48+n; ei[3] = 0; //enterprise identity char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password char bs[4] = "BS"; bs[2] = 48+n; bs[3] = 0; //BSSID char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask +#ifdef WLED_ENABLE_WPA_ENTERPRISE + char et[4] = "ET"; et[2] = 48+n; et[3] = 0; //WiFi encryption type + char ea[4] = "EA"; ea[2] = 48+n; ea[3] = 0; //enterprise anonymous identity + char ei[4] = "EI"; ei[2] = 48+n; ei[3] = 0; //enterprise identity +#endif if (request->hasArg(cs)) { if (n >= multiWiFi.size()) multiWiFi.emplace_back(); // expand vector by one - byte oldType = multiWiFi[n].encryptionType; char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID); - char oldAnon[65]; strcpy(oldAnon, multiWiFi[n].enterpriseAnonIdentity); - char oldIden[65]; strcpy(oldIden, multiWiFi[n].enterpriseIdentity); char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass); - multiWiFi[n].encryptionType = request->arg(et).toInt(); - forceReconnect |= oldType != multiWiFi[n].encryptionType; strlcpy(multiWiFi[n].clientSSID, request->arg(cs).c_str(), 33); if (strlen(oldSSID) == 0 || strncmp(multiWiFi[n].clientSSID, oldSSID, 32) != 0) { forceReconnect = true; } - if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { - // PSK - Clear the anonymous identity and identity fields - multiWiFi[n].enterpriseAnonIdentity[0] = '\0'; - multiWiFi[n].enterpriseIdentity[0] = '\0'; - } else { - // WPA2-Enterprise - strlcpy(multiWiFi[n].enterpriseAnonIdentity, request->arg(ea).c_str(), 65); - strlcpy(multiWiFi[n].enterpriseIdentity, request->arg(ei).c_str(), 65); - } - if (strncmp(multiWiFi[n].enterpriseAnonIdentity, oldAnon, 64) != 0) { - forceReconnect = true; - } - if (strncmp(multiWiFi[n].enterpriseIdentity, oldIden, 64) != 0) { - forceReconnect = true; - } if (!isAsterisksOnly(request->arg(pw).c_str(), 65)) { strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65); forceReconnect = true; @@ -72,6 +54,34 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) multiWiFi[n].staticGW[i] = request->arg(gw).toInt(); multiWiFi[n].staticSN[i] = request->arg(sn).toInt(); } + +#ifdef WLED_ENABLE_WPA_ENTERPRISE + byte oldType = multiWiFi[n].encryptionType; + char oldAnon[65]; strcpy(oldAnon, multiWiFi[n].enterpriseAnonIdentity); + char oldIden[65]; strcpy(oldIden, multiWiFi[n].enterpriseIdentity); + if (request->hasArg(et) && request->hasArg(ea) && request->hasArg(ei)) { + multiWiFi[n].encryptionType = request->arg(et).toInt(); + strlcpy(multiWiFi[n].enterpriseAnonIdentity, request->arg(ea).c_str(), 65); + strlcpy(multiWiFi[n].enterpriseIdentity, request->arg(ei).c_str(), 65); + } else { + // No enterprise settings provided, default to PSK + multiWiFi[n].encryptionType = WIFI_ENCRYPTION_TYPE_PSK; + } + + if (multiWiFi[n].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { + // PSK - Clear the anonymous identity and identity fields + multiWiFi[n].enterpriseAnonIdentity[0] = '\0'; + multiWiFi[n].enterpriseIdentity[0] = '\0'; + } + forceReconnect |= oldType != multiWiFi[n].encryptionType; + if (strncmp(multiWiFi[n].enterpriseAnonIdentity, oldAnon, 64) != 0) { + forceReconnect = true; + } + if (strncmp(multiWiFi[n].enterpriseIdentity, oldIden, 64) != 0) { + forceReconnect = true; + } +#endif + cnt++; } } diff --git a/wled00/wled.cpp b/wled00/wled.cpp index c39d43877a..ab9d1788e5 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -689,9 +689,10 @@ void WLED::initConnection() // convert the "serverDescription" into a valid DNS hostname (alphanumeric) char hostname[25]; prepareHostname(hostname); + +#ifdef WLED_ENABLE_WPA_ENTERPRISE if (multiWiFi[selectedWiFi].encryptionType == WIFI_ENCRYPTION_TYPE_PSK) { DEBUG_PRINTLN(F("Using PSK")); -#ifndef WLED_DISABLE_WPA_ENTERPRISE #ifdef ESP8266 wifi_station_set_wpa2_enterprise_auth(0); wifi_station_clear_enterprise_ca_cert(); @@ -700,10 +701,8 @@ void WLED::initConnection() wifi_station_clear_enterprise_username(); wifi_station_clear_enterprise_password(); #endif -#endif - WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); } else { // WIFI_ENCRYPTION_TYPE_ENTERPRISE -#ifndef WLED_DISABLE_WPA_ENTERPRISE DEBUG_PRINTF_P(PSTR("Using WPA2_AUTH_PEAP (Anon: %s, Ident: %s)\n"), multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity); #ifdef ESP8266 struct station_config sta_conf; @@ -718,13 +717,11 @@ void WLED::initConnection() wifi_station_connect(); #else WiFi.begin(multiWiFi[selectedWiFi].clientSSID, WPA2_AUTH_PEAP, multiWiFi[selectedWiFi].enterpriseAnonIdentity, multiWiFi[selectedWiFi].enterpriseIdentity, multiWiFi[selectedWiFi].clientPass); -#endif -#else - DEBUG_PRINTLN(F("WPA2_AUTH_PEAP is disabled by WLED_DISABLE_WPA_ENTERPRISE, connecting using PSK.")); - WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); #endif } - +#else // WLED_ENABLE_WPA_ENTERPRISE + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times +#endif // WLED_ENABLE_WPA_ENTERPRISE #ifdef ARDUINO_ARCH_ESP32 WiFi.setTxPower(wifi_power_t(txPower)); diff --git a/wled00/wled.h b/wled00/wled.h index b81d5d7810..5d06241745 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -77,7 +77,7 @@ #include #ifdef ESP8266 #include - #ifndef WLED_DISABLE_WPA_ENTERPRISE + #ifdef WLED_ENABLE_WPA_ENTERPRISE #include "wpa2_enterprise.h" #endif #include diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 064a04e236..5e976f07ce 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -198,16 +198,26 @@ void getSettingsJS(byte subPage, Print& settingsScript) memset(fpass,'*',l); char bssid[13]; fillMAC2Str(bssid, multiWiFi[n].bssid); - settingsScript.printf_P(PSTR("addWiFi(\"%u\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X);"), - multiWiFi[n].encryptionType, +#ifdef WLED_ENABLE_WPA_ENTERPRISE + settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X,\"%u\",\"%s\",\"%s\");"), multiWiFi[n].clientSSID, + fpass, + bssid, + (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct + (uint32_t) multiWiFi[n].staticGW, + (uint32_t) multiWiFi[n].staticSN, + multiWiFi[n].encryptionType, multiWiFi[n].enterpriseAnonIdentity, - multiWiFi[n].enterpriseIdentity, + multiWiFi[n].enterpriseIdentity); +#else + settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",\"%s\",0x%X,0x%X,0x%X);"), + multiWiFi[n].clientSSID, fpass, bssid, (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct (uint32_t) multiWiFi[n].staticGW, (uint32_t) multiWiFi[n].staticSN); +#endif } printSetFormValue(settingsScript,PSTR("D0"),dnsAddress[0]);