838  Wi-Fi Hands-On Labs and Exercises

838.1 Learning Objectives

By completing these hands-on labs, you will be able to:

  • Configure ESP32 Wi-Fi in Station (STA) mode
  • Read digital sensor data using the DHT protocol
  • Create an HTTP web server on embedded hardware
  • Serve dynamic HTML content with live sensor readings
  • Analyze Wi-Fi channel congestion and optimize deployments
  • Calculate power consumption for battery-powered Wi-Fi devices
  • Design Wi-Fi network infrastructure for IoT applications

838.2 Hands-On Lab: Wi-Fi Weather Station

This interactive lab uses the Wokwi ESP32 simulator to build a complete Wi-Fi weather station. You will connect an ESP32 to Wi-Fi, read temperature and humidity data from a DHT22 sensor, and serve the readings through a simple web server.

838.2.1 Prerequisites

  • Basic understanding of Arduino/C++ syntax
  • Familiarity with Wi-Fi concepts from previous chapters
  • No physical hardware required (browser-based simulation)

838.2.2 About Wokwi

Wokwi is a free online simulator for Arduino, ESP32, and other microcontrollers. It allows you to build and test IoT projects entirely in your browser without purchasing hardware.

838.2.3 Launch the Simulator

Launch the simulator below to get started. The default project includes an ESP32 - you will add components and code as you progress.

TipSimulator Tips
  • Click on the ESP32 to see available pins
  • Use the + button to add components (search for “DHT22”)
  • Connect wires by clicking on pins
  • The Serial Monitor shows debug output
  • Press the green Play button to run your code

838.2.4 Step 1: Set Up the Circuit

  1. Add a DHT22 sensor: Click the + button and search for “DHT22”
  2. Wire the DHT22 to ESP32:
    • DHT22 VCC (pin 1) -> ESP32 3.3V
    • DHT22 Data (pin 2) -> ESP32 GPIO 4
    • DHT22 GND (pin 4) -> ESP32 GND
  3. Optional: Add an LED on GPIO 2 for status indication

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085'}}}%%
flowchart LR
    subgraph ESP32["ESP32 DevKit"]
        V33["3.3V"]
        G4["GPIO 4"]
        GND["GND"]
        G2["GPIO 2<br/>(Built-in LED)"]
    end

    subgraph DHT["DHT22 Sensor"]
        VCC["VCC"]
        DATA["Data"]
        NC["NC"]
        DGND["GND"]
    end

    V33 -.->|"Power"| VCC
    G4 -.->|"Data Signal"| DATA
    GND -.->|"Ground"| DGND

    style ESP32 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style DHT fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff

838.2.5 Step 2: Copy the Weather Station Code

Copy this code into the Wokwi code editor:

// Wi-Fi Weather Station Lab
// Reads DHT22 temperature/humidity and serves data via web server

#include <WiFi.h>
#include <WebServer.h>
#include "DHT.h"

// ========== CONFIGURATION ==========
// Note: In Wokwi simulator, use these credentials:
const char* ssid = "Wokwi-GUEST";
const char* password = "";  // Leave empty for Wokwi

// DHT Sensor Configuration
#define DHTPIN 4        // GPIO pin connected to DHT22 data pin
#define DHTTYPE DHT22   // DHT22 (AM2302)
#define LED_PIN 2       // Built-in LED for status

// ========== GLOBAL OBJECTS ==========
DHT dht(DHTPIN, DHTTYPE);
WebServer server(80);

// Sensor readings (global for access in handlers)
float temperature = 0.0;
float humidity = 0.0;
unsigned long lastReadTime = 0;
const unsigned long READ_INTERVAL = 2000;  // Read every 2 seconds

// ========== WEB PAGE HTML ==========
String getHTML() {
  String html = "<!DOCTYPE html><html><head>";
  html += "<meta charset='UTF-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<meta http-equiv='refresh' content='5'>";  // Auto-refresh every 5s
  html += "<title>ESP32 Weather Station</title>";
  html += "<style>";
  html += "body { font-family: Arial, sans-serif; background: #1a1a2e; color: #eee; ";
  html += "display: flex; justify-content: center; align-items: center; ";
  html += "min-height: 100vh; margin: 0; }";
  html += ".container { text-align: center; background: #16213e; ";
  html += "padding: 40px; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); }";
  html += "h1 { color: #e94560; margin-bottom: 30px; }";
  html += ".reading { background: #0f3460; padding: 20px; margin: 15px; ";
  html += "border-radius: 15px; display: inline-block; min-width: 150px; }";
  html += ".value { font-size: 48px; font-weight: bold; color: #00fff5; }";
  html += ".label { font-size: 14px; color: #aaa; margin-top: 10px; }";
  html += ".unit { font-size: 24px; color: #e94560; }";
  html += ".status { margin-top: 20px; font-size: 12px; color: #666; }";
  html += "</style></head><body>";
  html += "<div class='container'>";
  html += "<h1>ESP32 Weather Station</h1>";
  html += "<div class='reading'>";
  html += "<div class='value'>" + String(temperature, 1) + "<span class='unit'>C</span></div>";
  html += "<div class='label'>Temperature</div>";
  html += "</div>";
  html += "<div class='reading'>";
  html += "<div class='value'>" + String(humidity, 1) + "<span class='unit'>%</span></div>";
  html += "<div class='label'>Humidity</div>";
  html += "</div>";
  html += "<div class='status'>Auto-refreshes every 5 seconds</div>";
  html += "</div></body></html>";
  return html;
}

// ========== REQUEST HANDLERS ==========
void handleRoot() {
  digitalWrite(LED_PIN, HIGH);  // Blink LED on request
  server.send(200, "text/html", getHTML());
  delay(50);
  digitalWrite(LED_PIN, LOW);
}

void handleJSON() {
  // API endpoint for JSON data
  String json = "{";
  json += "\"temperature\":" + String(temperature, 2) + ",";
  json += "\"humidity\":" + String(humidity, 2) + ",";
  json += "\"unit\":\"celsius\",";
  json += "\"timestamp\":" + String(millis());
  json += "}";
  server.send(200, "application/json", json);
}

void handleNotFound() {
  server.send(404, "text/plain", "404: Not Found");
}

// ========== SENSOR READING ==========
void readSensor() {
  if (millis() - lastReadTime >= READ_INTERVAL) {
    float h = dht.readHumidity();
    float t = dht.readTemperature();

    // Check if readings are valid
    if (!isnan(h) && !isnan(t)) {
      humidity = h;
      temperature = t;
      Serial.printf("Temperature: %.1f C, Humidity: %.1f%%\n", t, h);
    } else {
      Serial.println("Failed to read from DHT sensor!");
    }
    lastReadTime = millis();
  }
}

// ========== SETUP ==========
void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);

  Serial.println("\n========================================");
  Serial.println("   ESP32 Wi-Fi Weather Station Lab");
  Serial.println("========================================\n");

  // Initialize DHT sensor
  dht.begin();
  Serial.println("[OK] DHT22 sensor initialized");

  // Connect to Wi-Fi
  Serial.printf("[..] Connecting to %s", ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 30) {
    delay(500);
    Serial.print(".");
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));  // Blink while connecting
    attempts++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\n[OK] Wi-Fi connected!");
    Serial.print("[OK] IP Address: ");
    Serial.println(WiFi.localIP());
    digitalWrite(LED_PIN, HIGH);  // Solid LED when connected
  } else {
    Serial.println("\n[!!] Wi-Fi connection failed!");
    return;
  }

  // Set up web server routes
  server.on("/", handleRoot);
  server.on("/api/data", handleJSON);
  server.onNotFound(handleNotFound);

  // Start server
  server.begin();
  Serial.println("[OK] HTTP server started on port 80");
  Serial.println("\n========================================");
  Serial.printf("   Open: http://%s/\n", WiFi.localIP().toString().c_str());
  Serial.println("   API:  /api/data (JSON format)");
  Serial.println("========================================\n");
}

// ========== MAIN LOOP ==========
void loop() {
  server.handleClient();  // Handle incoming HTTP requests
  readSensor();           // Read sensor at intervals
}

838.2.6 Step 3: Configure the Wokwi Project

In Wokwi, configure the diagram.json file:

{
  "version": 1,
  "author": "IoT Class Lab",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-esp32-devkit-v1", "id": "esp", "top": 0, "left": 0, "attrs": {} },
    { "type": "wokwi-dht22", "id": "dht1", "top": -50, "left": 150, "attrs": {} }
  ],
  "connections": [
    [ "esp:TX0", "$serialMonitor:RX", "", [] ],
    [ "esp:RX0", "$serialMonitor:TX", "", [] ],
    [ "dht1:VCC", "esp:3V3", "red", [] ],
    [ "dht1:SDA", "esp:D4", "green", [] ],
    [ "dht1:GND", "esp:GND.1", "black", [] ]
  ],
  "dependencies": {}
}

838.2.7 Step 4: Run and Test

  1. Click the Play button to start the simulation
  2. Watch the Serial Monitor for connection status
  3. Once connected, Wokwi provides a simulated IP address
  4. Click the IP address link to open the web page
  5. Observe temperature and humidity readings updating

838.2.8 Understanding the Code

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085'}}}%%
flowchart LR
    subgraph SENSOR["Sensing Layer"]
        DHT["DHT22<br/>Temp + Humidity"]
    end

    subgraph MCU["Processing Layer"]
        ESP["ESP32<br/>Read sensor<br/>Run web server<br/>Handle requests"]
    end

    subgraph NETWORK["Network Layer"]
        WIFI["Wi-Fi<br/>802.11 b/g/n"]
        HTTP["HTTP Server<br/>Port 80"]
    end

    subgraph CLIENT["Presentation Layer"]
        BROWSER["Web Browser<br/>HTML + CSS"]
        API["JSON API<br/>/api/data"]
    end

    DHT -->|"Digital Signal"| ESP
    ESP -->|"Connect"| WIFI
    WIFI -->|"TCP/IP"| HTTP
    HTTP -->|"GET /"| BROWSER
    HTTP -->|"GET /api/data"| API

    style DHT fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style ESP fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff
    style WIFI fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff

Key Components:

Component Purpose
WiFi.h ESP32 Wi-Fi library for network connectivity
WebServer.h Creates HTTP server to handle requests
DHT.h Library to read DHT22 temperature/humidity sensor
WiFi.begin() Initiates connection to Wi-Fi network
server.on() Registers URL routes and handler functions
server.handleClient() Processes incoming HTTP requests

838.2.9 Challenge Exercises

The DHT library can calculate the “feels like” temperature. Modify the code to:

  1. Calculate heat index using dht.computeHeatIndex(temperature, humidity, false)
  2. Display heat index on the web page alongside temperature
  3. Add a warning message if heat index exceeds 32C

Hint: Add a new variable heatIndex and update both readSensor() and getHTML().

Create a simple history feature:

  1. Store the last 10 temperature readings in an array
  2. Create a new endpoint /api/history that returns all readings as JSON
  3. Add a simple bar chart to the HTML using CSS

Hint: Use a circular buffer array and update it each read cycle.

Implement an alert system:

  1. Define HIGH_TEMP and LOW_TEMP thresholds
  2. Change the web page background color based on temperature:
    • Blue if below LOW_TEMP
    • Green if normal
    • Red if above HIGH_TEMP
  3. Blink the LED when temperature is outside normal range

Hint: Pass a “status” parameter to the HTML generation function.

Expand the weather station:

  1. Add a second DHT22 sensor on a different GPIO pin
  2. Read both sensors and display indoor/outdoor readings
  3. Calculate the difference between the two
  4. Add a /api/compare endpoint with both readings

Hint: Create a second DHT object with a different pin number.

Add professional IoT features:

  1. Enable mDNS so the device is accessible at weather.local
  2. Add Over-The-Air (OTA) update capability
  3. Create a /settings page to configure the device name

Hint: Include ESPmDNS.h and ArduinoOTA.h libraries.

838.2.10 Troubleshooting Guide

Problem Possible Cause Solution
“Failed to read from DHT sensor!” Incorrect wiring Check GPIO 4 connection to DHT22 data pin
Wi-Fi won’t connect Wrong credentials Use “Wokwi-GUEST” with empty password
Web page not loading Server not started Check Serial Monitor for IP address
Readings show NaN Sensor initialization failed Ensure dht.begin() is called in setup
Page loads but shows 0.0 First reading not complete Wait 2+ seconds after boot

838.3 Exercise 1: Wi-Fi Channel Analysis

Objective: Analyze 2.4 GHz and 5 GHz channel congestion to optimize IoT device placement

Tasks:

  1. Scan 2.4 GHz Spectrum (simulated or real):
    • Use Wi-Fi analyzer app (Wi-Fi Analyzer for Android, NetSpot for PC/Mac)
    • Identify all access points on channels 1, 6, 11
    • Measure signal strength (RSSI) for each AP
    • Calculate channel utilization percentage
  2. Identify Overlapping Channels:
    • Determine which APs cause interference
    • Find the least congested channel
    • Calculate expected throughput reduction from overlapping APs
  3. Compare 2.4 GHz vs 5 GHz:
    • Scan 5 GHz channels
    • Count total APs on each band
    • Recommend band selection for IoT devices
  4. Design Channel Plan:
    • For a building with 3 Wi-Fi APs, assign non-overlapping channels
    • Account for neighboring networks
    • Minimize interference for IoT sensors

838.4 Exercise 2: Wi-Fi Security Audit

Objective: Audit a Wi-Fi network for security vulnerabilities

Tasks:

  1. Identify Security Weaknesses:
    • Scan for WEP/WPA networks (outdated encryption)
    • Find APs with default SSIDs
    • Detect open networks
    • Identify WPS-enabled networks
  2. Test WPA2/WPA3 Configuration:
    • Verify encryption method (CCMP vs TKIP)
    • Check if WPA2-Enterprise is available
    • Test guest network isolation
  3. IoT Device Security Assessment:
    • Inventory all IoT devices on network
    • Identify devices using weak passwords
    • Check for HTTP admin panels
    • Scan for outdated firmware
  4. Create Security Improvement Plan:
    • Upgrade to WPA3 if supported
    • Disable WPS
    • Create separate IoT VLAN

838.5 Exercise 3: Wi-Fi Power Consumption Measurement

Objective: Measure and optimize Wi-Fi power consumption for battery-powered IoT sensors

Scenario: ESP32-based temperature sensor sending data every 10 minutes

Tasks:

  1. Measure Current Draw (use multimeter or power analyzer):
    • Wi-Fi connection establishment
    • Active transmission
    • Wi-Fi modem sleep
    • Deep sleep
  2. Calculate Battery Life:
    • Battery: 2x AA (3000 mAh)
    • Operating voltage: 3.3V
    • Daily cycles: 144 (every 10 minutes)
  3. Optimize for 1-Year Battery Life:
    • Option A: Wi-Fi 4 with standard sleep
    • Option B: Wi-Fi 6 with TWT
    • Option C: Reduce transmission frequency

Expected Outcome:

Power Consumption Measurement:
====================================
ESP32 Wi-Fi Power States:

1. Deep Sleep: 10 uA
2. Wi-Fi Connecting: 160 mA for 2s
3. Transmitting Data: 120 mA for 1s
4. Wi-Fi Modem Sleep: 15 mA

Daily Power Budget (144 cycles):
====================================
Deep Sleep (23h 48m):
- 23.8h x 0.010 mA = 0.238 mAh

Wi-Fi Connection (144 x 2s):
- 288s x 160 mA / 3600 = 12.8 mAh

Data Transmission (144 x 1s):
- 144s x 120 mA / 3600 = 4.8 mAh

Total Daily: 17.84 mAh/day
Battery Life: 3000 mAh / 17.84 = 168 days

Optimization Strategy:
====================================
Option A: Wi-Fi 4 (current) -> 168 days
Option B: Wi-Fi 6 + TWT -> ~300 days
Option C: 30-minute intervals -> 456 days

Recommended: Option C + Option B
- 30-minute transmission + Wi-Fi 6 TWT
- New daily budget: 6.5 mAh/day
- Battery life: 461 days (1.26 years)

838.6 Exercise 4: Wi-Fi Network Capacity Planning

Objective: Design Wi-Fi infrastructure for a 200-device IoT deployment

Scenario: Office building (2,000 sqm) deploying: - 100x Occupancy sensors (low bandwidth, 2.4 GHz) - 50x Smart lights (medium bandwidth, 2.4 GHz) - 30x Environmental sensors (low bandwidth, 2.4 GHz) - 20x Security cameras (high bandwidth, 5 GHz)

Tasks:

  1. Calculate Bandwidth Requirements:
    • Occupancy sensors: 100 bytes every 5 minutes
    • Smart lights: 200 bytes on state change
    • Environmental sensors: 500 bytes every 10 minutes
    • Cameras: 2 Mbps continuous
  2. Determine AP Count and Placement:
    • Consumer AP capacity: 30-50 devices
    • Enterprise AP capacity: 200-500 devices
    • Coverage area per AP
  3. Design VLAN Segmentation:
    • VLAN 10: Corporate laptops/phones
    • VLAN 20: IoT sensors
    • VLAN 30: Security cameras
    • VLAN 40: Guest network
  4. Calculate Total Cost:
    • Access points (enterprise-grade)
    • PoE switches for AP power
    • Controller software

838.7 Lab Summary

In these labs, you practiced:

  1. Connecting an ESP32 to a Wi-Fi network
  2. Reading temperature and humidity from a DHT22 sensor
  3. Creating an HTTP web server on embedded hardware
  4. Building a responsive web interface with auto-refresh
  5. Implementing a JSON API endpoint for data integration
  6. Analyzing Wi-Fi channel congestion
  7. Planning power budgets for battery-powered devices
  8. Designing network infrastructure for IoT

838.8 What’s Next

Apply your Wi-Fi knowledge by exploring: