Files
immich-frame/src/wifi_manager.cpp
cottongin 531906ca2c fix: call configTime() in minimal WiFi path to initialize DNS resolver
Without configTime(), the ESP32 DNS subsystem isn't properly
initialized after WiFi connect, causing HTTPS hostname resolution
to fail silently in the deep sleep wake path. The fix calls
configTime() fire-and-forget (non-blocking, <1ms) which initializes
DNS without the 5-second NTP wait.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-06 01:39:17 -04:00

139 lines
3.8 KiB
C++

#include "wifi_manager.h"
#include <WiFi.h>
#include <ESPmDNS.h>
#include <M5Unified.h>
#include <time.h>
#include <sys/time.h>
#include "config.h"
void WiFiManager::begin(SettingsManager& settings, bool minimal) {
_settings = &settings;
if (!_settings->isProvisioned()) {
Serial.println("[wifi] Not provisioned — starting AP");
startAP();
return;
}
startStation(minimal);
}
bool WiFiManager::isConnected() {
return WiFi.status() == WL_CONNECTED;
}
bool WiFiManager::isAPMode() {
return _apMode;
}
String WiFiManager::getIP() {
if (_apMode) {
return WiFi.softAPIP().toString();
}
return WiFi.localIP().toString();
}
int WiFiManager::getRSSI() {
if (_apMode) return 0;
return WiFi.RSSI();
}
void WiFiManager::startAP() {
WiFi.disconnect(true);
WiFi.mode(WIFI_AP);
WiFi.softAP("PaperColor-Setup");
_apMode = true;
Serial.printf("[wifi] AP started: PaperColor-Setup, IP: %s\n",
WiFi.softAPIP().toString().c_str());
}
void WiFiManager::startStation(bool minimal) {
Settings s = _settings->get();
WiFi.disconnect(true);
WiFi.mode(WIFI_STA);
_apMode = false;
Serial.printf("[wifi] Connecting to: %s%s\n", s.wifi_ssid.c_str(),
minimal ? " (minimal)" : "");
for (_retryCount = 0; _retryCount < WIFI_MAX_RETRIES; _retryCount++) {
if (attemptConnection(s.wifi_ssid, s.wifi_pass)) {
Serial.printf("[wifi] Connected! IP: %s, RSSI: %d\n",
WiFi.localIP().toString().c_str(), WiFi.RSSI());
if (minimal) {
// Deep sleep wake path: skip blocking NTP wait and mDNS to
// minimize active time. Still call configTime() to initialize
// the DNS resolver (required for HTTPS hostname resolution).
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
return;
}
WiFi.setSleep(WIFI_PS_MIN_MODEM);
syncNTP();
setupMDNS("papercolor");
return;
}
Serial.printf("[wifi] Attempt %d/%d failed\n", _retryCount + 1, WIFI_MAX_RETRIES);
}
Serial.println("[wifi] All attempts failed — falling back to AP mode");
startAP();
}
void WiFiManager::setupMDNS(const char* hostname) {
if (MDNS.begin(hostname)) {
MDNS.addService("http", "tcp", 80);
Serial.printf("[wifi] mDNS: %s.local\n", hostname);
} else {
Serial.println("[wifi] mDNS failed to start");
}
}
bool WiFiManager::attemptConnection(const String& ssid, const String& pass) {
WiFi.begin(ssid.c_str(), pass.c_str());
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - start > WIFI_CONNECT_TIMEOUT_MS) {
return false;
}
delay(100);
}
return true;
}
void WiFiManager::syncNTP() {
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
// Wait up to 5 seconds for NTP sync
unsigned long start = millis();
time_t now = 0;
while (now < 1600000000 && (millis() - start) < 5000) {
delay(100);
time(&now);
}
if (now < 1600000000) {
Serial.println("[wifi] NTP sync timed out");
return;
}
// Write synced time to hardware RTC
struct tm t;
gmtime_r(&now, &t);
m5::rtc_datetime_t dt;
dt.date.year = t.tm_year + 1900;
dt.date.month = t.tm_mon + 1;
dt.date.date = t.tm_mday;
dt.time.hours = t.tm_hour;
dt.time.minutes = t.tm_min;
dt.time.seconds = t.tm_sec;
M5.Rtc.setDateTime(dt);
Serial.printf("[wifi] NTP synced: %04d-%02d-%02d %02d:%02d:%02d UTC, written to RTC\n",
dt.date.year, dt.date.month, dt.date.date,
dt.time.hours, dt.time.minutes, dt.time.seconds);
}