diff --git a/wled00/my_config_sample.h b/wled00/my_config_sample.h index 000793deb6..6dc2f3f044 100644 --- a/wled00/my_config_sample.h +++ b/wled00/my_config_sample.h @@ -22,5 +22,6 @@ #define CLIENT_PASS "Your_Password" */ +//#define WLED_FORCE_WIFI_OFF // Disable regular WiFi (STA/AP fallback). Requires a configured momentary button 0 for emergency AP long-press recovery. //#define MAX_LEDS 1500 // Maximum total LEDs. More than 1500 might create a low memory situation on ESP8266. //#define MDNS_NAME "wled" // mDNS hostname, ie: *.local diff --git a/wled00/network.cpp b/wled00/network.cpp index 105fdf6b27..4a4f469a39 100644 --- a/wled00/network.cpp +++ b/wled00/network.cpp @@ -2,6 +2,25 @@ #include "fcn_declare.h" #include "wled_ethernet.h" +namespace { + +bool restartWiFiScanIfEnabled(bool requireMultiWiFi) +{ +#ifdef WLED_FORCE_WIFI_OFF + (void)requireMultiWiFi; + return false; +#else + if (!interfacesInited) return false; + if (requireMultiWiFi && multiWiFi.size() <= 1) return false; + const int scanStatus = WiFi.scanComplete(); + if (scanStatus == WIFI_SCAN_RUNNING) return false; // do not restart while scan is active + findWiFi(true); // reinit WiFi scan + return true; +#endif +} + +} // namespace + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) // The following six pins are neither configurable nor @@ -385,8 +404,7 @@ void WiFiEvent(WiFiEvent_t event) case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: if (wasConnected && interfacesInited) { DEBUG_PRINTF_P(PSTR("WiFi-E: Disconnected! @ %lus\n"), millis()/1000); - if (interfacesInited && multiWiFi.size() > 1 && WiFi.scanComplete() >= 0) { - findWiFi(true); // reinit WiFi scan + if (restartWiFiScanIfEnabled(true)) { forceReconnect = true; } interfacesInited = false; @@ -427,7 +445,7 @@ void WiFiEvent(WiFiEvent_t event) // may be necessary to reconnect the WiFi when // ethernet disconnects, as a way to provide // alternative access to the device. - if (interfacesInited && WiFi.scanComplete() >= 0) findWiFi(true); // reinit WiFi scan + restartWiFiScanIfEnabled(false); forceReconnect = true; break; #endif diff --git a/wled00/wled.cpp b/wled00/wled.cpp index d67f784078..48bdbc8117 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -14,6 +14,58 @@ extern "C" void usePWMFixedNMI(); +namespace { + +bool regularWiFiEnabled() +{ +#ifdef WLED_FORCE_WIFI_OFF + return false; +#else + return true; +#endif +} + +void initRegularWiFiStartup() +{ + if (!regularWiFiEnabled()) { + DEBUG_PRINTLN(F("WLED_FORCE_WIFI_OFF: disabling regular WiFi startup (AP button emergency remains available).")); + apBehavior = AP_BEHAVIOR_BUTTON_ONLY; + WiFi.mode(WIFI_OFF); + return; + } + + WiFi.mode(WIFI_STA); // enable scanning + findWiFi(true); // start scanning for available WiFi-s +} + +bool handleForceWiFiOffConnection() +{ + if (regularWiFiEnabled()) return false; + + DEBUG_PRINTLN(F("WLED_FORCE_WIFI_OFF active. WiFi stays OFF unless AP emergency mode is opened by button.")); + apBehavior = AP_BEHAVIOR_BUTTON_ONLY; + lastReconnectAttempt = millis(); + if (!apActive) { + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); + } + return true; +} + +bool wifiScanRunning(bool wifiConfigured) +{ + if (!regularWiFiEnabled()) return false; + return wifiConfigured && multiWiFi.size() > 1 && WiFi.scanComplete() < 0; +} + +int findWiFiIfEnabled(bool doScan = false) +{ + if (!regularWiFiEnabled()) return selectedWiFi; + return findWiFi(doScan); +} + +} // namespace + /* * Main WLED class implementation. Mostly initialization and connection logic */ @@ -511,8 +563,7 @@ void WLED::setup() WiFi.persistent(false); // on ES8266 using NVM for wifi config has no benefit of faster connection #endif WiFi.onEvent(WiFiEvent); - WiFi.mode(WIFI_STA); // enable scanning - findWiFi(true); // start scanning for available WiFi-s + initRegularWiFiStartup(); // all GPIOs are allocated at this point serialCanRX = !PinManager::isPinAllocated(hardwareRX); // Serial RX pin (GPIO 3 on ESP32 and ESP8266) @@ -673,6 +724,8 @@ void WLED::initAP(bool resetAP) void WLED::initConnection() { DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000); + if (handleForceWiFiOffConnection()) return; + #ifdef WLED_ENABLE_WEBSOCKETS ws.onEvent(wsEvent); #endif @@ -867,12 +920,13 @@ void WLED::handleConnection() // 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))) + const bool wifiScanRunning = ::wifiScanRunning(wifiConfigured); + if (wifiScanRunning || (now < 2000 && (!wifiConfigured || apBehavior == AP_BEHAVIOR_ALWAYS))) return; if (lastReconnectAttempt == 0 || forceReconnect) { DEBUG_PRINTF_P(PSTR("Initial connect or forced reconnect (@ %lus).\n"), nowS); - selectedWiFi = findWiFi(); // find strongest WiFi + selectedWiFi = findWiFiIfEnabled(); // find strongest WiFi initConnection(); interfacesInited = false; forceReconnect = false; @@ -905,12 +959,12 @@ void WLED::handleConnection() if (interfacesInited) { if (scanDone && multiWiFi.size() > 1) { DEBUG_PRINTLN(F("WiFi scan initiated on disconnect.")); - findWiFi(true); // reinit scan + findWiFiIfEnabled(true); // reinit scan scanDone = false; return; // try to connect in next iteration } DEBUG_PRINTLN(F("Disconnected!")); - selectedWiFi = findWiFi(); + selectedWiFi = findWiFiIfEnabled(); initConnection(); interfacesInited = false; scanDone = true; diff --git a/wled00/wled.h b/wled00/wled.h index 21b340d94c..207848d267 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -29,6 +29,7 @@ #endif // You can choose some of these features to disable: +//#define WLED_FORCE_WIFI_OFF // disable regular WiFi (STA/AP fallback). Requires a configured momentary button 0 for emergency AP long-press recovery. //#define WLED_DISABLE_ALEXA // saves 11kb //#define WLED_DISABLE_HUESYNC // saves 4kb //#define WLED_DISABLE_INFRARED // saves 12kb, there is no pin left for this on ESP8266-01 @@ -291,6 +292,18 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS); #ifndef BTNTYPE #define BTNTYPE BTN_TYPE_PUSH #endif + +#ifdef WLED_FORCE_WIFI_OFF + #ifndef WLED_USE_ETHERNET + #error "WLED_FORCE_WIFI_OFF requires WLED_USE_ETHERNET." + #endif + #if (BTNPIN < 0) + #warning "WLED_FORCE_WIFI_OFF: BTNPIN is disabled. Emergency AP long-press on button 0 will not be available unless configured in cfg.json." + #endif + #if !((BTNTYPE == BTN_TYPE_PUSH) || (BTNTYPE == BTN_TYPE_PUSH_ACT_HIGH) || (BTNTYPE == BTN_TYPE_TOUCH)) + #warning "WLED_FORCE_WIFI_OFF: BTNTYPE is not momentary by default. Emergency AP long-press on button 0 requires a momentary button type." + #endif +#endif #ifndef RLYPIN WLED_GLOBAL int8_t rlyPin _INIT(-1); #else