STA모드 추가
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// ============================================================
|
||||
// ESP32 Serial Logger
|
||||
// Hardware: ESP-WROOM-32D DevKitC V4
|
||||
// Hardware: ESP-WROOM-32D DevKitC V4 + DS3231 RTC
|
||||
//
|
||||
// Arduino IDE Settings:
|
||||
// Board: "ESP32 Dev Module"
|
||||
@@ -13,16 +13,19 @@
|
||||
// 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)
|
||||
// 1. WebSockets by Links2004
|
||||
// 2. ArduinoJson v6.x
|
||||
// 3. SoftWire by Steve Marple (+ AsyncDelay)
|
||||
// 4. SD, SPI (built-in)
|
||||
//
|
||||
// Pin Assignments:
|
||||
// UART2 TX: GPIO17 | UART2 RX: GPIO16
|
||||
// SD CLK: GPIO14 | SD MISO: GPIO26 | SD MOSI: GPIO13 | SD CS: GPIO15
|
||||
// SD MISO: GPIO19 | SD MOSI: GPIO23 | SD SCLK: GPIO18 | SD CS: GPIO5 (VSPI)
|
||||
// RTC SDA: GPIO25 | RTC SCL: GPIO26 (DS3231 @ 0x68, SoftWire)
|
||||
//
|
||||
// WiFi:
|
||||
// Boot → AP mode (always available)
|
||||
// Settings → STA mode enable (AP+STA dual mode)
|
||||
// ============================================================
|
||||
|
||||
#include <Arduino.h>
|
||||
@@ -33,6 +36,7 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <SoftWire.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
@@ -44,78 +48,119 @@
|
||||
#include "serial_task.h"
|
||||
#include "sdcard_task.h"
|
||||
#include "web_task.h"
|
||||
#include "rtc_task.h"
|
||||
|
||||
// --- WiFi STA state (controlled from web UI) ---
|
||||
volatile bool staEnabled = false;
|
||||
volatile bool staConnected = false;
|
||||
char staSSID[64] = "";
|
||||
char staPW[64] = "";
|
||||
|
||||
// ============================================================
|
||||
// NTP Time Sync Task
|
||||
// Only works in STA mode (internet required)
|
||||
// In AP mode, time is synced from browser via WebSocket
|
||||
// Enable STA mode (AP+STA dual) - called from web_task
|
||||
// ============================================================
|
||||
void ntpSyncTask(void *param) {
|
||||
Serial.println("[Task] NTP Sync started");
|
||||
bool wifiEnableSTA(const char *ssid, const char *password) {
|
||||
if (!ssid || strlen(ssid) == 0) return false;
|
||||
|
||||
// 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));
|
||||
}
|
||||
strncpy(staSSID, ssid, sizeof(staSSID) - 1);
|
||||
strncpy(staPW, password, sizeof(staPW) - 1);
|
||||
|
||||
Serial.printf("[WiFi] Enabling STA: SSID='%s'\n", staSSID);
|
||||
|
||||
// Switch to AP+STA dual mode
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
WiFi.softAP(WIFI_AP_SSID, WIFI_AP_PASSWORD);
|
||||
WiFi.begin(staSSID, staPW);
|
||||
WiFi.setSleep(false);
|
||||
|
||||
staEnabled = true;
|
||||
|
||||
// Wait for connection (non-blocking, with timeout)
|
||||
unsigned long start = millis();
|
||||
while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// STA mode - try NTP
|
||||
configTime(NTP_GMT_OFFSET, NTP_DAYLIGHT_OFFSET, NTP_SERVER);
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
staConnected = true;
|
||||
Serial.printf("[WiFi] STA connected! IP: %s (RSSI: %d)\n",
|
||||
WiFi.localIP().toString().c_str(), WiFi.RSSI());
|
||||
Serial.printf("[WiFi] AP still active: %s (%s)\n",
|
||||
WIFI_AP_SSID, WiFi.softAPIP().toString().c_str());
|
||||
|
||||
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));
|
||||
// STA 연결 성공 → NTP 시도
|
||||
configTime(NTP_GMT_OFFSET, NTP_DAYLIGHT_OFFSET, NTP_SERVER);
|
||||
Serial.println("[NTP] Time re-synced");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
staConnected = false;
|
||||
Serial.println("[WiFi] STA connection failed (will keep retrying)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// WiFi Connection (STA + fallback AP mode)
|
||||
// Disable STA mode - return to AP only
|
||||
// ============================================================
|
||||
void wifiConnect() {
|
||||
Serial.println("[WiFi] Connecting to: " + String(WIFI_SSID));
|
||||
void wifiDisableSTA() {
|
||||
Serial.println("[WiFi] Disabling STA, AP-only mode");
|
||||
WiFi.disconnect(true);
|
||||
delay(100);
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAP(WIFI_AP_SSID, WIFI_AP_PASSWORD);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
WiFi.setSleep(false);
|
||||
staEnabled = false;
|
||||
staConnected = false;
|
||||
staSSID[0] = '\0';
|
||||
staPW[0] = '\0';
|
||||
|
||||
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.printf("[WiFi] AP mode: %s (%s)\n",
|
||||
WIFI_AP_SSID, WiFi.softAPIP().toString().c_str());
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// NTP + STA Monitor Task
|
||||
// Periodically checks STA status, retries connection, syncs NTP
|
||||
// ============================================================
|
||||
void ntpSyncTask(void *param) {
|
||||
Serial.println("[Task] NTP/WiFi monitor started");
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
|
||||
while (true) {
|
||||
// If STA is enabled, monitor connection
|
||||
if (staEnabled) {
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (!staConnected) {
|
||||
staConnected = true;
|
||||
Serial.printf("[WiFi] STA reconnected: %s\n",
|
||||
WiFi.localIP().toString().c_str());
|
||||
}
|
||||
|
||||
// Try NTP sync
|
||||
struct tm timeinfo;
|
||||
configTime(NTP_GMT_OFFSET, NTP_DAYLIGHT_OFFSET, NTP_SERVER);
|
||||
if (getLocalTime(&timeinfo, 3000)) {
|
||||
rtcSyncFromSystem();
|
||||
static uint32_t ntpCount = 0;
|
||||
if (++ntpCount % 60 == 1) { // Log every ~60 cycles
|
||||
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 {
|
||||
staConnected = false;
|
||||
// Auto-retry connection
|
||||
if (strlen(staSSID) > 0) {
|
||||
WiFi.begin(staSSID, staPW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.println("[WiFi] Connected! IP: " + WiFi.localIP().toString());
|
||||
Serial.println("[WiFi] RSSI: " + String(WiFi.RSSI()) + " dBm");
|
||||
vTaskDelay(pdMS_TO_TICKS(60000)); // Check every 60s
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -126,65 +171,85 @@ void setup() {
|
||||
delay(1000);
|
||||
|
||||
Serial.println("============================================");
|
||||
Serial.println(" ESP32 Serial Logger v1.0");
|
||||
Serial.println(" ESP-WROOM-32D DevKitC V4");
|
||||
Serial.println(" ESP32 Serial Logger v2.1");
|
||||
Serial.println(" ESP-WROOM-32D DevKitC V4 + DS3231");
|
||||
Serial.println("============================================");
|
||||
Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap());
|
||||
Serial.printf(" CPU Freq: %d MHz\n", getCpuFrequencyMhz());
|
||||
Serial.println("============================================");
|
||||
Serial.println("============================================\n");
|
||||
|
||||
// 1. WiFi
|
||||
wifiConnect();
|
||||
// 1. DS3231 RTC
|
||||
Serial.println("--- Step 1: RTC ---");
|
||||
bool hasRTC = rtcInit();
|
||||
|
||||
// 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
|
||||
// 2. WiFi - Always start AP mode (immediate access)
|
||||
Serial.println("\n--- Step 2: WiFi (AP mode) ---");
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAP(WIFI_AP_SSID, WIFI_AP_PASSWORD);
|
||||
Serial.printf("[WiFi] AP SSID: %s\n", WIFI_AP_SSID);
|
||||
Serial.printf("[WiFi] AP IP: %s\n", WiFi.softAPIP().toString().c_str());
|
||||
Serial.println("[WiFi] STA: disabled (enable via Settings page)");
|
||||
|
||||
// 3. Time status
|
||||
Serial.println("\n--- Step 3: Time ---");
|
||||
if (hasRTC && rtcStatus.timeSynced) {
|
||||
Serial.println("[Time] Using RTC time");
|
||||
} else {
|
||||
Serial.println("[Time] AP mode: time will sync from browser on first connect");
|
||||
Serial.println("[Time] Waiting for browser sync");
|
||||
}
|
||||
|
||||
// 3. SD Card
|
||||
// 4. SD Card
|
||||
Serial.println("\n--- Step 4: SD Card ---");
|
||||
sdTaskInit();
|
||||
|
||||
// 4. Serial2 UART
|
||||
// 5. Serial2 UART
|
||||
Serial.println("\n--- Step 5: Serial2 ---");
|
||||
serialTaskInit();
|
||||
|
||||
// 5. Web Server + WebSocket
|
||||
// 6. Web Server + WebSocket
|
||||
Serial.println("\n--- Step 6: Web Server ---");
|
||||
webTaskInit();
|
||||
|
||||
Serial.println("============================================");
|
||||
Serial.println(" All tasks started!");
|
||||
Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap());
|
||||
// 7. RTC periodic sync task
|
||||
rtcTaskInit();
|
||||
|
||||
String ip = (WiFi.getMode() == WIFI_AP) ?
|
||||
WiFi.softAPIP().toString() : WiFi.localIP().toString();
|
||||
Serial.println(" URL: http://" + ip);
|
||||
// 8. NTP + WiFi monitor task (always running)
|
||||
xTaskCreatePinnedToCore(ntpSyncTask, "NTP", TASK_STACK_NTP,
|
||||
NULL, TASK_PRIORITY_NTP, NULL, 0);
|
||||
|
||||
// Status summary
|
||||
Serial.println("\n============================================");
|
||||
Serial.println(" All systems initialized!");
|
||||
Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap());
|
||||
Serial.printf(" AP URL: http://%s\n", WiFi.softAPIP().toString().c_str());
|
||||
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(" Core 0: SDLog(3), WebBC(2), RTC(1), NTP(1)");
|
||||
Serial.println(" Loop : server.handleClient()");
|
||||
Serial.println(" Time : NTP(STA) or Browser sync(AP)");
|
||||
Serial.printf(" RTC: %s | Time: %s\n",
|
||||
rtcStatus.available ? "OK" : "NO",
|
||||
rtcStatus.timeSynced ? "Valid" : "Pending");
|
||||
Serial.println("============================================\n");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Loop - handles HTTP requests (must be on main loop)
|
||||
// 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",
|
||||
char timeBuf[24];
|
||||
getTimestamp(timeBuf, sizeof(timeBuf));
|
||||
Serial.printf("[SYS] %s | Heap:%d | SD:%s | WS:%d | RTC:%s | STA:%s\n",
|
||||
timeBuf,
|
||||
ESP.getFreeHeap(),
|
||||
ESP.getMinFreeHeap(),
|
||||
sdCardPresent() ? "OK" : "FAIL",
|
||||
webSocket.connectedClients());
|
||||
webSocket.connectedClients(),
|
||||
rtcStatus.available ? "OK" : "NO",
|
||||
staConnected ? "ON" : "OFF");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user