239 lines
7.7 KiB
Markdown
239 lines
7.7 KiB
Markdown
# ESP32 MP3 Player - Web Request & WiFiManager Memory Optimizations
|
|
|
|
## High-Impact Web Request Optimizations
|
|
|
|
### 1. **ESPAsyncWifiManager Configuration Optimization** (HIGH IMPACT: 10-20KB)
|
|
|
|
The ESPAsyncWifiManager can be configured to use less memory:
|
|
|
|
```cpp
|
|
// In setup(), before wifiManager.autoConnect():
|
|
AsyncWiFiManager wifiManager(&server, &dns);
|
|
|
|
// Reduce timeout to free memory faster
|
|
wifiManager.setTimeout(60); // Reduced from 180 to 60 seconds
|
|
|
|
// Disable debug output to save memory
|
|
wifiManager.setDebugOutput(false);
|
|
|
|
// Set custom parameters to reduce memory usage
|
|
wifiManager.setConfigPortalBlocking(false); // Non-blocking mode saves memory
|
|
wifiManager.setConnectTimeout(20); // Faster connection timeout
|
|
wifiManager.setConfigPortalTimeout(60); // Shorter portal timeout
|
|
```
|
|
|
|
### 2. **Web Server Request Handler Optimization** (MEDIUM IMPACT: 5-10KB)
|
|
|
|
Current issue: Each request handler creates temporary objects and strings.
|
|
|
|
**Optimization A: Use String References Instead of Copies**
|
|
```cpp
|
|
// Replace current parameter handling with more efficient version:
|
|
void id_song_action(AsyncWebServerRequest *request)
|
|
{
|
|
const AsyncWebParameter* p = request->getParam("id");
|
|
if (p != nullptr) {
|
|
playSongById(p->value().toInt()); // Direct conversion, no string copy
|
|
}
|
|
lastInteraction = millis();
|
|
request->send_P(200, "text/plain", "ok"); // Use PROGMEM string
|
|
}
|
|
```
|
|
|
|
**Optimization B: Reduce JSON Buffer Allocations**
|
|
```cpp
|
|
String getState()
|
|
{
|
|
// Use static buffer to avoid repeated allocations
|
|
static DynamicJsonDocument jsonState(384); // Further reduced from 512
|
|
jsonState.clear(); // Clear previous data
|
|
|
|
jsonState[F("playing")] = audio.isRunning(); // Use F() macro
|
|
|
|
if (currentNode != nullptr)
|
|
jsonState[F("title")] = *currentNode->getCurrentPlaying();
|
|
else
|
|
jsonState[F("title")] = F("Angehalten"); // Store in flash
|
|
|
|
jsonState[F("time")] = audio.getAudioCurrentTime();
|
|
jsonState[F("volume")] = audio.getVolume();
|
|
jsonState[F("length")] = audio.getAudioFileDuration();
|
|
jsonState[F("voltage")] = lastVoltage;
|
|
jsonState[F("uid")] = lastUid;
|
|
jsonState[F("heap")] = free_heap;
|
|
|
|
String output;
|
|
output.reserve(256); // Pre-allocate string buffer
|
|
serializeJson(jsonState, output);
|
|
return output;
|
|
}
|
|
```
|
|
|
|
### 3. **File Upload Handler Memory Optimization** (HIGH IMPACT: 15-30KB)
|
|
|
|
Current issue: Large temporary buffers and inefficient string operations.
|
|
|
|
```cpp
|
|
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
|
static String logBuffer; // Static to avoid repeated allocations
|
|
|
|
if (!index) {
|
|
// Use const references to avoid string copies
|
|
const String& lowerFilename = filename;
|
|
|
|
// Pre-allocate log buffer
|
|
logBuffer.reserve(128);
|
|
logBuffer = F("Upload Start: ");
|
|
logBuffer += filename;
|
|
|
|
// More efficient space check
|
|
uint32_t freeSpace = (SD.cardSize() - SD.usedBytes()) >> 20; // Bit shift instead of division
|
|
|
|
if (freeSpace < 10) {
|
|
request->send(507, F("text/plain"), F("Insufficient storage space"));
|
|
return;
|
|
}
|
|
|
|
Serial.println(logBuffer);
|
|
logBuffer.clear(); // Free memory immediately
|
|
|
|
// ... rest of upload logic
|
|
}
|
|
|
|
// Reduce logging frequency to save memory
|
|
if (len && (index % 204800 == 0)) { // Log every 200KB instead of 100KB
|
|
logBuffer = F("Upload: ");
|
|
logBuffer += humanReadableSize(index + len);
|
|
Serial.println(logBuffer);
|
|
logBuffer.clear();
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. **HTML Template Processing Optimization** (MEDIUM IMPACT: 3-5KB)
|
|
|
|
```cpp
|
|
String processor(const String &var)
|
|
{
|
|
if (var == F("DIRECTORY")) // Use F() macro
|
|
{
|
|
return rootNode.getDirectoryStructureHTML();
|
|
}
|
|
return String(); // Return empty string instead of creating new String
|
|
}
|
|
```
|
|
|
|
### 5. **Static Content Serving Optimization** (LOW IMPACT: 1-2KB)
|
|
|
|
```cpp
|
|
// Optimize CSS/JS serving with better error handling
|
|
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request) {
|
|
activateSD();
|
|
const char* cssPath = "/system/style.css";
|
|
if (SD.exists(cssPath)) {
|
|
request->send(SD, cssPath, F("text/css"));
|
|
} else {
|
|
// Serve minimal fallback without creating large strings
|
|
request->send_P(200, "text/css", "body{font-family:Arial;text-align:center;}");
|
|
}
|
|
deactivateSD();
|
|
});
|
|
```
|
|
|
|
## ESPAsyncWifiManager Specific Optimizations
|
|
|
|
### 6. **WiFiManager Memory Pool Configuration** (HIGH IMPACT: 15-25KB)
|
|
|
|
```cpp
|
|
// Add these configurations in setup():
|
|
void setup() {
|
|
// ... existing code ...
|
|
|
|
AsyncWiFiManager wifiManager(&server, &dns);
|
|
|
|
// Memory optimizations for WiFiManager
|
|
wifiManager.setDebugOutput(false); // Disable debug strings
|
|
wifiManager.setMinimumSignalQuality(20); // Reduce AP scan results
|
|
wifiManager.setRemoveDuplicateAPs(true); // Remove duplicate APs from memory
|
|
wifiManager.setConfigPortalBlocking(false); // Non-blocking saves memory
|
|
wifiManager.setScanDisposeDelay(5000); // Dispose scan results faster
|
|
|
|
// Reduce timeouts to free memory faster
|
|
wifiManager.setTimeout(60); // Reduced from 180
|
|
wifiManager.setConnectTimeout(15); // Faster connection attempts
|
|
wifiManager.setConfigPortalTimeout(60); // Shorter portal timeout
|
|
|
|
// Custom CSS/HTML to reduce memory usage (optional)
|
|
wifiManager.setCustomHeadElement(F("<style>body{font-size:14px;}</style>"));
|
|
|
|
if (wifiManager.autoConnect("HannaBox")) {
|
|
// ... existing server setup ...
|
|
}
|
|
}
|
|
```
|
|
|
|
## Additional Compiler & Build Optimizations
|
|
|
|
### 7. **Enhanced Build Flags** (MEDIUM IMPACT: 5-10KB)
|
|
|
|
Add to `platformio.ini`:
|
|
```ini
|
|
build_flags =
|
|
-Os ; Optimize for size
|
|
-DCORE_DEBUG_LEVEL=0 ; Disable all debug output
|
|
-DARDUINO_LOOP_STACK_SIZE=3072 ; Further reduce from 4096
|
|
-DWIFI_TASK_STACK_SIZE=3072 ; Reduce WiFi task stack
|
|
-DARDUINO_EVENT_TASK_STACK_SIZE=2048 ; Reduce event task stack
|
|
-DTCPIP_TASK_STACK_SIZE=2048 ; Reduce TCP/IP stack
|
|
-DESP_TASK_WDT_TIMEOUT_S=10 ; Reduce watchdog timeout
|
|
-DCONFIG_ASYNC_TCP_MAX_ACK_TIME=3000 ; Reduce TCP ACK timeout
|
|
-DCONFIG_ASYNC_TCP_QUEUE_SIZE=32 ; Reduce TCP queue size
|
|
```
|
|
|
|
## Implementation Priority
|
|
|
|
1. **IMMEDIATE (High Impact)**:
|
|
- ESPAsyncWifiManager configuration optimization
|
|
- File upload handler memory optimization
|
|
- Enhanced build flags
|
|
|
|
2. **SHORT TERM (Medium Impact)**:
|
|
- JSON buffer optimization with F() macros
|
|
- Web request handler optimization
|
|
- Static content serving optimization
|
|
|
|
3. **LONG TERM (Maintenance)**:
|
|
- Monitor memory usage patterns
|
|
- Consider implementing request queuing if needed
|
|
- Profile actual memory usage during web operations
|
|
|
|
## Expected Total Memory Savings
|
|
|
|
| Optimization Category | Memory Saved |
|
|
|----------------------|--------------|
|
|
| ESPAsyncWifiManager Config | 15-25KB |
|
|
| File Upload Handler | 15-30KB |
|
|
| JSON & String Optimizations | 5-10KB |
|
|
| Build Flag Optimizations | 5-10KB |
|
|
| **Total Potential Savings** | **40-75KB** |
|
|
|
|
## Testing & Validation
|
|
|
|
After implementing these optimizations:
|
|
|
|
1. Monitor free heap via web interface during:
|
|
- WiFi connection process
|
|
- File uploads
|
|
- Multiple concurrent web requests
|
|
- JSON state requests
|
|
|
|
2. Test stability under load:
|
|
- Multiple rapid web requests
|
|
- Large file uploads
|
|
- WiFi reconnection scenarios
|
|
|
|
3. Verify functionality:
|
|
- All web endpoints work correctly
|
|
- File uploads complete successfully
|
|
- WiFi manager portal functions properly
|