Refactor WiFiManager: extract server and handlers into separate modules

- Move server lifecycle management to WiFiManagerServer
- Move HTTP handlers and rendering to WiFiManagerHandlers
- Move DEBUG_WM template definitions to WiFiManagerDebug
- Implement lazy initialization of server manager to save memory
- Add proper cleanup in destructor and on multiple createServer calls
- Update tests to use getServer() and getDNSServer() accessors
This commit is contained in:
2025-11-15 22:22:36 +10:00
parent 1788aa3c4a
commit 9cd5f62f9b
14 changed files with 1777 additions and 1753 deletions
+22 -89
View File
@@ -6,7 +6,7 @@
*
* @author Creator tzapu
* @author tablatronix
* @version 0.0.0
* @author Alex Hope-O'Connor
* @license MIT
*/
@@ -22,6 +22,8 @@
#include <vector>
#include "WiFiManagerParameter.h"
// #define WM_MDNS // includes MDNS, also set MDNS with sethostname
// #define WM_FIXERASECONFIG // use erase flash fix
// #define WM_ERASE_NVS // esp32 erase(true) will erase NVS
@@ -180,55 +182,8 @@
// #pragma message "VER_IDF_STR = " WM_STRING(VER_IDF_STR)
// #pragma message "VER_ARDUINO_STR = " WM_STRING(VER_ARDUINO_STR)
#ifndef WIFI_MANAGER_MAX_PARAMS
#define WIFI_MANAGER_MAX_PARAMS 5 // params will autoincrement and realloc by this amount when max is reached
#endif
#define WFM_LABEL_BEFORE 1
#define WFM_LABEL_AFTER 2
#define WFM_NO_LABEL 0
#define WFM_LABEL_DEFAULT 1
// WiFiManagerRequestArgs is defined as a nested class inside WiFiManager (after WM_WebServer is defined)
class WiFiManagerParameter {
public:
/**
Create custom parameters that can be added to the WiFiManager setup web page
@id is used for HTTP queries and must not contain spaces nor other special characters
*/
WiFiManagerParameter();
WiFiManagerParameter(const char *custom);
WiFiManagerParameter(const char *id, const char *label);
WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length);
WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom);
WiFiManagerParameter(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement);
~WiFiManagerParameter();
// WiFiManagerParameter& operator=(const WiFiManagerParameter& rhs);
const char *getID() const;
const char *getValue() const;
const char *getLabel() const;
const char *getPlaceholder() const; // @deprecated, use getLabel
int getValueLength() const;
int getLabelPlacement() const;
virtual const char *getCustomHTML() const;
void setValue(const char *defaultValue, int length);
protected:
void init(const char *id, const char *label, const char *defaultValue, int length, const char *custom, int labelPlacement);
WiFiManagerParameter& operator=(const WiFiManagerParameter&);
const char *_id;
const char *_label;
char *_value;
int _length;
int _labelPlacement;
const char *_customHTML;
friend class WiFiManager;
};
// debugging
typedef enum {
@@ -240,6 +195,10 @@ class WiFiManagerParameter {
WM_DEBUG_MAX = 5 // MAX extra dev auditing, var dumps etc (MAX+1 will print timing,mem and frag info)
} wm_debuglevel_t;
// Forward declarations
class WiFiManagerServer;
class WiFiManagerHandlers;
class WiFiManager
{
public:
@@ -496,10 +455,12 @@ class WiFiManager
// get hostname helper
String getWiFiHostname();
std::unique_ptr<DNSServer> dnsServer;
std::unique_ptr<AsyncWebServer> server;
// get server instance (for testing)
AsyncWebServer* getServer();
// get DNS server instance (for testing)
DNSServer* getDNSServer();
public:
// Define WiFiManagerRequestArgs here after AsyncWebServer is available
@@ -566,8 +527,12 @@ class WiFiManager
}
};
friend class WiFiManagerServer;
friend class WiFiManagerHandlers;
protected:
// vars
std::unique_ptr<WiFiManagerServer> _serverManager;
std::vector<uint8_t> _menuIds;
std::vector<const char *> _menuIdsParams = {"wifi","param","info","exit"};
std::vector<const char *> _menuIdsUpdate = {"wifi","param","info","update","exit"};
@@ -722,7 +687,6 @@ protected:
bool startAP();
void setupDNSD();
void setupHTTPServer();
uint8_t connectWifi(String ssid, String pass, bool connect = true);
bool setSTAConfig();
@@ -733,33 +697,9 @@ protected:
uint8_t waitForConnectResult(uint32_t timeout);
void updateConxResult(uint8_t status);
// webserver handlers
public:
void handleNotFound(AsyncWebServerRequest *request);
protected:
void handleRoot(AsyncWebServerRequest *request);
void handleWifi(AsyncWebServerRequest *request, boolean scan);
void handleWifiSave(AsyncWebServerRequest *request);
void handleInfo(AsyncWebServerRequest *request);
void handleReset(AsyncWebServerRequest *request);
void handleExit(AsyncWebServerRequest *request);
void handleClose(AsyncWebServerRequest *request);
void handleErase(AsyncWebServerRequest *request, boolean opt);
void handleParam(AsyncWebServerRequest *request);
void handleWiFiStatus(AsyncWebServerRequest *request);
void handleWiFiScanStatus(AsyncWebServerRequest *request);
void handleRequest(AsyncWebServerRequest *request);
void handleParamSave(AsyncWebServerRequest *request);
void doParamSave(WiFiManagerRequestArgs requestArgs);
boolean captivePortal(AsyncWebServerRequest *request);
// Config portal lifecycle (handlers moved to WiFiManagerHandlers)
boolean configPortalHasTimeout();
uint8_t processConfigPortal();
void stopCaptivePortal();
// OTA Update handler
void handleUpdate(AsyncWebServerRequest *request);
void handleUpdating(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
void handleUpdateDone(AsyncWebServerRequest *request);
// wifi platform abstractions
@@ -815,21 +755,11 @@ protected:
#endif
#endif
// output helpers
String getParamOut();
String getIpForm(String id, String title, String value);
String getScanItemOut();
String getStaticOut();
String getHTTPHead(String title, String classes = "");
String getHTTPEnd();
String getMenuOut();
//helpers
//helpers (rendering methods moved to WiFiManagerHandlers)
boolean isIp(String str);
String toStringIp(IPAddress ip);
boolean validApPassword();
String encryptionTypeStr(uint8_t authmode);
void reportStatus(String &page);
String getInfoData(String id);
// flags
boolean connect = false;
@@ -915,6 +845,9 @@ protected:
};
// Include template implementations for DEBUG_WM
#include "WiFiManagerDebug.h"
#endif
#endif
@@ -0,0 +1,74 @@
/**
* WiFiManagerDebug.h
*
* Debug output macros and templates for WiFiManager
*
* @author tablatronix
* @author Alex Hope-O'Connor
* @license MIT
*/
#ifndef WiFiManagerDebug_h
#define WiFiManagerDebug_h
#if defined(ESP8266) || defined(ESP32)
// Template implementations for DEBUG_WM - must be in header for template instantiation
// This file is included at the end of WiFiManager.h after the class definition
template <typename Generic>
void WiFiManager::DEBUG_WM(Generic text) {
DEBUG_WM(WM_DEBUG_NOTIFY,text,"");
}
template <typename Generic>
void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text) {
if(_debugLevel >= level) DEBUG_WM(level,text,"");
}
template <typename Generic, typename Genericb>
void WiFiManager::DEBUG_WM(Generic text,Genericb textb) {
DEBUG_WM(WM_DEBUG_NOTIFY,text,textb);
}
template <typename Generic, typename Genericb>
void WiFiManager::DEBUG_WM(wm_debuglevel_t level,Generic text,Genericb textb) {
if(!_debug || _debugLevel < level) return;
if(_debugLevel >= WM_DEBUG_MAX){
#ifdef ESP8266
// uint32_t free;
// uint16_t max;
// uint8_t frag;
// ESP.getHeapStats(&free, &max, &frag);// @todo Does not exist in 2.3.0
// _debugPort.printf("[MEM] free: %5d | max: %5d | frag: %3d%% \n", free, max, frag);
#elif defined ESP32
// total_free_bytes; ///< Total free bytes in the heap. Equivalent to multi_free_heap_size().
// total_allocated_bytes; ///< Total bytes allocated to data in the heap.
// largest_free_block; ///< Size of largest free block in the heap. This is the largest malloc-able size.
// minimum_free_bytes; ///< Lifetime minimum free heap size. Equivalent to multi_minimum_free_heap_size().
// allocated_blocks; ///< Number of (variable size) blocks allocated in the heap.
// free_blocks; ///< Number of (variable size) free blocks in the heap.
// total_blocks; ///< Total number of (variable size) blocks in the heap.
multi_heap_info_t info;
heap_caps_get_info(&info, MALLOC_CAP_INTERNAL);
uint32_t free = info.total_free_bytes;
uint16_t max = info.largest_free_block;
uint8_t frag = 100 - (max * 100) / free;
_debugPort.printf("[MEM] free: %5u | max: %5u | frag: %3u%% \n", free, max, frag);
#endif
}
_debugPort.print(_debugPrefix);
if(_debugLevel >= debugLvlShow) _debugPort.print("["+(String)level+"] ");
_debugPort.print(text);
if(textb){
_debugPort.print(" ");
_debugPort.print(textb);
}
_debugPort.println();
}
#endif // defined(ESP8266) || defined(ESP32)
#endif // WiFiManagerDebug_h
@@ -0,0 +1,69 @@
/**
* WiFiManagerHandlers.h
*
* HTTP request handlers and rendering logic for WiFiManager
* Handles all web portal page generation and request processing
*
* @author tablatronix
* @author Alex Hope-O'Connor
* @license MIT
*/
#ifndef WiFiManagerHandlers_h
#define WiFiManagerHandlers_h
#if defined(ESP8266) || defined(ESP32)
#include <ESPAsyncWebServer.h>
#include <memory>
#include "WiFiManager.h" // Need full definition for WiFiManagerRequestArgs
class WiFiManagerHandlers {
public:
WiFiManagerHandlers(WiFiManager* wm);
// HTTP Request Handlers
void handleRoot(AsyncWebServerRequest *request);
void handleWifi(AsyncWebServerRequest *request, boolean scan);
void handleWifiSave(AsyncWebServerRequest *request);
void handleParam(AsyncWebServerRequest *request);
void handleParamSave(AsyncWebServerRequest *request);
void handleInfo(AsyncWebServerRequest *request);
void handleReset(AsyncWebServerRequest *request);
void handleExit(AsyncWebServerRequest *request);
void handleClose(AsyncWebServerRequest *request);
void handleErase(AsyncWebServerRequest *request, boolean opt);
void handleNotFound(AsyncWebServerRequest *request);
void handleRequest(AsyncWebServerRequest *request);
void handleWiFiStatus(AsyncWebServerRequest *request);
void handleWiFiScanStatus(AsyncWebServerRequest *request);
void handleUpdate(AsyncWebServerRequest *request);
void handleUpdating(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
void handleUpdateDone(AsyncWebServerRequest *request);
// Captive Portal
boolean captivePortal(AsyncWebServerRequest *request);
void stopCaptivePortal();
// Rendering Methods
String getHTTPHead(String title, String classes = "");
String getHTTPEnd();
String getMenuOut();
String getScanItemOut();
String getParamOut();
String getStaticOut();
String getIpForm(String id, String title, String value);
String getInfoData(String id);
void reportStatus(String &page);
// Internal helper (needed by handlers)
void doParamSave(WiFiManager::WiFiManagerRequestArgs requestArgs);
private:
WiFiManager* _wm;
};
#endif // defined(ESP8266) || defined(ESP32)
#endif // WiFiManagerHandlers_h
@@ -0,0 +1,66 @@
/**
* WiFiManagerServer.h
*
* Server lifecycle management for WiFiManager
* Handles AsyncWebServer creation, route registration, and shutdown
*
* @author tablatronix
* @author Alex Hope-O'Connor
* @license MIT
*/
#ifndef WiFiManagerServer_h
#define WiFiManagerServer_h
#if defined(ESP8266) || defined(ESP32)
#include <ESPAsyncWebServer.h>
#include <DNSServer.h>
#include <functional>
#include <memory>
// Forward declarations
class WiFiManager;
// Forward declaration - full definition needed in .cpp file
class WiFiManagerHandlers;
class WiFiManagerServer {
public:
WiFiManagerServer(WiFiManager* wm);
// Create server instance
void createServer(uint16_t port);
// Register all routes (takes handler callbacks)
void registerRoutes();
// Setup DNS server for captive portal
void setupDNSD();
// Process DNS requests (call periodically)
void processDNS();
// Shutdown and cleanup server and DNS
void shutdownServer();
// Get server instance
AsyncWebServer* getServer() { return server.get(); }
// Get DNS server instance (for testing)
DNSServer* getDNSServer() { return dnsServer.get(); }
private:
WiFiManager* _wm;
std::unique_ptr<WiFiManagerHandlers> _handlers;
std::unique_ptr<AsyncWebServer> server;
std::unique_ptr<DNSServer> dnsServer;
};
// Include WiFiManagerHandlers.h after class definition to provide full definition
// needed for std::unique_ptr destructor
#include "WiFiManagerHandlers.h"
#endif // defined(ESP8266) || defined(ESP32)
#endif // WiFiManagerServer_h
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+173
View File
@@ -0,0 +1,173 @@
/**
* WiFiManagerServer.cpp
*
* Server lifecycle management implementation
*
* @author tablatronix
* @author Alex Hope-O'Connor
* @license MIT
*/
#include "WiFiManagerServer.h"
#include "WiFiManager.h"
#include "WiFiManagerHandlers.h" // Full definition needed for unique_ptr
#if defined(ESP8266) || defined(ESP32)
WiFiManagerServer::WiFiManagerServer(WiFiManager* wm)
: _wm(wm), _handlers(std::make_unique<WiFiManagerHandlers>(wm)) {
}
void WiFiManagerServer::createServer(uint16_t port) {
// If server already exists, shutdown first to prevent leaks and connection drops
if (server) {
#ifdef WM_DEBUG_LEVEL
_wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("Server already exists, shutting down first"));
#endif
shutdownServer();
}
#ifdef WM_DEBUG_LEVEL
_wm->DEBUG_WM(F("Starting Web Portal"));
#endif
if(port != 80) {
#ifdef WM_DEBUG_LEVEL
_wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("http server started with custom port: "), port); // @todo not showing ip
#endif
}
server.reset(new AsyncWebServer(port));
}
void WiFiManagerServer::registerRoutes() {
if (!server) {
#ifdef WM_DEBUG_LEVEL
_wm->DEBUG_WM(WM_DEBUG_ERROR, F("[ERROR] Server not created, call createServer() first"));
#endif
return;
}
if (_wm->_webservercallback != NULL) {
#ifdef WM_DEBUG_LEVEL
_wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("[CB] _webservercallback calling"));
#endif
_wm->_webservercallback(); // @CALLBACK
}
/* Setup httpd callbacks, web pages: root, wifi config pages, SO captive portal detectors and not found. */
// Register routes with lambdas
server->on(WM_G(R_root), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleRoot(request);
});
server->on(WM_G(R_wifi), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleWifi(request, true);
});
server->on(WM_G(R_wifinoscan), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleWifi(request, false);
});
server->on(WM_G(R_wifisave), HTTP_POST, [this](AsyncWebServerRequest *request) {
this->_handlers->handleWifiSave(request);
});
server->on(WM_G(R_info), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleInfo(request);
});
server->on(WM_G(R_param), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleParam(request);
});
server->on(WM_G(R_paramsave), HTTP_POST, [this](AsyncWebServerRequest *request) {
this->_handlers->handleParamSave(request);
});
server->on(WM_G(R_restart), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleReset(request);
});
server->on(WM_G(R_exit), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleExit(request);
});
server->on(WM_G(R_close), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleClose(request);
});
server->on(WM_G(R_erase), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleErase(request, false);
});
server->on(WM_G(R_status), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleWiFiStatus(request);
});
server->on(WM_G(R_scanstatus), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleWiFiScanStatus(request);
});
// OTA Update routes
server->on(WM_G(R_update), HTTP_GET, [this](AsyncWebServerRequest *request) {
this->_handlers->handleUpdate(request);
});
server->on(WM_G(R_updatedone), HTTP_POST,
[this](AsyncWebServerRequest *request) {
this->_handlers->handleUpdateDone(request);
},
[this](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
this->_handlers->handleUpdating(request, filename, index, data, len, final);
}
);
// 404 handler
server->onNotFound([this](AsyncWebServerRequest *request) {
this->_handlers->handleNotFound(request);
});
server->begin(); // Web server start
#ifdef WM_DEBUG_LEVEL
_wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("HTTP server started"));
#endif
}
void WiFiManagerServer::setupDNSD() {
dnsServer.reset(new DNSServer());
/* Setup the DNS server redirecting all the domains to the apIP */
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
#ifdef WM_DEBUG_LEVEL
// DEBUG_WM("dns server started port: ",DNS_PORT);
_wm->DEBUG_WM(WM_DEBUG_DEV, F("dns server started with ip: "), WiFi.softAPIP()); // @todo not showing ip
#endif
const uint8_t DNS_PORT = 53;
dnsServer->start(DNS_PORT, F("*"), WiFi.softAPIP());
}
void WiFiManagerServer::processDNS() {
if (dnsServer) {
dnsServer->processNextRequest();
}
}
void WiFiManagerServer::shutdownServer() {
// @todo what is the proper way to shutdown and free the server up
// debug - many open issues aobut port not clearing for use with other servers
// AsyncWebServer doesn't have stop(), just reset the unique_ptr
if (server) {
server.reset();
}
// Shutdown DNS server
if (dnsServer) {
dnsServer->stop(); // free heap ?
dnsServer.reset();
}
}
#endif
@@ -15,13 +15,13 @@ void test_dns_server_created() {
// Wait for DNS server to be created
unsigned long start = millis();
while (!wm.dnsServer && (millis() - start < 1000)) {
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
// DNS server should be created when portal starts
TEST_ASSERT_NOT_NULL(wm.dnsServer);
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
wm.stopConfigPortal();
@@ -40,13 +40,13 @@ void test_dns_server_cleanup() {
// Wait for DNS server to be created
unsigned long start = millis();
while (!wm.dnsServer && (millis() - start < 1000)) {
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
// Verify DNS server exists
TEST_ASSERT_NOT_NULL(wm.dnsServer);
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
// Stop portal
wm.stopConfigPortal();
@@ -72,11 +72,11 @@ void test_dns_server_lifecycle_cycles() {
wm.process();
unsigned long start = millis();
while (!wm.dnsServer && (millis() - start < 1000)) {
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
TEST_ASSERT_NOT_NULL(wm.dnsServer);
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
wm.stopConfigPortal();
wm.process();
@@ -87,11 +87,11 @@ void test_dns_server_lifecycle_cycles() {
wm.process();
start = millis();
while (!wm.dnsServer && (millis() - start < 1000)) {
while (!wm.getDNSServer() && (millis() - start < 1000)) {
wm.process();
delay(10);
}
TEST_ASSERT_NOT_NULL(wm.dnsServer);
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
wm.stopConfigPortal();
wm.process();
@@ -1,6 +1,7 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include <WiFiManagerParameter.h>
#include "../test_main.h"
// Test autoConnect fallback flow
@@ -145,8 +146,8 @@ void test_portal_with_parameters_and_infrastructure() {
TEST_ASSERT_TRUE(wm.getConfigPortalActive());
// Verify infrastructure
TEST_ASSERT_NOT_NULL(wm.server);
TEST_ASSERT_NOT_NULL(wm.dnsServer);
TEST_ASSERT_NOT_NULL(wm.getServer());
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
// Verify parameters
TEST_ASSERT_EQUAL(2, wm.getParametersCount());
@@ -1,6 +1,7 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include <WiFiManagerParameter.h>
#include "../test_main.h"
// Test parameter value set directly
@@ -1,6 +1,7 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include <WiFiManagerParameter.h>
// Test custom parameters
void test_create_parameter() {
@@ -107,10 +107,10 @@ void test_config_portal_infrastructure() {
delay(200); // Give time for initialization
// Verify server object exists (must check while portal is active)
TEST_ASSERT_NOT_NULL_MESSAGE(wm.server, "Server object should exist when portal is active");
TEST_ASSERT_NOT_NULL_MESSAGE(wm.getServer(), "Server object should exist when portal is active");
// Verify DNS server exists
TEST_ASSERT_NOT_NULL_MESSAGE(wm.dnsServer, "DNS server object should exist when portal is active");
TEST_ASSERT_NOT_NULL_MESSAGE(wm.getDNSServer(), "DNS server object should exist when portal is active");
// Verify WiFi is in AP mode
WiFiMode_t mode = WiFi.getMode();
@@ -145,7 +145,7 @@ void test_start_web_portal() {
wm.process();
// Verify server object exists
TEST_ASSERT_NOT_NULL(wm.server);
TEST_ASSERT_NOT_NULL(wm.getServer());
wm.stopWebPortal();
@@ -76,8 +76,8 @@ void test_state_consistency_during_portal() {
// Verify state consistency
TEST_ASSERT_TRUE(wm.getConfigPortalActive());
TEST_ASSERT_NOT_NULL(wm.server);
TEST_ASSERT_NOT_NULL(wm.dnsServer);
TEST_ASSERT_NOT_NULL(wm.getServer());
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
// Process multiple times
for (int i = 0; i < 10; i++) {
+3 -2
View File
@@ -1,6 +1,7 @@
#include <unity.h>
#include <Arduino.h>
#include <WiFiManager.h>
#include <WiFiManagerParameter.h>
#include "../test_main.h"
// Test many start/stop cycles for memory leaks
@@ -56,8 +57,8 @@ void test_long_running_portal() {
TEST_ASSERT_TRUE(wm.getConfigPortalActive());
// Verify infrastructure remains
TEST_ASSERT_NOT_NULL(wm.server);
TEST_ASSERT_NOT_NULL(wm.dnsServer);
TEST_ASSERT_NOT_NULL(wm.getServer());
TEST_ASSERT_NOT_NULL(wm.getDNSServer());
delay(10);
}