+ DNS server address:
+ ...
+
mDNS address (leave empty for no mDNS):
http:// .local
Client IP: Not connected
@@ -186,10 +212,12 @@
Access Point WiFi channel:
AP opens:
+
+
+
+
+
+
AP IP: Not active
Experimental
Force 802.11g mode (ESP8266 only):
@@ -215,6 +243,7 @@
+
diff --git a/wled00/data/style.css b/wled00/data/style.css
index 52b26a825..b6cb0f9e6 100644
--- a/wled00/data/style.css
+++ b/wled00/data/style.css
@@ -81,6 +81,7 @@ input:disabled {
}
input[type="text"],
input[type="number"],
+input[type="password"],
select {
font-size: medium;
margin: 2px;
diff --git a/wled00/e131.cpp b/wled00/e131.cpp
index 68c7ca5a5..c9fe350be 100644
--- a/wled00/e131.cpp
+++ b/wled00/e131.cpp
@@ -490,7 +490,7 @@ void prepareArtnetPollReply(ArtPollReply *reply) {
// Node is DHCP capable
// Node supports 15 bit Port-Address (Art-Net 3 or 4)
// Node is able to switch between ArtNet and sACN
- reply->reply_status_2 = (staticIP[0] == 0) ? 0x1F : 0x1D;
+ reply->reply_status_2 = (multiWiFi[0].staticIP[0] == 0) ? 0x1F : 0x1D;
// RDM is disabled
// Output style is continuous
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h
index e256ceb5f..bb24725d9 100644
--- a/wled00/fcn_declare.h
+++ b/wled00/fcn_declare.h
@@ -48,6 +48,21 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
return true;
}
+typedef struct WiFiConfig {
+ char clientSSID[33];
+ char clientPass[65];
+ 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
+ : staticIP(ip)
+ , staticGW(gw)
+ , staticSN(subnet)
+ {
+ strncpy(clientSSID, ssid, 32); clientSSID[32] = 0;
+ strncpy(clientPass, pass, 64); clientPass[64] = 0;
+ }
+} wifi_config;
//colors.cpp
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
diff --git a/wled00/file.cpp b/wled00/file.cpp
index 4edbdd6fb..fc3dc7eeb 100644
--- a/wled00/file.cpp
+++ b/wled00/file.cpp
@@ -377,27 +377,27 @@ void updateFSInfo() {
//Un-comment any file types you need
static String getContentType(AsyncWebServerRequest* request, String filename){
- if(request->hasArg("download")) return "application/octet-stream";
- else if(filename.endsWith(".htm")) return "text/html";
- else if(filename.endsWith(".html")) return "text/html";
- else if(filename.endsWith(".css")) return "text/css";
- else if(filename.endsWith(".js")) return "application/javascript";
- else if(filename.endsWith(".json")) return "application/json";
- else if(filename.endsWith(".png")) return "image/png";
- else if(filename.endsWith(".gif")) return "image/gif";
- else if(filename.endsWith(".jpg")) return "image/jpeg";
- else if(filename.endsWith(".ico")) return "image/x-icon";
-// else if(filename.endsWith(".xml")) return "text/xml";
-// else if(filename.endsWith(".pdf")) return "application/x-pdf";
-// else if(filename.endsWith(".zip")) return "application/x-zip";
-// else if(filename.endsWith(".gz")) return "application/x-gzip";
+ if(request->hasArg(F("download"))) return SET_F("application/octet-stream");
+ else if(filename.endsWith(F(".htm"))) return SET_F("text/html");
+ else if(filename.endsWith(F(".html"))) return SET_F("text/html");
+ else if(filename.endsWith(F(".css"))) return SET_F("text/css");
+ else if(filename.endsWith(F(".js"))) return SET_F("application/javascript");
+ else if(filename.endsWith(F(".json"))) return SET_F("application/json");
+ else if(filename.endsWith(F(".png"))) return SET_F("image/png");
+ else if(filename.endsWith(F(".gif"))) return SET_F("image/gif");
+ else if(filename.endsWith(F(".jpg"))) return SET_F("image/jpeg");
+ else if(filename.endsWith(F(".ico"))) return SET_F("image/x-icon");
+// else if(filename.endsWith(F(".xml"))) return SET_F("text/xml");
+// else if(filename.endsWith(F(".pdf"))) return SET_F("application/x-pdf");
+// else if(filename.endsWith(F(".zip"))) return SET_F("application/x-zip");
+// else if(filename.endsWith(F(".gz"))) return SET_F("application/x-gzip");
return "text/plain";
}
bool handleFileRead(AsyncWebServerRequest* request, String path){
DEBUG_PRINTLN("WS FileRead: " + path);
if(path.endsWith("/")) path += "index.htm";
- if(path.indexOf("sec") > -1) return false;
+ if(path.indexOf(F("sec")) > -1) return false;
String contentType = getContentType(request, path);
/*String pathWithGz = path + ".gz";
if(WLED_FS.exists(pathWithGz)){
diff --git a/wled00/improv.cpp b/wled00/improv.cpp
index 695d07ff7..f7867117f 100644
--- a/wled00/improv.cpp
+++ b/wled00/improv.cpp
@@ -259,14 +259,14 @@ void parseWiFiCommand(char* rpcData) {
uint8_t ssidLen = rpcData[1];
if (ssidLen > len -1 || ssidLen > 32) return;
- memset(clientSSID, 0, 32);
- memcpy(clientSSID, rpcData+2, ssidLen);
+ memset(multiWiFi[0].clientSSID, 0, 32);
+ memcpy(multiWiFi[0].clientSSID, rpcData+2, ssidLen);
- memset(clientPass, 0, 64);
+ memset(multiWiFi[0].clientPass, 0, 64);
if (len > ssidLen +1) {
uint8_t passLen = rpcData[2+ssidLen];
- memset(clientPass, 0, 64);
- memcpy(clientPass, rpcData+3+ssidLen, passLen);
+ memset(multiWiFi[0].clientPass, 0, 64);
+ memcpy(multiWiFi[0].clientPass, rpcData+3+ssidLen, passLen);
}
sendImprovStateResponse(0x03); //provisioning
diff --git a/wled00/json.cpp b/wled00/json.cpp
index 395ee7cbc..2213dd5b1 100644
--- a/wled00/json.cpp
+++ b/wled00/json.cpp
@@ -470,6 +470,19 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
}
+ JsonObject wifi = root[F("wifi")];
+ if (!wifi.isNull()) {
+ bool apMode = getBoolVal(wifi[F("ap")], apActive);
+ if (!apActive && apMode) WLED::instance().initAP(); // start AP mode immediately
+ else if (apActive && !apMode) { // stop AP mode immediately
+ dnsServer.stop();
+ WiFi.softAPdisconnect(true);
+ apActive = false;
+ }
+ //bool restart = wifi[F("restart")] | false;
+ //if (restart) forceReconnect = true;
+ }
+
stateUpdated(callMode);
if (presetToRestore) currentPreset = presetToRestore;
@@ -611,7 +624,7 @@ void serializeInfo(JsonObject root)
root[F("vid")] = VERSION;
root[F("cn")] = F(WLED_CODENAME);
- JsonObject leds = root.createNestedObject("leds");
+ JsonObject leds = root.createNestedObject(F("leds"));
leds[F("count")] = strip.getLengthTotal();
leds[F("pwr")] = BusManager::currentMilliamps();
leds["fps"] = strip.getFps();
@@ -622,7 +635,7 @@ void serializeInfo(JsonObject root)
#ifndef WLED_DISABLE_2D
if (strip.isMatrix) {
- JsonObject matrix = leds.createNestedObject("matrix");
+ JsonObject matrix = leds.createNestedObject(F("matrix"));
matrix["w"] = Segment::maxWidth;
matrix["h"] = Segment::maxHeight;
}
@@ -702,7 +715,7 @@ void serializeInfo(JsonObject root)
}
}
- JsonObject wifi_info = root.createNestedObject("wifi");
+ JsonObject wifi_info = root.createNestedObject(F("wifi"));
wifi_info[F("bssid")] = WiFi.BSSIDstr();
int qrssi = WiFi.RSSI();
wifi_info[F("rssi")] = qrssi;
diff --git a/wled00/network.cpp b/wled00/network.cpp
index 1b02d0c5d..2ae38f799 100644
--- a/wled00/network.cpp
+++ b/wled00/network.cpp
@@ -123,6 +123,16 @@ const ethernet_settings ethernetBoards[] = {
18, // eth_mdio,
ETH_PHY_LAN8720, // eth_type,
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
+ },
+
+ // ESP32-POE-WROVER
+ {
+ 0, // eth_address,
+ 12, // eth_power,
+ 23, // eth_mdc,
+ 18, // eth_mdio,
+ ETH_PHY_LAN8720, // eth_type,
+ ETH_CLOCK_GPIO0_OUT // eth_clk_mode
}
};
#endif
@@ -163,8 +173,8 @@ void WiFiEvent(WiFiEvent_t event)
if (!apActive) {
WiFi.disconnect(true);
}
- if (staticIP != (uint32_t)0x00000000 && staticGateway != (uint32_t)0x00000000) {
- ETH.config(staticIP, staticGateway, staticSubnet, IPAddress(8, 8, 8, 8));
+ if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) {
+ ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress);
} else {
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
}
diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp
index f065cd36a..19b26c224 100644
--- a/wled00/overlay.cpp
+++ b/wled00/overlay.cpp
@@ -89,6 +89,16 @@ void _overlayAnalogCountdown()
void handleOverlayDraw() {
usermods.handleOverlayDraw();
+ if (analogClockSolidBlack) {
+ const Segment* segments = strip.getSegments();
+ for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
+ const Segment& segment = segments[i];
+ if (!segment.isActive()) continue;
+ if (segment.mode > 0 || segment.colors[0] > 0) {
+ return;
+ }
+ }
+ }
if (overlayCurrent == 1) _overlayAnalogClock();
}
diff --git a/wled00/set.cpp b/wled00/set.cpp
index e83911783..49a54ab25 100755
--- a/wled00/set.cpp
+++ b/wled00/set.cpp
@@ -19,21 +19,52 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//WIFI SETTINGS
if (subPage == SUBPAGE_WIFI)
{
- char oldSSID[sizeof(clientSSID)];
+ unsigned cnt = 0;
+ for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) {
+ char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID
+ char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password
+ 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
+ if (request->hasArg(cs)) {
+ if (n >= multiWiFi.size()) multiWiFi.push_back(WiFiConfig()); // expand vector by one
+ char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID);
+ char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass);
- strcpy(oldSSID, clientSSID);
- strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33);
- if (!strcmp(oldSSID, clientSSID)) forceReconnect = true;
+ strlcpy(multiWiFi[n].clientSSID, request->arg(cs).c_str(), 33);
+ if (strlen(oldSSID) == 0 || !strncmp(multiWiFi[n].clientSSID, oldSSID, 32)) {
+ forceReconnect = true;
+ }
+ if (!isAsterisksOnly(request->arg(pw).c_str(), 65)) {
+ strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65);
+ forceReconnect = true;
+ }
+ for (size_t i = 0; i < 4; i++) {
+ ip[3] = 48+i;
+ gw[3] = 48+i;
+ sn[3] = 48+i;
+ multiWiFi[n].staticIP[i] = request->arg(ip).toInt();
+ multiWiFi[n].staticGW[i] = request->arg(gw).toInt();
+ multiWiFi[n].staticSN[i] = request->arg(sn).toInt();
+ }
+ cnt++;
+ }
+ }
+ // remove unused
+ if (cnt < multiWiFi.size()) {
+ cnt = multiWiFi.size() - cnt;
+ while (cnt--) multiWiFi.pop_back();
+ multiWiFi.shrink_to_fit(); // release memory
+ }
- if (!isAsterisksOnly(request->arg(F("CP")).c_str(), 65)) {
- strlcpy(clientPass, request->arg(F("CP")).c_str(), 65);
- forceReconnect = true;
+ if (request->hasArg(F("D0"))) {
+ dnsAddress = IPAddress(request->arg(F("D0")).toInt(),request->arg(F("D1")).toInt(),request->arg(F("D2")).toInt(),request->arg(F("D3")).toInt());
}
strlcpy(cmDNS, request->arg(F("CM")).c_str(), 33);
apBehavior = request->arg(F("AB")).toInt();
- strcpy(oldSSID, apSSID);
+ char oldSSID[33]; strcpy(oldSSID, apSSID);
strlcpy(apSSID, request->arg(F("AS")).c_str(), 33);
if (!strcmp(oldSSID, apSSID) && apActive) forceReconnect = true;
apHide = request->hasArg(F("AH"));
@@ -61,21 +92,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
ethernetType = request->arg(F("ETH")).toInt();
WLED::instance().initEthernet();
#endif
-
- char k[3]; k[2] = 0;
- for (int i = 0; i<4; i++)
- {
- k[1] = i+48;//ascii 0,1,2,3
-
- k[0] = 'I'; //static IP
- staticIP[i] = request->arg(k).toInt();
-
- k[0] = 'G'; //gateway
- staticGateway[i] = request->arg(k).toInt();
-
- k[0] = 'S'; //subnet
- staticSubnet[i] = request->arg(k).toInt();
- }
}
//LED SETTINGS
@@ -440,6 +456,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
analogClock12pixel = request->arg(F("OM")).toInt();
analogClock5MinuteMarks = request->hasArg(F("O5"));
analogClockSecondsTrail = request->hasArg(F("OS"));
+ analogClockSolidBlack = request->hasArg(F("OB"));
countdownMode = request->hasArg(F("CE"));
countdownYear = request->arg(F("CY")).toInt();
diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp
index 6268aa983..4a03d4847 100644
--- a/wled00/usermods_list.cpp
+++ b/wled00/usermods_list.cpp
@@ -170,7 +170,7 @@
#endif
#ifdef USERMOD_KLIPPER_PERCENTAGE
- #include "..\usermods\usermod_v2_klipper_percentage\usermod_v2_klipper_percentage.h"
+ #include "../usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h"
#endif
#ifdef USERMOD_BOBLIGHT
diff --git a/wled00/wled.cpp b/wled00/wled.cpp
index 967192efe..cc42e9dd5 100644
--- a/wled00/wled.cpp
+++ b/wled00/wled.cpp
@@ -34,6 +34,8 @@ void WLED::reset()
void WLED::loop()
{
+ static uint32_t lastHeap = UINT32_MAX;
+ static unsigned long heapTime = 0;
#ifdef WLED_DEBUG
static unsigned long lastRun = 0;
unsigned long loopMillis = millis();
@@ -151,6 +153,21 @@ void WLED::loop()
createEditHandler(false);
}
+ // reconnect WiFi to clear stale allocations if heap gets too low
+ if (millis() - heapTime > 15000) {
+ uint32_t heap = ESP.getFreeHeap();
+ if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) {
+ DEBUG_PRINT(F("Heap too low! ")); DEBUG_PRINTLN(heap);
+ forceReconnect = true;
+ strip.resetSegments(); // remove all but one segments from memory
+ } else if (heap < MIN_HEAP_SIZE) {
+ DEBUG_PRINTLN(F("Heap low, purging segments."));
+ strip.purgeSegments();
+ }
+ lastHeap = heap;
+ heapTime = millis();
+ }
+
//LED settings have been saved, re-init busses
//This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate!
if (doInitBusses) {
@@ -386,7 +403,7 @@ void WLED::setup()
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
-#ifdef WLED_DEBUG
+#if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST)
pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output
#endif
#ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin
@@ -424,6 +441,7 @@ void WLED::setup()
escapedMac.toLowerCase();
WLED_SET_AP_SSID(); // otherwise it is empty on first boot until config is saved
+ multiWiFi.push_back(WiFiConfig(CLIENT_SSID,CLIENT_PASS)); // initialise vector with default WiFi
DEBUG_PRINTLN(F("Reading config"));
deserializeConfigFromFS();
@@ -445,13 +463,16 @@ void WLED::setup()
usermods.setup();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
- if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0)
+ if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0)
showWelcomePage = true;
WiFi.persistent(false);
#ifdef WLED_USE_ETHERNET
WiFi.onEvent(WiFiEvent);
#endif
+ WiFi.mode(WIFI_STA); // enable scanning
+ findWiFi(true); // start scanning for available WiFi-s
+
#ifdef WLED_ENABLE_ADALIGHT
//Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused
//Serial TX (Debug, Improv, Serial JSON) only possible if GPIO1 unused
@@ -697,11 +718,52 @@ bool WLED::initEthernet()
#else
return false; // Ethernet not enabled for build
#endif
+}
+// performs asynchronous scan for available networks (which may take couple of seconds to finish)
+// returns configured WiFi ID with the strongest signal (or default if no configured networks available)
+int8_t WLED::findWiFi(bool doScan) {
+ if (multiWiFi.size() <= 1) {
+ DEBUG_PRINTLN(F("Defaulf WiFi used."));
+ return 0;
+ }
+
+ if (doScan) WiFi.scanDelete(); // restart scan
+
+ int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <3s with not very crowded air)
+
+ if (status == WIFI_SCAN_FAILED) {
+ DEBUG_PRINTLN(F("WiFi scan started."));
+ WiFi.scanNetworks(true); // start scanning in asynchronous mode
+ } else if (status >= 0) { // status contains number of found networks
+ DEBUG_PRINT(F("WiFi scan completed: ")); DEBUG_PRINTLN(status);
+ int rssi = -9999;
+ int selected = selectedWiFi;
+ for (int o = 0; o < status; o++) {
+ DEBUG_PRINT(F(" WiFi available: ")); DEBUG_PRINT(WiFi.SSID(o));
+ DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(WiFi.RSSI(o)); DEBUG_PRINTLN(F("dB"));
+ for (unsigned n = 0; n < multiWiFi.size(); n++)
+ if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) {
+ // find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big)
+ if ((n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) {
+ rssi = WiFi.RSSI(o);
+ selected = n;
+ }
+ break;
+ }
+ }
+ DEBUG_PRINT(F("Selected: ")); DEBUG_PRINT(multiWiFi[selected].clientSSID);
+ DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(rssi); DEBUG_PRINTLN(F("dB"));
+ return selected;
+ }
+ //DEBUG_PRINT(F("WiFi scan running."));
+ return status; // scan is still running or there was an error
}
void WLED::initConnection()
{
+ DEBUG_PRINTLN(F("initConnection() called."));
+
#ifdef WLED_ENABLE_WEBSOCKETS
ws.onEvent(wsEvent);
#endif
@@ -714,13 +776,13 @@ void WLED::initConnection()
}
#endif
- WiFi.disconnect(true); // close old connections
+ WiFi.disconnect(true); // close old connections
#ifdef ESP8266
WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N);
#endif
- if (staticIP[0] != 0 && staticGateway[0] != 0) {
- WiFi.config(staticIP, staticGateway, staticSubnet, IPAddress(1, 1, 1, 1));
+ if (multiWiFi[selectedWiFi].staticIP != 0U && multiWiFi[selectedWiFi].staticGW != 0U) {
+ WiFi.config(multiWiFi[selectedWiFi].staticIP, multiWiFi[selectedWiFi].staticGW, multiWiFi[selectedWiFi].staticSN, dnsAddress);
} else {
WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0));
}
@@ -745,13 +807,14 @@ void WLED::initConnection()
showWelcomePage = false;
DEBUG_PRINT(F("Connecting to "));
- DEBUG_PRINT(clientSSID);
+ DEBUG_PRINT(multiWiFi[selectedWiFi].clientSSID);
DEBUG_PRINTLN("...");
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
char hostname[25];
prepareHostname(hostname);
- WiFi.begin(clientSSID, clientPass);
+ WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times
+
#ifdef ARDUINO_ARCH_ESP32
#if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3))
WiFi.setTxPower(WIFI_POWER_8_5dBm);
@@ -843,35 +906,26 @@ void WLED::initInterfaces()
void WLED::handleConnection()
{
+ static bool scanDone = true;
static byte stacO = 0;
- static uint32_t lastHeap = UINT32_MAX;
- static unsigned long heapTime = 0;
unsigned long now = millis();
+ const bool wifiConfigured = WLED_WIFI_CONFIGURED;
- if (now < 2000 && (!WLED_WIFI_CONFIGURED || apBehavior == AP_BEHAVIOR_ALWAYS))
+ // ignore connection handling if WiFi is configured and scan still running
+ // or within first 2s if WiFi is not configured or AP is always active
+ if ((wifiConfigured && multiWiFi.size() > 1 && WiFi.scanComplete() < 0) || (now < 2000 && (!wifiConfigured || apBehavior == AP_BEHAVIOR_ALWAYS)))
return;
- if (lastReconnectAttempt == 0) {
- DEBUG_PRINTLN(F("lastReconnectAttempt == 0"));
+ if (lastReconnectAttempt == 0 || forceReconnect) {
+ DEBUG_PRINTLN(F("Initial connect or forced reconnect."));
+ selectedWiFi = findWiFi(); // find strongest WiFi
initConnection();
+ interfacesInited = false;
+ forceReconnect = false;
+ wasConnected = false;
return;
}
- // reconnect WiFi to clear stale allocations if heap gets too low
- if (now - heapTime > 5000) {
- uint32_t heap = ESP.getFreeHeap();
- if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) {
- DEBUG_PRINT(F("Heap too low! "));
- DEBUG_PRINTLN(heap);
- forceReconnect = true;
- strip.resetSegments();
- } else if (heap < MIN_HEAP_SIZE) {
- strip.purgeSegments();
- }
- lastHeap = heap;
- heapTime = now;
- }
-
byte stac = 0;
if (apActive) {
#ifdef ESP8266
@@ -885,7 +939,7 @@ void WLED::handleConnection()
stacO = stac;
DEBUG_PRINT(F("Connected AP clients: "));
DEBUG_PRINTLN(stac);
- if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) { // trying to connect, but not connected
+ if (!WLED_CONNECTED && wifiConfigured) { // trying to connect, but not connected
if (stac)
WiFi.disconnect(); // disable search so that AP can work
else
@@ -893,36 +947,49 @@ void WLED::handleConnection()
}
}
}
- if (forceReconnect) {
- DEBUG_PRINTLN(F("Forcing reconnect."));
- initConnection();
- interfacesInited = false;
- forceReconnect = false;
- wasConnected = false;
- return;
- }
+
if (!Network.isConnected()) {
if (interfacesInited) {
+ if (scanDone && multiWiFi.size() > 1) {
+ DEBUG_PRINTLN(F("WiFi scan initiated on disconnect."));
+ findWiFi(true); // reinit scan
+ scanDone = false;
+ return; // try to connect in next iteration
+ }
DEBUG_PRINTLN(F("Disconnected!"));
+ selectedWiFi = findWiFi();
initConnection();
interfacesInited = false;
+ scanDone = true;
}
//send improv failed 6 seconds after second init attempt (24 sec. after provisioning)
if (improvActive > 2 && now - lastReconnectAttempt > 6000) {
sendImprovStateResponse(0x03, true);
improvActive = 2;
}
- if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && WLED_WIFI_CONFIGURED) {
+ if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && wifiConfigured) {
if (improvActive == 2) improvActive = 3;
DEBUG_PRINTLN(F("Last reconnect too old."));
+ if (++selectedWiFi >= multiWiFi.size()) selectedWiFi = 0; // we couldn't connect, try with another network from the list
initConnection();
}
if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) {
- DEBUG_PRINTLN(F("Not connected AP."));
- initAP();
+ if (!(apBehavior == AP_BEHAVIOR_TEMPORARY && now > WLED_AP_TIMEOUT)) {
+ DEBUG_PRINTLN(F("Not connected AP."));
+ initAP(); // start AP only within first 5min
+ }
+ }
+ if (apActive && apBehavior == AP_BEHAVIOR_TEMPORARY && now > WLED_AP_TIMEOUT && stac == 0) { // disconnect AP after 5min if no clients connected
+ // if AP was enabled more than 10min after boot or if client was connected more than 10min after boot do not disconnect AP mode
+ if (now < 2*WLED_AP_TIMEOUT) {
+ dnsServer.stop();
+ WiFi.softAPdisconnect(true);
+ apActive = false;
+ DEBUG_PRINTLN(F("Temporary AP disabled."));
+ }
}
} else if (!interfacesInited) { //newly connected
- DEBUG_PRINTLN("");
+ DEBUG_PRINTLN();
DEBUG_PRINT(F("Connected! IP address: "));
DEBUG_PRINTLN(Network.localIP());
if (improvActive) {
@@ -940,7 +1007,7 @@ void WLED::handleConnection()
dnsServer.stop();
WiFi.softAPdisconnect(true);
apActive = false;
- DEBUG_PRINTLN(F("Access point disabled (handle)."));
+ DEBUG_PRINTLN(F("Access point disabled (connected)."));
}
}
}
diff --git a/wled00/wled.h b/wled00/wled.h
index 79488e8e8..f9027c4f9 100755
--- a/wled00/wled.h
+++ b/wled00/wled.h
@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
-#define VERSION 2401140
+#define VERSION 2401270
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG
@@ -304,22 +304,21 @@ WLED_GLOBAL int8_t irPin _INIT(IRPIN);
WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use
// WiFi CONFIG (all these can be changed via web UI, no need to set them here)
-WLED_GLOBAL char clientSSID[33] _INIT(CLIENT_SSID);
-WLED_GLOBAL char clientPass[65] _INIT(CLIENT_PASS);
-WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used)
-WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup)
-WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13)
-WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID
-WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default
-WLED_GLOBAL IPAddress staticIP _INIT_N((( 0, 0, 0, 0))); // static IP of ESP
-WLED_GLOBAL IPAddress staticGateway _INIT_N((( 0, 0, 0, 0))); // gateway (router) IP
-WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks
+WLED_GLOBAL uint8_t selectedWiFi _INIT(0);
+WLED_GLOBAL std::vector multiWiFi;
+WLED_GLOBAL IPAddress dnsAddress _INIT_N((( 8, 8, 8, 8))); // Google's DNS
+WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used)
+WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup)
+WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13)
+WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID
+WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default
#ifdef ARDUINO_ARCH_ESP32
-WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues
+WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues
#else
WLED_GLOBAL bool noWifiSleep _INIT(false);
#endif
WLED_GLOBAL bool force802_3g _INIT(false);
+#define WLED_WIFI_CONFIGURED (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) != 0)
#ifdef WLED_USE_ETHERNET
#ifdef WLED_ETH_DEFAULT // default ethernet board type if specified
@@ -494,6 +493,7 @@ WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1);
WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be
WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel
WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position
+WLED_GLOBAL bool analogClockSolidBlack _INIT(false); // Show clock overlay only if all LEDs are solid black (effect is 0 and color is black)
WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date
WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits
@@ -833,7 +833,6 @@ WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0);
#else
#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED)
#endif
-#define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0)
#ifndef WLED_AP_SSID_UNIQUE
#define WLED_SET_AP_SSID() do { \
@@ -883,6 +882,7 @@ public:
void initAP(bool resetAP = false);
void initConnection();
void initInterfaces();
+ int8_t findWiFi(bool doScan = false);
#if defined(STATUSLED)
void handleStatusLED();
#endif
diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp
index 9ea838797..89e5d65c4 100755
--- a/wled00/wled_eeprom.cpp
+++ b/wled00/wled_eeprom.cpp
@@ -74,11 +74,11 @@ void loadSettingsFromEEPROM()
int lastEEPROMversion = EEPROM.read(377); //last EEPROM version before update
- readStringFromEEPROM( 0, clientSSID, 32);
- readStringFromEEPROM( 32, clientPass, 64);
- readStringFromEEPROM( 96, cmDNS, 32);
- readStringFromEEPROM(128, apSSID, 32);
- readStringFromEEPROM(160, apPass, 64);
+ readStringFromEEPROM( 0, multiWiFi[0].clientSSID, 32);
+ readStringFromEEPROM( 32, multiWiFi[0].clientPass, 64);
+ readStringFromEEPROM( 96, cmDNS, 32);
+ readStringFromEEPROM(128, apSSID, 32);
+ readStringFromEEPROM(160, apPass, 64);
nightlightDelayMinsDefault = EEPROM.read(224);
nightlightDelayMins = nightlightDelayMinsDefault;
diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp
index 82cc55014..57e0c84b9 100644
--- a/wled00/wled_server.cpp
+++ b/wled00/wled_server.cpp
@@ -532,18 +532,18 @@ void serveSettings(AsyncWebServerRequest* request, bool post) {
const String& url = request->url();
if (url.indexOf("sett") >= 0) {
- if (url.indexOf(".js") > 0) subPage = SUBPAGE_JS;
- else if (url.indexOf(".css") > 0) subPage = SUBPAGE_CSS;
- else if (url.indexOf("wifi") > 0) subPage = SUBPAGE_WIFI;
- else if (url.indexOf("leds") > 0) subPage = SUBPAGE_LEDS;
- else if (url.indexOf("ui") > 0) subPage = SUBPAGE_UI;
- else if (url.indexOf("sync") > 0) subPage = SUBPAGE_SYNC;
- else if (url.indexOf("time") > 0) subPage = SUBPAGE_TIME;
- else if (url.indexOf("sec") > 0) subPage = SUBPAGE_SEC;
- else if (url.indexOf("dmx") > 0) subPage = SUBPAGE_DMX;
- else if (url.indexOf("um") > 0) subPage = SUBPAGE_UM;
- else if (url.indexOf("2D") > 0) subPage = SUBPAGE_2D;
- else if (url.indexOf("lock") > 0) subPage = SUBPAGE_LOCK;
+ if (url.indexOf(F(".js")) > 0) subPage = SUBPAGE_JS;
+ else if (url.indexOf(F(".css")) > 0) subPage = SUBPAGE_CSS;
+ else if (url.indexOf(F("wifi")) > 0) subPage = SUBPAGE_WIFI;
+ else if (url.indexOf(F("leds")) > 0) subPage = SUBPAGE_LEDS;
+ else if (url.indexOf(F("ui")) > 0) subPage = SUBPAGE_UI;
+ else if (url.indexOf( "sync") > 0) subPage = SUBPAGE_SYNC;
+ else if (url.indexOf( "time") > 0) subPage = SUBPAGE_TIME;
+ else if (url.indexOf(F("sec")) > 0) subPage = SUBPAGE_SEC;
+ else if (url.indexOf( "dmx") > 0) subPage = SUBPAGE_DMX;
+ else if (url.indexOf( "um") > 0) subPage = SUBPAGE_UM;
+ else if (url.indexOf( "2D") > 0) subPage = SUBPAGE_2D;
+ else if (url.indexOf(F("lock")) > 0) subPage = SUBPAGE_LOCK;
}
else if (url.indexOf("/update") >= 0) subPage = SUBPAGE_UPDATE; // update page, for PIN check
//else if (url.indexOf("/edit") >= 0) subPage = 10;
diff --git a/wled00/xml.cpp b/wled00/xml.cpp
index de183c5a6..3c7ebd2c3 100755
--- a/wled00/xml.cpp
+++ b/wled00/xml.cpp
@@ -157,8 +157,8 @@ void appendGPIOinfo() {
oappend(SET_F(",2")); // DMX hardcoded pin
#endif
- #ifdef WLED_DEBUG
- oappend(SET_F(",")); oappend(itoa(hardwareTX,nS,10));// debug output (TX) pin
+ #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST)
+ oappend(SET_F(",")); oappend(itoa(hardwareTX,nS,10)); // debug output (TX) pin
#endif
//Note: Using pin 3 (RX) disables Adalight / Serial JSON
@@ -248,23 +248,34 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == SUBPAGE_WIFI)
{
- sappends('s',SET_F("CS"),clientSSID);
-
- byte l = strlen(clientPass);
- char fpass[l+1]; //fill password field with ***
- fpass[l] = 0;
- memset(fpass,'*',l);
- sappends('s',SET_F("CP"),fpass);
-
- char k[3]; k[2] = 0; //IP addresses
- for (int i = 0; i<4; i++)
- {
- k[1] = 48+i; //ascii 0,1,2,3
- k[0] = 'I'; sappend('v',k,staticIP[i]);
- k[0] = 'G'; sappend('v',k,staticGateway[i]);
- k[0] = 'S'; sappend('v',k,staticSubnet[i]);
+ char nS[10];
+ size_t l;
+ oappend(SET_F("resetWiFi("));
+ oappend(itoa(WLED_MAX_WIFI_COUNT,nS,10));
+ oappend(SET_F(");"));
+ for (size_t n = 0; n < multiWiFi.size(); n++) {
+ l = strlen(multiWiFi[n].clientPass);
+ char fpass[l+1]; //fill password field with ***
+ fpass[l] = 0;
+ memset(fpass,'*',l);
+ oappend(SET_F("addWiFi(\""));
+ oappend(multiWiFi[n].clientSSID);
+ oappend(SET_F("\",\""));
+ oappend(fpass);
+ oappend(SET_F("\",0x"));
+ oappend(itoa(multiWiFi[n].staticIP,nS,16));
+ oappend(SET_F(",0x"));
+ oappend(itoa(multiWiFi[n].staticGW,nS,16));
+ oappend(SET_F(",0x"));
+ oappend(itoa(multiWiFi[n].staticSN,nS,16));
+ oappend(SET_F(");"));
}
+ sappend('v',SET_F("D0"),dnsAddress[0]);
+ sappend('v',SET_F("D1"),dnsAddress[1]);
+ sappend('v',SET_F("D2"),dnsAddress[2]);
+ sappend('v',SET_F("D3"),dnsAddress[3]);
+
sappends('s',SET_F("CM"),cmDNS);
sappend('i',SET_F("AB"),apBehavior);
sappends('s',SET_F("AS"),apSSID);
@@ -597,6 +608,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("OM"),analogClock12pixel);
sappend('c',SET_F("OS"),analogClockSecondsTrail);
sappend('c',SET_F("O5"),analogClock5MinuteMarks);
+ sappend('c',SET_F("OB"),analogClockSolidBlack);
sappend('c',SET_F("CE"),countdownMode);
sappend('v',SET_F("CY"),countdownYear);