-
Notifications
You must be signed in to change notification settings - Fork 0
Development Guide
Guide for developers who want to extend or contribute to ESP32 WiFi Utility.
Required Tools:
- PlatformIO Core or IDE
- Git
- Text editor or IDE (VS Code recommended)
Optional:
- ESPTool for manual flashing
- Serial monitor (Arduino IDE, PuTTY, screen)
1. Clone Repository:
git clone https://github.com/yourusername/esp32-wifi-utility.git
cd esp32-wifi-utility2. Open in PlatformIO:
# VS Code with PlatformIO extension
code .
# Or command line
pio run3. Build:
# Build for ESP32dev
pio run -e esp32dev
# Build for Feather TFT
pio run -e feather-esp32-s3-tft
# Build all environments
pio run4. Upload:
# Upload to connected device
pio run -e esp32dev --target upload
# Upload and monitor
pio run -e esp32dev --target upload --target monitoresp32-wifi-utility/
βββ include/ # Header files
β βββ config.h # System configuration
β βββ wifi_manager.h # WiFi management
β βββ web_server.h # Web interface
β βββ ap_config.h # AP persistence
β βββ station_config.h # Station persistence
β βββ channel_analyzer.h # Channel analysis
β βββ latency_analyzer.h # Latency testing
β βββ iperf_manager.h # iPerf integration
β βββ performance_monitor.h # Performance tracking
β βββ error_handling.h # Error management
β βββ logging.h # Logging system
β
βββ src/ # Source files
β βββ main.cpp # Entry point
β βββ wifi_manager.cpp # WiFi implementation
β βββ web_server.cpp # Web server pages
β βββ command_interface.cpp # Serial commands
β βββ ap_config.cpp # AP config persistence
β βββ station_config.cpp # Station config persistence
β βββ channel_analyzer.cpp # Channel scanning
β βββ latency_analyzer.cpp # Latency tests
β βββ iperf_manager.cpp # iPerf protocol
β βββ performance_monitor.cpp # Performance stats
β βββ error_handling.cpp # Error utilities
β βββ logging.cpp # Logging implementation
β βββ led_controller.cpp # LED control
β βββ base64_utils.cpp # Base64 encoding
β
βββ docs/ # Documentation
β βββ README.md # Documentation index
β βββ technical/ # Technical docs
β βββ user-guides/ # User guides
β βββ archive/ # Old documentation
β
βββ scripts/ # Build scripts
β βββ version-manager.sh # Version management
β
βββ test/ # Test files
β βββ README # Test documentation
β
βββ platformio.ini # Build configuration
βββ README.md # Project readme
βββ CHANGELOG.md # Version history
config.h - System-wide configuration constants
- WiFi settings
- Hardware pin definitions
- Buffer sizes
- Timeouts
wifi_manager.cpp - Core WiFi functionality
- Mode switching
- Network scanning
- Connection management
- QR code generation
web_server.cpp - Web interface implementation
- HTTP endpoints
- HTML page generation
- API handlers
command_interface.cpp - Serial command processor
- Command parsing
- Function dispatch
- Help system
The system uses a straightforward loop-based architecture:
void setup() {
// 1. Initialize subsystems
initializeSerial();
initializeLED();
initializeWiFi();
initializeWebServer();
// 2. Load configuration
if (hasStationConfig()) {
startStationMode();
} else {
startAccessPoint();
}
// 3. Start services
startWebServer();
}
void loop() {
// 1. Handle serial commands
processSerialCommands();
// 2. Handle web requests
if (webServerEnabled) {
handleWebServerRequests();
}
// 3. Update status
updateLEDStatus();
monitorWebServerState();
// 4. Background tasks
// (periodic scans, performance logging, etc.)
}Key Characteristics:
- No FreeRTOS tasks
- No queues or semaphores
- Simple sequential execution
- Direct function calls
Removed in v4.1.0:
- Task priorities
- Mutex locks
- Queue management
- Task communication
- Watchdog complications
Create header in include/:
// include/my_feature.h
#pragma once
#include <Arduino.h>
#include "config.h"
#include "logging.h"
#include "error_handling.h"
#define TAG_MYFEATURE "MyFeature"
// Initialize feature
void initializeMyFeature();
// Main functionality
Result<void> doSomething(int param);
// Configuration
void configureMyFeature(bool enabled);
// Status
void printMyFeatureStatus();Create source in src/:
// src/my_feature.cpp
#include "my_feature.h"
// State variables
static bool featureEnabled = false;
static int featureState = 0;
void initializeMyFeature() {
LOG_INFO(TAG_MYFEATURE, "Initializing...");
featureEnabled = true;
featureState = 0;
}
Result<void> doSomething(int param) {
if (!featureEnabled) {
return {ErrorCode::FEATURE_DISABLED, "Feature not initialized"};
}
if (param < 0) {
return {ErrorCode::INVALID_PARAMETER, "Parameter must be positive"};
}
LOG_DEBUG(TAG_MYFEATURE, "Doing something with param: %d", param);
featureState = param;
return {}; // Success
}
void configureMyFeature(bool enabled) {
featureEnabled = enabled;
LOG_INFO(TAG_MYFEATURE, "Feature %s", enabled ? "enabled" : "disabled");
}
void printMyFeatureStatus() {
Serial.println("ββββββββββββββββββββββββββββββββββββ");
Serial.println("My Feature Status");
Serial.println("ββββββββββββββββββββββββββββββββββββ");
Serial.printf("Enabled: %s\n", featureEnabled ? "Yes" : "No");
Serial.printf("State: %d\n", featureState);
Serial.println("ββββββββββββββββββββββββββββββββββββ");
}Update command_interface.cpp:
// In executeCommand()
else if (command == "myfeature") {
if (argument == "enable") {
configureMyFeature(true);
} else if (argument == "disable") {
configureMyFeature(false);
} else if (argument == "do") {
int param = secondArgument.toInt();
auto result = doSomething(param);
if (!result) {
LOG_ERROR(TAG_MYFEATURE, "%s", result.getMessage());
}
} else if (argument == "status") {
printMyFeatureStatus();
} else {
Serial.println("Usage: myfeature <enable|disable|do <n>|status>");
}
}
// In printHelp()
Serial.println(" myfeature enable - Enable feature");
Serial.println(" myfeature disable - Disable feature");
Serial.println(" myfeature do <number> - Do something");
Serial.println(" myfeature status - Show status");Update web_server.cpp:
// Register handler in startWebServer()
webServer->on("/myfeature", HTTP_GET, handleMyFeature);
// Implement page handler
void handleMyFeature() {
String html = htmlHeader("My Feature");
html += "<div class='card'>";
html += "<h2>My Feature Control</h2>";
html += "<button onclick='enableFeature()'>Enable</button>";
html += "<button onclick='disableFeature()'>Disable</button>";
html += "<div id='status'></div>";
html += "</div>";
html += "<script>";
html += "function enableFeature() {";
html += " fetch('/myfeature/enable').then(r => updateStatus());";
html += "}";
html += "function disableFeature() {";
html += " fetch('/myfeature/disable').then(r => updateStatus());";
html += "}";
html += "function updateStatus() {";
html += " fetch('/myfeature/status')";
html += " .then(r => r.json())";
html += " .then(d => document.getElementById('status').innerHTML = d.status);";
html += "}";
html += "updateStatus();";
html += "</script>";
html += htmlFooter();
webServer->send(200, "text/html", html);
}If your feature needs to save settings:
// include/my_feature_config.h
#pragma once
#include <Arduino.h>
void initializeMyFeatureConfig();
bool loadMyFeatureConfig();
bool saveMyFeatureConfig(int setting1, bool setting2);
void clearMyFeatureConfig();
void printMyFeatureConfig();// src/my_feature_config.cpp
#include "my_feature_config.h"
#include <Preferences.h>
static Preferences prefs;
void initializeMyFeatureConfig() {
loadMyFeatureConfig();
}
bool loadMyFeatureConfig() {
prefs.begin("myfeature", true); // Read-only
int setting1 = prefs.getInt("setting1", 0);
bool setting2 = prefs.getBool("setting2", false);
prefs.end();
// Apply settings to feature
configureMyFeature(setting2);
return true;
}
bool saveMyFeatureConfig(int setting1, bool setting2) {
prefs.begin("myfeature", false); // Read-write
prefs.putInt("setting1", setting1);
prefs.putBool("setting2", setting2);
prefs.end();
return true;
}Functions:
// camelCase for public functions
void initializeWiFi();
void startAccessPoint();
// static for internal/private functions
static void updateInternalState();
static bool validateInput();Variables:
// camelCase for local/member variables
int networkCount;
String currentSSID;
// UPPERCASE for constants
#define MAX_NETWORKS 20
const int TIMEOUT_MS = 5000;Types:
// PascalCase for types
enum class WiFiMode { IDLE, STATION, AP };
class NetworkAnalyzer { };
struct ScanResult { };Header Comments:
/**
* @brief Connects to WiFi network
* @param ssid Network SSID
* @param password Network password
* @return Result indicating success or error
*/
Result<void> connectToNetwork(const String& ssid, const String& password);Inline Comments:
// Single-line comment for brief explanations
int timeout = 5000; // 5 second timeout
/* Multi-line comment
for longer explanations
or disabled code blocks */Use Result:
Result<int> getValue() {
if (notInitialized) {
return {ErrorCode::NOT_INITIALIZED, "System not ready"};
}
return 42; // Success with value
}Check Results:
auto result = getValue();
if (!result) {
LOG_ERROR(TAG, "%s", result.getMessage());
return;
}
int value = result.getValue();Use Logging Macros:
LOG_INFO(TAG_WIFI, "Connecting to %s", ssid);
LOG_ERROR(TAG_CONFIG, "Save failed: %d", errorCode);
LOG_DEBUG(TAG_PERF, "Operation took %lu ms", duration);Don't use Serial.print directly:
// BAD
Serial.print("Connecting...");
// GOOD
LOG_INFO(TAG_WIFI, "Connecting to %s", ssid);Test All Environments:
# Build all configurations
pio run
# Build specific environment
pio run -e esp32dev
pio run -e feather-esp32-s3-tft
pio run -e feather-esp32-s3-reverse-tft1. Serial Commands:
# Connect to device
pio device monitor
# Test commands
> help
> mode station
> scan
> connect "TestNetwork" "password"
> status2. Web Interface:
- Access
http://[device-ip] - Test all pages
- Verify forms work
- Check mobile responsiveness
3. Configuration Persistence:
> config ap save "MyAP" "password" 6
> config ap show
> reboot
# Verify config persists after rebootMonitor Memory:
void loop() {
static unsigned long lastCheck = 0;
if (millis() - lastCheck > 60000) {
logMemoryStats(TAG_SYSTEM);
printAllPerformanceStats();
lastCheck = millis();
}
}Check for Leaks:
- Monitor free heap over time
- Should be stable
- Watch for gradual decrease
Enable Debug Logs:
void setup() {
setLogLevel(LogLevel::DEBUG);
setLogTimestamps(true);
}Add Debug Points:
LOG_DEBUG(TAG_MYFEATURE, "Variable x = %d", x);Check Heap:
Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap());
Serial.printf("Largest block: %d bytes\n", ESP.getMaxAllocHeap());Find Leaks:
// Before operation
size_t heapBefore = ESP.getFreeHeap();
// Do operation
performOperation();
// After operation
size_t heapAfter = ESP.getFreeHeap();
Serial.printf("Heap change: %d bytes\n", (int)(heapAfter - heapBefore));1. Fork & Clone:
git clone https://github.com/yourusername/esp32-wifi-utility.git
cd esp32-wifi-utility
git checkout -b feature/my-new-feature2. Make Changes:
- Follow code style
- Add documentation
- Test thoroughly
3. Commit:
git add .
git commit -m "Add my new feature"
git push origin feature/my-new-feature4. Create PR:
- Clear description
- List changes
- Include testing notes
Format:
[Type] Brief description
Detailed explanation of changes...
Types:
-
[Feature]- New functionality -
[Fix]- Bug fix -
[Docs]- Documentation -
[Refactor]- Code improvement -
[Test]- Test updates
Examples:
[Feature] Add network latency testing
Implements TCP-based latency measurement with jitter
calculation and quality assessment. Includes web
interface and serial commands.
[Fix] Correct AP channel validation
Channel selection was allowing invalid values. Now
properly validates against 1-13 range.
- Installation Guide - Setup instructions
- Command Reference - All commands
- API Reference - Programming interface
GitHub Repository β’ Report Issues β’ Discussions
ESP32 WiFi Utility v4.2.0 β’ MIT License β’ Β© Arunkumar Mourougappane
Version: 4.2.0
License: MIT