Files
esp32-Serial-Logger/ESP32_SerialLogger.ino
2026-02-14 23:14:00 +00:00

191 lines
6.1 KiB
C++

// ============================================================
// ESP32 Serial Logger
// Hardware: ESP-WROOM-32D DevKitC V4
//
// Arduino IDE Settings:
// Board: "ESP32 Dev Module"
// Upload Speed: 921600
// CPU Frequency: 240MHz (WiFi/BT)
// Flash Frequency: 80MHz
// Flash Mode: QIO
// Flash Size: 4MB (32Mb)
// Partition Scheme: "Huge APP (3MB No OTA/1MB SPIFFS)"
// PSRAM: Disabled
//
// Required Libraries:
// 1. WebSocketsServer by Links2004
// (Install: Library Manager -> "WebSockets" by Markus Sattler)
// 2. ArduinoJson by Benoit Blanchon v6.x
// (Install: Library Manager -> "ArduinoJson")
// 3. SD (built-in)
// 4. SPI (built-in)
//
// Pin Assignments:
// UART2 TX: GPIO17 | UART2 RX: GPIO16
// SD CLK: GPIO14 | SD MISO: GPIO26 | SD MOSI: GPIO13 | SD CS: GPIO15
// ============================================================
#include <Arduino.h>
#include <WiFi.h>
#include <esp_wifi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <SD.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include <sys/time.h>
#include <time.h>
#include "config.h"
#include "serial_task.h"
#include "sdcard_task.h"
#include "web_task.h"
// ============================================================
// NTP Time Sync Task
// Only works in STA mode (internet required)
// In AP mode, time is synced from browser via WebSocket
// ============================================================
void ntpSyncTask(void *param) {
Serial.println("[Task] NTP Sync started");
// Only attempt NTP if connected to external WiFi (STA mode)
if (WiFi.getMode() == WIFI_AP) {
Serial.println("[NTP] AP mode - skipping NTP, waiting for browser time sync");
// In AP mode, just keep task alive for potential future use
while (true) {
vTaskDelay(pdMS_TO_TICKS(60000));
}
}
// STA mode - try NTP
configTime(NTP_GMT_OFFSET, NTP_DAYLIGHT_OFFSET, NTP_SERVER);
struct tm timeinfo;
int retries = 0;
while (!getLocalTime(&timeinfo) && retries < 5) {
Serial.println("[NTP] Waiting for time sync...");
vTaskDelay(pdMS_TO_TICKS(1000));
retries++;
}
if (getLocalTime(&timeinfo)) {
Serial.printf("[NTP] Synced: %04d-%02d-%02d %02d:%02d:%02d\n",
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
} else {
Serial.println("[NTP] Failed - will use browser time when client connects");
}
// Periodic re-sync every 1 hour
while (true) {
vTaskDelay(pdMS_TO_TICKS(3600000));
configTime(NTP_GMT_OFFSET, NTP_DAYLIGHT_OFFSET, NTP_SERVER);
Serial.println("[NTP] Time re-synced");
}
}
// ============================================================
// WiFi Connection (STA + fallback AP mode)
// ============================================================
void wifiConnect() {
Serial.println("[WiFi] Connecting to: " + String(WIFI_SSID));
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
WiFi.setSleep(false);
unsigned long startTime = millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (millis() - startTime > WIFI_CONNECT_TIMEOUT) {
Serial.println("\n[WiFi] STA failed! Starting AP mode...");
WiFi.mode(WIFI_AP);
WiFi.softAP(WIFI_AP_SSID, WIFI_AP_PASSWORD);
Serial.println("[WiFi] AP SSID: " + String(WIFI_AP_SSID));
Serial.println("[WiFi] AP IP: " + WiFi.softAPIP().toString());
return;
}
}
Serial.println();
Serial.println("[WiFi] Connected! IP: " + WiFi.localIP().toString());
Serial.println("[WiFi] RSSI: " + String(WiFi.RSSI()) + " dBm");
}
// ============================================================
// Setup
// ============================================================
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("============================================");
Serial.println(" ESP32 Serial Logger v1.0");
Serial.println(" ESP-WROOM-32D DevKitC V4");
Serial.println("============================================");
Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap());
Serial.printf(" CPU Freq: %d MHz\n", getCpuFrequencyMhz());
Serial.println("============================================");
// 1. WiFi
wifiConnect();
// 2. NTP (STA mode only) + Browser time sync (AP mode)
xTaskCreatePinnedToCore(ntpSyncTask, "NTP", TASK_STACK_NTP,
NULL, TASK_PRIORITY_NTP, NULL, 0);
if (WiFi.getMode() != WIFI_AP) {
delay(2000); // Brief wait for NTP only in STA mode
} else {
Serial.println("[Time] AP mode: time will sync from browser on first connect");
}
// 3. SD Card
sdTaskInit();
// 4. Serial2 UART
serialTaskInit();
// 5. Web Server + WebSocket
webTaskInit();
Serial.println("============================================");
Serial.println(" All tasks started!");
Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap());
String ip = (WiFi.getMode() == WIFI_AP) ?
WiFi.softAPIP().toString() : WiFi.localIP().toString();
Serial.println(" URL: http://" + ip);
Serial.println("============================================");
Serial.println("\n Task Layout:");
Serial.println(" Core 1: SerialRX(5), SerialTX(4)");
Serial.println(" Core 0: SDLog(3), WebBC(2), NTP(1)");
Serial.println(" Loop : server.handleClient()");
Serial.println(" Time : NTP(STA) or Browser sync(AP)");
Serial.println("============================================\n");
}
// ============================================================
// Loop - handles HTTP requests (must be on main loop)
// ============================================================
void loop() {
server.handleClient();
vTaskDelay(pdMS_TO_TICKS(2));
// Periodic status report (30s)
static unsigned long lastReport = 0;
if (millis() - lastReport > 30000) {
lastReport = millis();
Serial.printf("[SYS] Heap: %d | MinHeap: %d | SD: %s | WS: %d clients\n",
ESP.getFreeHeap(),
ESP.getMinFreeHeap(),
sdCardPresent() ? "OK" : "FAIL",
webSocket.connectedClients());
}
}