10#include "freertos/FreeRTOS.h"
11#include "freertos/task.h"
22 memset(
this, 0,
sizeof(*
this));
32 static WifiHandlers s_instance;
41bool WifiHandlers::isValidIpOctet(
int val) {
42 return val >= 0 && val <= 255;
51 if (!ip || !ip[0])
return false;
53 if (sscanf(ip,
"%d.%d.%d.%d", &a, &b, &c, &d) != 4)
return false;
54 return isValidIpOctet(a) && isValidIpOctet(b) && isValidIpOctet(c) && isValidIpOctet(d);
62uint32_t WifiHandlers::parseIpAddress(
const char* ip)
const {
64 if (sscanf(ip,
"%d.%d.%d.%d", &a, &b, &c, &d) != 4)
return 0;
65 if (!isValidIpOctet(a) || !isValidIpOctet(b) || !isValidIpOctet(c) || !isValidIpOctet(d))
return 0;
66 return (
static_cast<uint32_t
>(a) << 24) | (
static_cast<uint32_t
>(b) << 16) |
67 (
static_cast<uint32_t
>(c) << 8) |
static_cast<uint32_t
>(d);
75 if (nvs_open(
"wifi", NVS_READONLY, &nvs) != ESP_OK) {
79 nvs_get_u32(nvs,
"tout", &ms);
94 if (nvs_open(
"wifi", NVS_READWRITE, &nvs) != ESP_OK)
return false;
95 esp_err_t err = nvs_set_u32(nvs,
"tout", ms);
96 if (err == ESP_OK) nvs_commit(nvs);
107 strncpy(wizard_.ssid, ssid,
sizeof(wizard_.ssid) - 1);
110 strncpy(wizard_.password, password,
sizeof(wizard_.password) - 1);
113 wizard_.useDhcp =
true;
122 if (nvs_open(
"wifi", NVS_READWRITE, &nvs) == ESP_OK) {
128 config_.valid =
false;
129 userEnabled_ =
false;
138 if (nvs_open(
"wifi", NVS_READONLY, &nvs) != ESP_OK) {
139 config_.valid =
false;
140 userEnabled_ =
false;
145 nvs_get_u8(nvs,
"ena", &ena);
146 userEnabled_ = (ena != 0);
148 size_t len =
sizeof(config_.ssid);
149 if (nvs_get_str(nvs,
"ssid", config_.ssid, &len) != ESP_OK || len <= 1) {
151 config_.valid =
false;
155 len =
sizeof(config_.password);
156 nvs_get_str(nvs,
"pass", config_.password, &len);
157 nvs_get_u8(nvs,
"sec", &config_.security);
160 nvs_get_u8(nvs,
"dhcp", &dhcp);
161 config_.useDhcp = (dhcp != 0);
163 nvs_get_u32(nvs,
"ip", &config_.staticIp);
164 nvs_get_u32(nvs,
"gw", &config_.gateway);
165 nvs_get_u32(nvs,
"nm", &config_.netmask);
168 config_.valid =
true;
177 if (nvs_open(
"wifi", NVS_READWRITE, &nvs) != ESP_OK)
return;
179 nvs_set_str(nvs,
"ssid", wizard_.ssid);
180 nvs_set_str(nvs,
"pass", wizard_.password);
181 nvs_set_u8(nvs,
"sec",
static_cast<uint8_t
>(wizard_.security));
182 nvs_set_u8(nvs,
"dhcp", wizard_.useDhcp ? 1 : 0);
185 if (!wizard_.useDhcp) {
186 nvs_set_u32(nvs,
"ip", parseIpAddress(wizard_.staticIp));
187 nvs_set_u32(nvs,
"gw", parseIpAddress(wizard_.gateway));
188 nvs_set_u32(nvs,
"nm", parseIpAddress(wizard_.netmask));
204 return wifi && wifi->isConnected();
212 if (!config_.valid) {
213 lastError_ =
"No config";
219 lastError_ =
"No WiFi HW";
223 if (!wifi->isEnabled()) {
225 lastError_ =
"WiFi init failed";
231 std::snprintf(toastMsg,
sizeof(toastMsg),
"%s\n%s",
232 cdc::ui::tr(
"core.wifi_connecting"), config_.ssid);
240 if (!connected || !wifi->isConnected()) {
245 default: lastError_ =
"Timeout";
break;
250 lastError_ =
nullptr;
262 if (wifi->isConnected()) {
268 vTaskDelay(pdMS_TO_TICKS(200));
270 if (wifi->isEnabled()) {
289 lastError_ =
"No WiFi HW";
294 bool weConnected =
false;
297 if (!wifi->isConnected()) {
298 if (!config_.valid) {
299 lastError_ =
"No config";
304 if (!wifi->isEnabled()) {
310 if (!connected || !wifi->isConnected()) {
311 lastError_ =
"Connect failed";
319 static bool sntpInited =
false;
321 esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL);
322 esp_sntp_setservername(0,
"pool.ntp.org");
323 esp_sntp_setservername(1,
"time.google.com");
331 uint32_t startMs = esp_timer_get_time() / 1000;
335 if (esp_sntp_get_sync_status() == SNTP_SYNC_STATUS_COMPLETED) {
339 vTaskDelay(pdMS_TO_TICKS(100));
343 if (weConnected && disconnectAfter) {
353 lastError_ =
nullptr;
357 lastError_ =
"NTP timeout";
372 lastError_ =
"No WiFi HW";
376 auto syncTimeIfNeeded = [
this]() {
378 if (!rtc || !rtc->isTimeSet()) {
383 if (wifi->isConnected()) {
387 if (!config_.valid) {
390 if (!config_.valid) {
391 lastError_ =
"No WLAN configured";
404void WifiHandlers::persistUserEnabled(
bool enabled) {
406 if (nvs_open(
"wifi", NVS_READWRITE, &nvs) != ESP_OK)
return;
407 nvs_set_u8(nvs,
"ena", enabled ? 1 : 0);
415void WifiHandlers::maybeRelease() {
416 if (!userEnabled_ && holdCount_ <= 0) {
425 userEnabled_ = enabled;
426 persistUserEnabled(enabled);
431 if (!config_.valid) {
432 lastError_ =
"No WLAN configured";
448 if (holdCount_ > 0) --holdCount_;
456 if (holdCount_ > 0) --holdCount_;
465 if (userEnabled_ && config_.valid) {
Internationalization with English fallbacks in code and overlay translations loaded at runtime from a...
void render(bool synchronous=false)
Render current view (and modal if present) and flush to display.
static ViewStack & instance()
Returns singleton view-stack instance.
bool setUserEnabled(bool enabled)
Sets the user/system WiFi intent and applies it immediately.
bool connect()
Connects to Wi-Fi using saved configuration.
static bool isValidIpAddress(const char *ip)
Validates dotted IPv4 address string.
bool syncNtp(bool disconnectAfter=true)
Synchronizes system time via NTP.
void saveCredentials(const char *ssid, const char *password)
Stores credentials directly (WPA2-PSK, DHCP) and persists them.
bool ensureConnected()
Ensures the device is connected to WiFi and optionally syncs time, leaving the connection up for the ...
bool setConnectTimeoutMs(uint32_t ms)
Persists the connect timeout to NVS.
void release()
Releases a previously acquired WiFi hold.
void saveConfig()
Saves current wizard Wi-Fi configuration to NVS.
bool acquire()
Acquires a hold on the WiFi connection for a plugin/host caller.
void restoreOnBoot()
Restores the persisted WiFi intent at boot.
static WifiHandlers & instance()
Returns singleton Wi-Fi handlers instance.
uint32_t getConnectTimeoutMs() const
Reads the persisted connect timeout (NVS key "tout").
void loadConfig()
Loads Wi-Fi configuration from NVS.
void disconnect()
Disconnects and disables Wi-Fi if active.
void clearConfig()
Erases the entire "wifi" NVS namespace and invalidates the cached configuration.
bool isConnected() const
Returns whether Wi-Fi is currently connected.
IWifiController * getWifiControllerInstance()
Returns the singleton Wi-Fi controller service instance.
IRtc * getRtcInstance()
Returns the singleton RTC service instance.
Centralized key-code constants for cdc_views.
const char * tr(const char *key)
Look up a translation by string key.
static constexpr uint32_t WIFI_CONNECT_TIMEOUT_DEFAULT_MS
void showToastTask(const char *message, uint16_t durationMs=0)
Shows a task/progress toast message.
static constexpr uint32_t WIFI_CONNECT_TIMEOUT_MIN_MS
static constexpr uint32_t NTP_SYNC_TIMEOUT_MS
static constexpr uint32_t WIFI_CONNECT_TIMEOUT_MAX_MS
void reset()
Resets Wi-Fi wizard state to defaults.