849 Wi-Fi Implementation: Comprehensive Lab
849.1 Learning Objectives
By the end of this lab, you will be able to:
- Build Production-Ready Wi-Fi Code: Implement robust connection management with exponential backoff
- Monitor Signal Quality: Track RSSI values, calculate quality percentages, and implement signal alerts
- Manage Power Modes: Configure and switch between modem sleep, light sleep, and active modes
- Perform HTTP Communication: Execute GET and POST requests with proper error handling
- Implement mDNS Discovery: Discover and advertise network services without hardcoded IPs
- Use Event-Driven Architecture: Handle Wi-Fi events for responsive connection management
What is this lab? A complete, production-ready ESP32 Wi-Fi implementation demonstrating best practices for IoT deployments.
Key Features Demonstrated: - Robust connection management with auto-reconnection - Signal strength monitoring and quality assessment - Power management mode transitions - HTTP client communication (GET/POST) - mDNS service discovery and advertisement - Event-driven architecture patterns
Time Required: ~45 minutes
Prerequisites: - Complete the basic ESP32 Wi-Fi chapters first - Understanding of HTTP and power management concepts
849.2 Prerequisites
Before starting this lab, you should be familiar with:
- Wi-Fi Implementation: ESP32 Basics: Basic Wi-Fi connection and configuration
- Wi-Fi Implementation: Power Optimization: Power-saving modes and battery life
- Wi-Fi Implementation: HTTP and WebSocket: HTTP communication patterns
849.3 Wi-Fi IoT Lab: Comprehensive ESP32 Implementation
This hands-on lab provides a comprehensive, production-ready ESP32 implementation demonstrating essential Wi-Fi IoT concepts. You will explore connection management, signal quality monitoring, power optimization, HTTP communication, and service discovery in a single integrated application.
849.3.1 What You Will Learn
In this lab, you will gain practical experience with:
- Robust Wi-Fi Connection Management: Implement connection handling with automatic reconnection, exponential backoff, and connection state monitoring
- Signal Quality Assessment: Monitor RSSI values, calculate signal quality percentages, and implement signal strength alerts
- Power Management Modes: Configure and switch between modem sleep, light sleep, and active modes based on application requirements
- HTTP/HTTPS Client Communication: Perform GET and POST requests to REST APIs with proper error handling and timeout management
- mDNS Service Discovery: Discover and advertise network services without hardcoded IP addresses
- Event-Driven Architecture: Use ESP32βs Wi-Fi event system for responsive connection handling
849.3.2 Lab Simulation
What This Simulates: A comprehensive ESP32 Wi-Fi implementation demonstrating connection management, RSSI monitoring, power modes, HTTP communication, and mDNS service discovery.
How to Use: 1. Click Start Simulation to launch the ESP32 2. Watch the Serial Monitor for connection status, RSSI readings, and power mode transitions 3. Observe HTTP requests being made to simulated endpoints 4. See mDNS service registration and discovery 5. Modify the code to experiment with different configurations
Copy the code below into the Wokwi editor to run the complete lab:
849.3.3 Complete Lab Code
/*
* =============================================================================
* Wi-Fi IoT Lab: Comprehensive ESP32 Implementation
* =============================================================================
*
* This lab demonstrates production-ready Wi-Fi IoT patterns including:
* - Robust connection management with reconnection handling
* - RSSI monitoring and signal quality assessment
* - Power management modes (modem sleep, light sleep)
* - HTTP/HTTPS client communication
* - mDNS service discovery and advertisement
*
* Target Platform: ESP32 (ESP-IDF/Arduino framework)
* Estimated Runtime: Continuous operation with periodic reporting
*
* Author: IoT Class Educational Series
* License: Educational Use
* =============================================================================
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <ESPmDNS.h>
#include <WiFiClient.h>
#include <esp_wifi.h>
#include <esp_sleep.h>
// =============================================================================
// CONFIGURATION SECTION
// =============================================================================
// Wi-Fi Credentials (in production, use secure provisioning)
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
// Device Configuration
const char* DEVICE_NAME = "esp32-iot-lab";
const char* DEVICE_TYPE = "environmental-sensor";
// HTTP Endpoints (simulated for lab purposes)
const char* HTTP_TEST_URL = "http://httpbin.org/get";
const char* HTTP_POST_URL = "http://httpbin.org/post";
// Timing Configuration (milliseconds)
const unsigned long WIFI_CONNECT_TIMEOUT = 30000;
const unsigned long RECONNECT_INITIAL_DELAY = 1000;
const unsigned long RECONNECT_MAX_DELAY = 60000;
const unsigned long RSSI_CHECK_INTERVAL = 5000;
const unsigned long HTTP_REQUEST_INTERVAL = 30000;
const unsigned long POWER_MODE_CYCLE_INTERVAL = 60000;
// RSSI Thresholds (dBm)
const int RSSI_EXCELLENT = -50;
const int RSSI_GOOD = -60;
const int RSSI_FAIR = -70;
const int RSSI_WEAK = -80;
const int RSSI_CRITICAL = -85;
// =============================================================================
// STATE MANAGEMENT
// =============================================================================
// Connection State Machine
enum WiFiState {
WIFI_STATE_DISCONNECTED,
WIFI_STATE_CONNECTING,
WIFI_STATE_CONNECTED,
WIFI_STATE_RECONNECTING,
WIFI_STATE_ERROR
};
// Power Management Modes
enum PowerMode {
POWER_MODE_ACTIVE,
POWER_MODE_MODEM_SLEEP,
POWER_MODE_LIGHT_SLEEP
};
// Global State Variables
WiFiState currentWiFiState = WIFI_STATE_DISCONNECTED;
PowerMode currentPowerMode = POWER_MODE_ACTIVE;
unsigned long reconnectDelay = RECONNECT_INITIAL_DELAY;
unsigned long lastReconnectAttempt = 0;
unsigned long lastRssiCheck = 0;
unsigned long lastHttpRequest = 0;
unsigned long lastPowerModeCycle = 0;
int connectionAttempts = 0;
int totalReconnections = 0;
bool mDNSStarted = false;
// Statistics Tracking
struct WiFiStatistics {
unsigned long totalConnectedTime;
unsigned long totalDisconnectedTime;
unsigned long connectionStartTime;
int rssiReadings[10];
int rssiReadingIndex;
int minRssi;
int maxRssi;
float avgRssi;
int httpSuccessCount;
int httpFailureCount;
int reconnectionCount;
} stats;
// =============================================================================
// UTILITY FUNCTIONS
// =============================================================================
/**
* Convert RSSI value to signal quality percentage
* @param rssi Signal strength in dBm
* @return Quality percentage (0-100)
*/
int rssiToQuality(int rssi) {
if (rssi >= -50) return 100;
if (rssi >= -60) return 80 + (rssi + 60) * 2;
if (rssi >= -70) return 60 + (rssi + 70) * 2;
if (rssi >= -80) return 40 + (rssi + 80) * 2;
if (rssi >= -90) return 20 + (rssi + 90) * 2;
return max(0, 10 + (rssi + 100));
}
/**
* Get human-readable signal quality description
* @param rssi Signal strength in dBm
* @return Quality description string
*/
const char* getSignalQualityDescription(int rssi) {
if (rssi >= RSSI_EXCELLENT) return "Excellent";
if (rssi >= RSSI_GOOD) return "Good";
if (rssi >= RSSI_FAIR) return "Fair";
if (rssi >= RSSI_WEAK) return "Weak";
if (rssi >= RSSI_CRITICAL) return "Critical";
return "Unusable";
}
/**
* Get Wi-Fi state as string
* @param state Current Wi-Fi state
* @return State description string
*/
const char* getWiFiStateString(WiFiState state) {
switch (state) {
case WIFI_STATE_DISCONNECTED: return "DISCONNECTED";
case WIFI_STATE_CONNECTING: return "CONNECTING";
case WIFI_STATE_CONNECTED: return "CONNECTED";
case WIFI_STATE_RECONNECTING: return "RECONNECTING";
case WIFI_STATE_ERROR: return "ERROR";
default: return "UNKNOWN";
}
}
/**
* Get power mode as string
* @param mode Current power mode
* @return Mode description string
*/
const char* getPowerModeString(PowerMode mode) {
switch (mode) {
case POWER_MODE_ACTIVE: return "ACTIVE";
case POWER_MODE_MODEM_SLEEP: return "MODEM_SLEEP";
case POWER_MODE_LIGHT_SLEEP: return "LIGHT_SLEEP";
default: return "UNKNOWN";
}
}
/**
* Print formatted timestamp
*/
void printTimestamp() {
unsigned long seconds = millis() / 1000;
unsigned long minutes = seconds / 60;
unsigned long hours = minutes / 60;
Serial.printf("[%02lu:%02lu:%02lu] ", hours % 24, minutes % 60, seconds % 60);
}
/**
* Update RSSI statistics
* @param rssi Current RSSI reading
*/
void updateRssiStats(int rssi) {
stats.rssiReadings[stats.rssiReadingIndex] = rssi;
stats.rssiReadingIndex = (stats.rssiReadingIndex + 1) % 10;
if (rssi < stats.minRssi) stats.minRssi = rssi;
if (rssi > stats.maxRssi) stats.maxRssi = rssi;
// Calculate rolling average
float sum = 0;
int count = 0;
for (int i = 0; i < 10; i++) {
if (stats.rssiReadings[i] != 0) {
sum += stats.rssiReadings[i];
count++;
}
}
if (count > 0) stats.avgRssi = sum / count;
}
/**
* Initialize statistics tracking
*/
void initStats() {
stats.totalConnectedTime = 0;
stats.totalDisconnectedTime = 0;
stats.connectionStartTime = 0;
stats.rssiReadingIndex = 0;
stats.minRssi = 0;
stats.maxRssi = -100;
stats.avgRssi = 0;
stats.httpSuccessCount = 0;
stats.httpFailureCount = 0;
stats.reconnectionCount = 0;
for (int i = 0; i < 10; i++) stats.rssiReadings[i] = 0;
}
// =============================================================================
// WIFI EVENT HANDLERS
// =============================================================================
/**
* Wi-Fi event callback handler
* Processes connection state changes and updates state machine
*/
void onWiFiEvent(WiFiEvent_t event) {
printTimestamp();
switch (event) {
case ARDUINO_EVENT_WIFI_STA_START:
Serial.println("Wi-Fi: Station mode started");
break;
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
Serial.println("Wi-Fi: Connected to access point");
currentWiFiState = WIFI_STATE_CONNECTING; // Still waiting for IP
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
Serial.print("Wi-Fi: Got IP address - ");
Serial.println(WiFi.localIP());
currentWiFiState = WIFI_STATE_CONNECTED;
reconnectDelay = RECONNECT_INITIAL_DELAY; // Reset backoff
connectionAttempts = 0;
stats.connectionStartTime = millis();
// Start mDNS after getting IP
if (!mDNSStarted) {
setupMDNS();
}
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
Serial.println("Wi-Fi: Disconnected from access point");
if (currentWiFiState == WIFI_STATE_CONNECTED) {
// Update connected time statistics
stats.totalConnectedTime += millis() - stats.connectionStartTime;
stats.reconnectionCount++;
}
currentWiFiState = WIFI_STATE_DISCONNECTED;
mDNSStarted = false;
break;
case ARDUINO_EVENT_WIFI_STA_LOST_IP:
Serial.println("Wi-Fi: Lost IP address");
currentWiFiState = WIFI_STATE_DISCONNECTED;
break;
default:
Serial.printf("Wi-Fi: Event %d\n", event);
break;
}
}
// =============================================================================
// WIFI CONNECTION MANAGEMENT
// =============================================================================
/**
* Initialize Wi-Fi connection with robust error handling
* @return true if connection initiated successfully
*/
bool initWiFi() {
printTimestamp();
Serial.println("Wi-Fi: Initializing connection...");
// Disconnect any existing connection
WiFi.disconnect(true);
delay(100);
// Set Wi-Fi mode to Station
WiFi.mode(WIFI_STA);
// Register event handler
WiFi.onEvent(onWiFiEvent);
// Configure Wi-Fi for performance/power balance
WiFi.setAutoReconnect(false); // We handle reconnection manually
WiFi.persistent(false); // Don't save to NVS (battery saving)
// Set transmit power (adjust based on distance to AP)
WiFi.setTxPower(WIFI_POWER_19_5dBm); // Full power for reliable connection
// Start connection
currentWiFiState = WIFI_STATE_CONNECTING;
connectionAttempts++;
Serial.printf("Wi-Fi: Connecting to '%s' (attempt %d)...\n", WIFI_SSID, connectionAttempts);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
return true;
}
/**
* Check Wi-Fi connection status and handle reconnection
* Implements exponential backoff for reconnection attempts
*/
void handleWiFiConnection() {
unsigned long currentTime = millis();
switch (currentWiFiState) {
case WIFI_STATE_DISCONNECTED:
case WIFI_STATE_RECONNECTING:
// Check if it's time for a reconnection attempt
if (currentTime - lastReconnectAttempt >= reconnectDelay) {
lastReconnectAttempt = currentTime;
printTimestamp();
Serial.printf("Wi-Fi: Reconnection attempt (delay: %lu ms)\n", reconnectDelay);
// Attempt reconnection
WiFi.disconnect(true);
delay(100);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
currentWiFiState = WIFI_STATE_RECONNECTING;
connectionAttempts++;
totalReconnections++;
// Exponential backoff with maximum limit
reconnectDelay = min(reconnectDelay * 2, RECONNECT_MAX_DELAY);
}
break;
case WIFI_STATE_CONNECTING:
// Check for connection timeout
if (WiFi.status() != WL_CONNECTED) {
if (connectionAttempts > 0 && currentTime - lastReconnectAttempt > WIFI_CONNECT_TIMEOUT) {
printTimestamp();
Serial.println("Wi-Fi: Connection timeout, will retry...");
currentWiFiState = WIFI_STATE_DISCONNECTED;
}
}
break;
case WIFI_STATE_CONNECTED:
// Verify connection is still valid
if (WiFi.status() != WL_CONNECTED) {
printTimestamp();
Serial.println("Wi-Fi: Connection lost unexpectedly");
currentWiFiState = WIFI_STATE_DISCONNECTED;
}
break;
case WIFI_STATE_ERROR:
// Attempt recovery after delay
if (currentTime - lastReconnectAttempt >= RECONNECT_MAX_DELAY) {
printTimestamp();
Serial.println("Wi-Fi: Attempting recovery from error state");
initWiFi();
}
break;
}
}
// =============================================================================
// RSSI MONITORING AND SIGNAL QUALITY
// =============================================================================
/**
* Monitor and report Wi-Fi signal strength
* Includes quality assessment and trend analysis
*/
void monitorRSSI() {
if (currentWiFiState != WIFI_STATE_CONNECTED) return;
unsigned long currentTime = millis();
if (currentTime - lastRssiCheck < RSSI_CHECK_INTERVAL) return;
lastRssiCheck = currentTime;
int rssi = WiFi.RSSI();
int quality = rssiToQuality(rssi);
const char* qualityDesc = getSignalQualityDescription(rssi);
updateRssiStats(rssi);
printTimestamp();
Serial.println("=== RSSI Report ===");
Serial.printf(" Current RSSI: %d dBm\n", rssi);
Serial.printf(" Signal Quality: %d%% (%s)\n", quality, qualityDesc);
Serial.printf(" Channel: %d\n", WiFi.channel());
Serial.printf(" BSSID: %s\n", WiFi.BSSIDstr().c_str());
// Print statistics if we have enough data
if (stats.maxRssi > -100) {
Serial.printf(" Min/Avg/Max RSSI: %d / %.1f / %d dBm\n",
stats.minRssi, stats.avgRssi, stats.maxRssi);
}
// Signal strength warnings
if (rssi < RSSI_CRITICAL) {
Serial.println(" WARNING: Signal critically weak - connection may drop!");
} else if (rssi < RSSI_WEAK) {
Serial.println(" NOTICE: Signal weak - consider moving device closer to AP");
}
// Visual signal bar
Serial.print(" Signal Bars: ");
int bars = map(constrain(rssi, -90, -30), -90, -30, 0, 5);
for (int i = 0; i < 5; i++) {
Serial.print(i < bars ? "|" : ".");
}
Serial.println();
Serial.println();
}
// =============================================================================
// POWER MANAGEMENT
// =============================================================================
/**
* Set Wi-Fi power management mode
* @param mode Target power mode
*/
void setPowerMode(PowerMode mode) {
printTimestamp();
Serial.printf("Power: Switching from %s to %s\n",
getPowerModeString(currentPowerMode),
getPowerModeString(mode));
switch (mode) {
case POWER_MODE_ACTIVE:
// Maximum performance, highest power consumption
WiFi.setSleep(false);
esp_wifi_set_ps(WIFI_PS_NONE);
Serial.println(" - Sleep disabled");
Serial.println(" - Maximum performance mode");
Serial.println(" - Typical current: 80-120 mA");
break;
case POWER_MODE_MODEM_SLEEP:
// Radio turns off between DTIM beacons
WiFi.setSleep(true);
esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
Serial.println(" - Modem sleep enabled");
Serial.println(" - Radio sleeps between beacons");
Serial.println(" - Typical current: 15-25 mA");
break;
case POWER_MODE_LIGHT_SLEEP:
// CPU can also sleep, wakes on Wi-Fi activity
WiFi.setSleep(true);
esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
Serial.println(" - Maximum power saving enabled");
Serial.println(" - CPU can enter light sleep");
Serial.println(" - Typical current: 0.8-3 mA");
Serial.println(" - Note: Increased latency expected");
break;
}
currentPowerMode = mode;
Serial.println();
}
/**
* Demonstrate power mode cycling
* Useful for understanding power consumption differences
*/
void cyclePowerModes() {
if (currentWiFiState != WIFI_STATE_CONNECTED) return;
unsigned long currentTime = millis();
if (currentTime - lastPowerModeCycle < POWER_MODE_CYCLE_INTERVAL) return;
lastPowerModeCycle = currentTime;
// Cycle through power modes for demonstration
switch (currentPowerMode) {
case POWER_MODE_ACTIVE:
setPowerMode(POWER_MODE_MODEM_SLEEP);
break;
case POWER_MODE_MODEM_SLEEP:
setPowerMode(POWER_MODE_LIGHT_SLEEP);
break;
case POWER_MODE_LIGHT_SLEEP:
setPowerMode(POWER_MODE_ACTIVE);
break;
}
}
/**
* Get current power consumption estimate
* @return Estimated current in mA
*/
float estimatePowerConsumption() {
if (currentWiFiState != WIFI_STATE_CONNECTED) {
return 0.01; // Deep sleep equivalent
}
switch (currentPowerMode) {
case POWER_MODE_ACTIVE:
return 100.0; // Average of TX/RX
case POWER_MODE_MODEM_SLEEP:
return 20.0;
case POWER_MODE_LIGHT_SLEEP:
return 2.0;
default:
return 50.0;
}
}
/**
* Calculate estimated battery life
* @param batteryCapacity_mAh Battery capacity in mAh
* @return Estimated battery life in hours
*/
float estimateBatteryLife(float batteryCapacity_mAh) {
float currentDraw = estimatePowerConsumption();
if (currentDraw <= 0) return 0;
return batteryCapacity_mAh / currentDraw;
}
// =============================================================================
// HTTP CLIENT COMMUNICATION
// =============================================================================
/**
* Perform HTTP GET request
* @param url Target URL
* @return Response code or negative error code
*/
int performHttpGet(const char* url) {
if (currentWiFiState != WIFI_STATE_CONNECTED) {
printTimestamp();
Serial.println("HTTP GET: Cannot perform request - not connected");
return -1;
}
printTimestamp();
Serial.printf("HTTP GET: Requesting %s\n", url);
HTTPClient http;
http.begin(url);
http.setTimeout(10000); // 10 second timeout
// Add headers
http.addHeader("User-Agent", "ESP32-IoT-Lab/1.0");
http.addHeader("Accept", "application/json");
unsigned long startTime = millis();
int httpCode = http.GET();
unsigned long duration = millis() - startTime;
if (httpCode > 0) {
Serial.printf("HTTP GET: Response code %d (took %lu ms)\n", httpCode, duration);
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.printf("HTTP GET: Response length: %d bytes\n", payload.length());
// Print first 200 characters of response
if (payload.length() > 200) {
Serial.println("HTTP GET: Response preview (first 200 chars):");
Serial.println(payload.substring(0, 200) + "...");
} else {
Serial.println("HTTP GET: Response:");
Serial.println(payload);
}
stats.httpSuccessCount++;
}
} else {
Serial.printf("HTTP GET: Failed with error: %s\n", http.errorToString(httpCode).c_str());
stats.httpFailureCount++;
}
http.end();
Serial.println();
return httpCode;
}
/**
* Perform HTTP POST request with JSON payload
* @param url Target URL
* @param jsonPayload JSON data to send
* @return Response code or negative error code
*/
int performHttpPost(const char* url, const String& jsonPayload) {
if (currentWiFiState != WIFI_STATE_CONNECTED) {
printTimestamp();
Serial.println("HTTP POST: Cannot perform request - not connected");
return -1;
}
printTimestamp();
Serial.printf("HTTP POST: Sending to %s\n", url);
Serial.printf("HTTP POST: Payload: %s\n", jsonPayload.c_str());
HTTPClient http;
http.begin(url);
http.setTimeout(10000);
// Set content type for JSON
http.addHeader("Content-Type", "application/json");
http.addHeader("User-Agent", "ESP32-IoT-Lab/1.0");
unsigned long startTime = millis();
int httpCode = http.POST(jsonPayload);
unsigned long duration = millis() - startTime;
if (httpCode > 0) {
Serial.printf("HTTP POST: Response code %d (took %lu ms)\n", httpCode, duration);
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_CREATED) {
String response = http.getString();
Serial.printf("HTTP POST: Response length: %d bytes\n", response.length());
stats.httpSuccessCount++;
}
} else {
Serial.printf("HTTP POST: Failed with error: %s\n", http.errorToString(httpCode).c_str());
stats.httpFailureCount++;
}
http.end();
Serial.println();
return httpCode;
}
/**
* Send sensor data via HTTP POST
* Demonstrates typical IoT data transmission pattern
*/
void sendSensorData() {
// Simulate sensor readings
float temperature = 22.5 + random(-50, 50) / 10.0;
float humidity = 45.0 + random(-100, 100) / 10.0;
int rssi = WiFi.RSSI();
// Build JSON payload
String payload = "{";
payload += "\"device\":\"" + String(DEVICE_NAME) + "\",";
payload += "\"type\":\"" + String(DEVICE_TYPE) + "\",";
payload += "\"temperature\":" + String(temperature, 1) + ",";
payload += "\"humidity\":" + String(humidity, 1) + ",";
payload += "\"rssi\":" + String(rssi) + ",";
payload += "\"uptime\":" + String(millis() / 1000) + ",";
payload += "\"power_mode\":\"" + String(getPowerModeString(currentPowerMode)) + "\"";
payload += "}";
performHttpPost(HTTP_POST_URL, payload);
}
/**
* Periodic HTTP operations handler
*/
void handleHttpOperations() {
if (currentWiFiState != WIFI_STATE_CONNECTED) return;
unsigned long currentTime = millis();
if (currentTime - lastHttpRequest < HTTP_REQUEST_INTERVAL) return;
lastHttpRequest = currentTime;
printTimestamp();
Serial.println("=== HTTP Operations ===");
// Alternate between GET and POST for demonstration
static bool doPost = false;
if (doPost) {
sendSensorData();
} else {
performHttpGet(HTTP_TEST_URL);
}
doPost = !doPost;
}
// =============================================================================
// MDNS SERVICE DISCOVERY
// =============================================================================
/**
* Initialize mDNS service for local network discovery
*/
void setupMDNS() {
if (currentWiFiState != WIFI_STATE_CONNECTED) return;
printTimestamp();
Serial.println("mDNS: Starting service...");
// Start mDNS responder
if (MDNS.begin(DEVICE_NAME)) {
Serial.printf("mDNS: Hostname registered: %s.local\n", DEVICE_NAME);
// Advertise HTTP service
MDNS.addService("http", "tcp", 80);
Serial.println("mDNS: HTTP service advertised on port 80");
// Advertise custom IoT service
MDNS.addService("iot-sensor", "tcp", 8080);
MDNS.addServiceTxt("iot-sensor", "tcp", "type", DEVICE_TYPE);
MDNS.addServiceTxt("iot-sensor", "tcp", "version", "1.0");
Serial.println("mDNS: Custom IoT service advertised on port 8080");
mDNSStarted = true;
Serial.printf("mDNS: Device discoverable at http://%s.local/\n", DEVICE_NAME);
} else {
Serial.println("mDNS: Failed to start responder");
}
Serial.println();
}
/**
* Discover services on the local network
* @param serviceType Service type to search for (e.g., "http", "mqtt")
* @param protocol Protocol (usually "tcp")
*/
void discoverServices(const char* serviceType, const char* protocol) {
if (currentWiFiState != WIFI_STATE_CONNECTED) return;
printTimestamp();
Serial.printf("mDNS: Searching for _%s._%s services...\n", serviceType, protocol);
int serviceCount = MDNS.queryService(serviceType, protocol);
if (serviceCount == 0) {
Serial.println("mDNS: No services found");
} else {
Serial.printf("mDNS: Found %d service(s):\n", serviceCount);
for (int i = 0; i < serviceCount; i++) {
Serial.printf(" %d. %s (%s:%d)\n",
i + 1,
MDNS.hostname(i).c_str(),
MDNS.IP(i).toString().c_str(),
MDNS.port(i));
}
}
Serial.println();
}
/**
* Demonstrate mDNS discovery capabilities
*/
void demonstrateMDNSDiscovery() {
if (!mDNSStarted) return;
printTimestamp();
Serial.println("=== mDNS Service Discovery Demo ===");
// Search for common IoT services
discoverServices("http", "tcp");
discoverServices("mqtt", "tcp");
discoverServices("iot-sensor", "tcp");
}
// =============================================================================
// STATUS REPORTING
// =============================================================================
/**
* Print comprehensive system status
*/
void printSystemStatus() {
printTimestamp();
Serial.println("========================================");
Serial.println(" Wi-Fi IoT Lab Status Report ");
Serial.println("========================================");
// Connection Status
Serial.println("\n--- Connection Status ---");
Serial.printf(" State: %s\n", getWiFiStateString(currentWiFiState));
Serial.printf(" Wi-Fi Status: %d\n", WiFi.status());
if (currentWiFiState == WIFI_STATE_CONNECTED) {
Serial.printf(" SSID: %s\n", WiFi.SSID().c_str());
Serial.printf(" IP: %s\n", WiFi.localIP().toString().c_str());
Serial.printf(" RSSI: %d dBm (%s)\n", WiFi.RSSI(),
getSignalQualityDescription(WiFi.RSSI()));
Serial.printf(" Channel: %d\n", WiFi.channel());
}
// Power Status
Serial.println("\n--- Power Management ---");
Serial.printf(" Mode: %s\n", getPowerModeString(currentPowerMode));
Serial.printf(" Est. Current: %.1f mA\n", estimatePowerConsumption());
Serial.printf(" Battery Life (2000mAh): %.1f hours\n",
estimateBatteryLife(2000));
// Statistics
Serial.println("\n--- Session Statistics ---");
Serial.printf(" Uptime: %lu seconds\n", millis() / 1000);
Serial.printf(" Connection Attempts: %d\n", connectionAttempts);
Serial.printf(" Total Reconnections: %d\n", stats.reconnectionCount);
Serial.printf(" HTTP Success/Failure: %d/%d\n",
stats.httpSuccessCount, stats.httpFailureCount);
if (stats.maxRssi > -100) {
Serial.printf(" RSSI Range: %d to %d dBm (avg: %.1f)\n",
stats.minRssi, stats.maxRssi, stats.avgRssi);
}
// mDNS Status
Serial.println("\n--- mDNS Service ---");
Serial.printf(" Status: %s\n", mDNSStarted ? "Active" : "Inactive");
if (mDNSStarted) {
Serial.printf(" Hostname: %s.local\n", DEVICE_NAME);
}
Serial.println("\n========================================\n");
}
// =============================================================================
// MAIN SETUP AND LOOP
// =============================================================================
void setup() {
// Initialize serial communication
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("========================================");
Serial.println(" Wi-Fi IoT Lab - ESP32 Implementation ");
Serial.println("========================================");
Serial.println();
Serial.println("This lab demonstrates:");
Serial.println(" - Robust Wi-Fi connection management");
Serial.println(" - RSSI monitoring and signal quality");
Serial.println(" - Power management modes");
Serial.println(" - HTTP/HTTPS client communication");
Serial.println(" - mDNS service discovery");
Serial.println();
Serial.println("Starting in 3 seconds...");
Serial.println();
delay(3000);
// Initialize statistics
initStats();
// Initialize Wi-Fi connection
initWiFi();
// Set initial power mode
setPowerMode(POWER_MODE_MODEM_SLEEP);
// Record initial reconnect time
lastReconnectAttempt = millis();
}
void loop() {
// Handle Wi-Fi connection state
handleWiFiConnection();
// Only perform operations when connected
if (currentWiFiState == WIFI_STATE_CONNECTED) {
// Monitor RSSI periodically
monitorRSSI();
// Handle HTTP operations
handleHttpOperations();
// Cycle through power modes for demonstration
cyclePowerModes();
}
// Print status report every 2 minutes
static unsigned long lastStatusReport = 0;
if (millis() - lastStatusReport >= 120000) {
lastStatusReport = millis();
printSystemStatus();
// Demonstrate mDNS discovery
if (mDNSStarted) {
demonstrateMDNSDiscovery();
}
}
// Small delay to prevent busy-waiting
delay(100);
}
// =============================================================================
// END OF WIFI IOT LAB
// =============================================================================849.3.4 Challenge Exercises
After running the basic lab, try these challenges to deepen your understanding:
849.3.5 Expected Outcomes
After completing this lab, you should observe:
| Behavior | Expected Output |
|---|---|
| Connection Sequence | Wi-Fi connects within 5-10 seconds, IP address assigned via DHCP |
| RSSI Monitoring | Signal strength updates every 5 seconds with quality assessment |
| Power Mode Cycling | Transitions between Active, Modem Sleep, and Light Sleep modes |
| HTTP Requests | GET/POST operations complete with response codes and timing |
| mDNS Discovery | Device discoverable at esp32-iot-lab.local, services advertised |
| Reconnection | Automatic reconnection with exponential backoff if connection drops |
| Statistics | Running totals of connection events, HTTP success/failure rates |
849.3.6 Key Learning Points
Event-Driven Architecture: Using
WiFi.onEvent()provides responsive connection state handling without pollingExponential Backoff: The reconnection delay doubles each attempt (1s, 2s, 4s, 8sβ¦) up to a maximum, reducing network congestion during outages
Power Mode Trade-offs:
- Active: ~100 mA, lowest latency, highest reliability
- Modem Sleep: ~20 mA, some latency increase, good balance
- Light Sleep: ~2 mA, higher latency, best for battery devices
mDNS Benefits: Eliminates hardcoded IP addresses, enables dynamic service discovery, simplifies IoT network management
HTTP Best Practices: Always set timeouts, use appropriate headers, handle errors gracefully, consider payload size impact on power
849.3.7 Troubleshooting Guide
| Issue | Possible Cause | Solution |
|---|---|---|
| Connection timeout | Wrong credentials or AP not in range | Verify SSID/password, check AP status |
| RSSI shows -127 dBm | Not connected or driver issue | Ensure connected before reading RSSI |
| HTTP requests fail | No internet or firewall blocking | Check gateway connectivity, try local endpoint |
| mDNS not working | mDNS disabled on network | Check router settings, some networks block mDNS |
| High power consumption | Sleep mode not activating | Verify WiFi.setSleep(true) is called |
| Frequent reconnections | Weak signal or interference | Move closer to AP, change Wi-Fi channel |
849.4 Resources
849.4.1 Internal Resources
- Videos Hub - Wi-Fi/ESP32 tutorials and protocol walkthroughs
- Simulations Hub - ESP32 Wi-Fi simulators
849.4.2 Tools and Utilities
- Wi-Fi Analyzer (Android/iOS) - Channel analysis
- Wireshark - Packet capture and analysis
- Fing - Network scanner, device discovery
- iPerf - Network speed testing
- ESP32 Provisioning App - Wi-Fi setup for ESP32
849.4.3 Hardware Platforms
- ESP32 - Common Wi-Fi SoC for IoT
- ESP8266 - Low-cost Wi-Fi module
- Raspberry Pi - Wi-Fi-enabled SBC
- Arduino Wi-Fi - Arduino with onboard Wi-Fi
- CC3200 - TI Wi-Fi microcontroller
849.4.4 Standards and Documentation
849.5 Summary
This comprehensive lab demonstrated production-ready Wi-Fi IoT implementation patterns:
- Robust Connection Management: Event-driven architecture with automatic reconnection and exponential backoff
- Signal Quality Monitoring: RSSI tracking, quality assessment, and signal strength alerts
- Power Management: Configuring modem sleep, light sleep, and active modes for power optimization
- HTTP Communication: GET/POST requests with proper error handling and timeout management
- mDNS Service Discovery: Advertising and discovering network services without hardcoded IPs
- Statistics Tracking: Monitoring connection events, HTTP success rates, and RSSI trends
849.6 Whatβs Next
Continue your Wi-Fi learning with Wi-Fi Comprehensive Review, covering Wi-Fi standards evolution, Wi-Fi 6 features, WPA3 security, and channel planning for dense deployments.