From ab7a0d56d79ba8ae897d13b2c9309a6428b1c05c Mon Sep 17 00:00:00 2001 From: Mickyleitor Date: Wed, 6 Aug 2025 01:50:00 +0200 Subject: [PATCH 1/6] Wifi ssid --- Firmware_ESP8266/ESP8266_Utils.h | 188 ++++++++++++++++++++++ Firmware_ESP8266/Firmware_ESP8266.ino | 1 + Firmware_ESP8266/basic_defines.h | 3 + Firmware_ESP8266/lcd.h | 219 +++++++++++++++++++++++--- 4 files changed, 392 insertions(+), 19 deletions(-) diff --git a/Firmware_ESP8266/ESP8266_Utils.h b/Firmware_ESP8266/ESP8266_Utils.h index 1d74fd0..339edb9 100644 --- a/Firmware_ESP8266/ESP8266_Utils.h +++ b/Firmware_ESP8266/ESP8266_Utils.h @@ -9,6 +9,8 @@ #define HTTP_SERVER_PING_ADDRESS "1.1.1.1" #define HTTP_SERVER_PING_INTERVAL_MS (10000) +#define WIFI_CONNECTION_TIMEOUT_MS (10000) + #define TEMPERATURE_DEGREE_INVALID (65535) extern struct Settings settings; @@ -17,6 +19,34 @@ struct WeatherData { double TemperatureDegree = TEMPERATURE_DEGREE_INVALID; } MyWeather; +struct WifiNetworkInfo { + String ssid; + String bssid; + int channel; + String encryption; + float avgRssi; + int rssiSamples; + int notSeenCount = 0; + bool seenInThisScan = false; + + // Constructor por defecto necesario para vector::resize + WifiNetworkInfo() = default; + + WifiNetworkInfo(String ssid_, String bssid_, int channel_, String encryption_, int rssi_) + : ssid(ssid_), + bssid(bssid_), + channel(channel_), + encryption(encryption_), + avgRssi(rssi_), + rssiSamples(1), + notSeenCount(0), + seenInThisScan(true) {} +}; + +std::vector wifiNetworks; +static bool wifiScanInProgress = false; +static unsigned long lastConnectAttemptMs = 0; + bool ESP8266Utils_Connect_STA( const char* ssid, const char* password, @@ -141,3 +171,161 @@ bool ESP8266Utils_update_WeatherData(struct Settings* myData) { client.stop(); return true; } + +void ESP8266Utils_clearWifiNetworksList() { + wifiNetworks.clear(); + Serial.println("Lista de redes WiFi borrada completamente."); +} + +// Compara por RSSI promedio, descendente +bool compareByRssiDesc(const WifiNetworkInfo& a, const WifiNetworkInfo& b) { + return a.avgRssi > b.avgRssi; +} + +// Elimina redes no vistas en los últimos 5 escaneos +void cleanNetworksNotSeen() { + for (auto it = wifiNetworks.begin(); it != wifiNetworks.end();) { + if (!it->seenInThisScan) { + it->notSeenCount++; + } else { + it->notSeenCount = 0; + } + + if (it->notSeenCount >= 5) { + it = wifiNetworks.erase(it); + } else { + ++it; + } + } +} + +// Inserta o actualiza una red escaneada +void updateOrInsertNetwork( + const String& ssid, + const String& bssid, + int channel, + const String& encryption, + int rssi) { + for (auto& net : wifiNetworks) { + if (net.bssid == bssid) { + net.avgRssi = (net.avgRssi * net.rssiSamples + rssi) / (net.rssiSamples + 1); + net.rssiSamples++; + net.seenInThisScan = true; + net.notSeenCount = 0; + return; + } + } + + // Filtro para evitar agregar redes volátiles de 1 sola muestra + if (rssi < -80) { + // Si la red es débil y no estaba antes, ignorarla + return; + } + + wifiNetworks.emplace_back(ssid, bssid, channel, encryption, rssi); +} + +// Inicia el escaneo WiFi si no está en curso +void ESP8266Utils_startWifiScanIfNeeded(void) { + if (!wifiScanInProgress) { + if (WiFi.status() == WL_CONNECTED) { + WiFi.disconnect(); + } + WiFi.mode(WIFI_STA); + WiFi.scanNetworks(true); // Async scan + wifiScanInProgress = true; + Serial.println("Started async WiFi scan..."); + } +} + +// Verifica si ya terminó el escaneo y actualiza la lista +void ESP8266Utils_checkScanResults() { + if (wifiScanInProgress) { + int n = WiFi.scanComplete(); + if (n == WIFI_SCAN_RUNNING) { + return; + } else if (n < 0) { + Serial.println("Scan failed"); + wifiScanInProgress = false; + return; + } + + wifiScanInProgress = false; + + // Marcar todas como no vistas inicialmente + for (auto& net : wifiNetworks) { + net.seenInThisScan = false; + } + + for (int i = 0; i < n; ++i) { + String ssid = WiFi.SSID(i); + int32_t rssi = WiFi.RSSI(i); + String bssid = WiFi.BSSIDstr(i); + uint8_t channel = WiFi.channel(i); + String encryptionType = WiFi.encryptionType(i) == ENC_TYPE_NONE ? "None" : "Encrypted"; + + updateOrInsertNetwork(ssid, bssid, channel, encryptionType, rssi); + } + + cleanNetworksNotSeen(); + + std::sort(wifiNetworks.begin(), wifiNetworks.end(), compareByRssiDesc); + + if (wifiNetworks.size() > 10) { + wifiNetworks.resize(10); + } + + Serial.println("Lista de redes ordenada por RSSI promedio:"); + for (size_t i = 0; i < wifiNetworks.size(); ++i) { + const auto& net = wifiNetworks[i]; + Serial.printf( + "%d: %s (%0.1f dBm avg, %d muestras) [%s] Canal: %d, Encriptación: %s\n", + int(i + 1), + net.ssid.c_str(), + net.avgRssi, + net.rssiSamples, + net.bssid.c_str(), + net.channel, + net.encryption.c_str()); + } + + WiFi.reconnect(); + } +} + +bool ESP8266Utils_getSsidAtIndex(int index, String& outSsid) { + if (index < 0 || index >= static_cast(wifiNetworks.size())) { + return false; + } + outSsid = wifiNetworks[index].ssid; + return true; +} + +int ESP8266Utils_getTrackedNetworkCount() { return static_cast(wifiNetworks.size()); } + +int ESP8266Utils_getIndexBySsid(const String& targetSsid) { + for (size_t i = 0; i < wifiNetworks.size(); ++i) { + if (wifiNetworks[i].ssid == targetSsid) { + return static_cast(i); + } + } + return -1; // No encontrado +} + +void ESP8266Utils_connectToWifi(const String& ssid, const String& password) { + WiFi.mode(WIFI_STA); + WiFi.begin(ssid.c_str(), password.c_str()); + lastConnectAttemptMs = millis(); +} + +bool ESP8266Utils_isWifiConnected() { return WiFi.status() == WL_CONNECTED; } + +int ESP8266Utils_getWifiConnectionPercentage() { + if (lastConnectAttemptMs == 0) { + return 0; + } + unsigned long elapsed = millis() - lastConnectAttemptMs; + return (elapsed * 100) / WIFI_CONNECTION_TIMEOUT_MS; +} + +void Wifi_handler() {} diff --git a/Firmware_ESP8266/Firmware_ESP8266.ino b/Firmware_ESP8266/Firmware_ESP8266.ino index 582579e..5fd1e8e 100644 --- a/Firmware_ESP8266/Firmware_ESP8266.ino +++ b/Firmware_ESP8266/Firmware_ESP8266.ino @@ -85,4 +85,5 @@ void loop() { buzzer_handler(); shutterHandler(); EEPROM_Handler(); + Wifi_handler(); } diff --git a/Firmware_ESP8266/basic_defines.h b/Firmware_ESP8266/basic_defines.h index 729d0f6..d4b3f46 100644 --- a/Firmware_ESP8266/basic_defines.h +++ b/Firmware_ESP8266/basic_defines.h @@ -53,7 +53,10 @@ enum seleccionMenu { SELECCION_MENU_CONFIG_DEBUG, SELECCION_MENU_CONFIG_DEBUG_SOFT_RST_COUNT, SELECCION_MENU_CONFIG_WIFI, + SELECCION_MENU_CONFIG_WIFI_HABILITAR, + SELECCION_MENU_CONFIG_WIFI_SSID, SELECCION_MENU_CONFIG_WIFI_PASSWORD, + SELECCION_MENU_CONFIG_WIFI_RESULTADO, SELECCION_MENU_MAX }; diff --git a/Firmware_ESP8266/lcd.h b/Firmware_ESP8266/lcd.h index 3e4c6f1..8f5caa8 100644 --- a/Firmware_ESP8266/lcd.h +++ b/Firmware_ESP8266/lcd.h @@ -19,6 +19,7 @@ static uint32_t previousBuzzerVolume = 0; static unsigned long currentAdjustedLevelIndex = 0; static bool previousBuzzerEnabled = false; static bool buttonIsReleased = false; +static String adjustedSSID = ""; static String adjustedPassword = ""; static unsigned long buttonHoldingTimeMs = 0; @@ -28,7 +29,11 @@ static unsigned long buttonHoldingTimeMs = 0; #define LCD_SPECIAL_CHAR_DOWN_ARROW (char)(LCD_SPECIAL_CHAR_BASE + 2) #define LCD_SPECIAL_CHAR_RIGHT_ARROW (char)(LCD_SPECIAL_CHAR_BASE + 3) #define LCD_SPECIAL_CHAR_STOP_ARROW (char)(LCD_SPECIAL_CHAR_BASE + 4) -#define LCD_SPECIAL_CHAR_UP_ARROW_CAN (char)(LCD_SPECIAL_CHAR_BASE + 5) +#define LCD_SPECIAL_CHAR_CONNECTED_SYMBOL (char)(LCD_SPECIAL_CHAR_BASE + 5) +#define LCD_SPECIAL_CHAR_WARNING_SYMBOL (char)(LCD_SPECIAL_CHAR_BASE + 6) +// Keep this in sync with the number of custom characters defined above. +// Maximum is 8, but we use only 7. +#define LCD_SPECIAL_CHAR_TOTAL_CHARS (7) #define LCD_SLIDE_OR_FLASH_SPEED_MS (500) #define LCD_HOLDING_TIME_CONFIRM_MS (2000) @@ -44,13 +49,15 @@ void _sendLcdBuffer(String line1, String line2) { _lcd.clear(); for (int i = 0; i < 16; i++) { _lcd.setCursor(i, 0); - if ((line1[i] >= LCD_SPECIAL_CHAR_BASE) && (line1[i] < LCD_SPECIAL_CHAR_BASE + 6)) { + if ((line1[i] >= LCD_SPECIAL_CHAR_BASE) + && (line1[i] < LCD_SPECIAL_CHAR_BASE + LCD_SPECIAL_CHAR_TOTAL_CHARS)) { _lcd.write(line1[i] - LCD_SPECIAL_CHAR_BASE); } else { _lcd.print(line1[i]); } _lcd.setCursor(i, 1); - if ((line2[i] >= LCD_SPECIAL_CHAR_BASE) && (line2[i] < LCD_SPECIAL_CHAR_BASE + 6)) { + if ((line2[i] >= LCD_SPECIAL_CHAR_BASE) + && (line2[i] < LCD_SPECIAL_CHAR_BASE + LCD_SPECIAL_CHAR_TOTAL_CHARS)) { _lcd.write(line2[i] - LCD_SPECIAL_CHAR_BASE); } else { _lcd.print(line2[i]); @@ -90,20 +97,23 @@ bool pantalla_iniciar(int32_t timeout_ms) { } _lcd.begin(16, 2); - uint8_t customArrayChar[6][8] = { - /* Flecha izquierda */ { 0x00, 0x07, 0x0E, 0x1C, 0x1C, 0x0E, 0x07, 0x00 }, - /* Flecha arriba */ + uint8_t customArrayChar[LCD_SPECIAL_CHAR_TOTAL_CHARS][8] = { + // LCD_SPECIAL_CHAR_LEFT_ARROW + { 0x00, 0x07, 0x0E, 0x1C, 0x1C, 0x0E, 0x07, 0x00 }, + // LCD_SPECIAL_CHAR_UP_ARROW { 0x00, 0x04, 0x0E, 0x1F, 0x1B, 0x11, 0x00, 0x00 }, - /* Flecha abajo */ + // LCD_SPECIAL_CHAR_DOWN_ARROW { 0x00, 0x00, 0x11, 0x1B, 0x1F, 0x0E, 0x04, 0x00 }, - /* Flecha derecha */ + // LCD_SPECIAL_CHAR_RIGHT_ARROW { 0x00, 0x1C, 0x0E, 0x07, 0x07, 0x0E, 0x1C, 0x00 }, - /* Flecha STOP */ + // LCD_SPECIAL_CHAR_STOP_ARROW { 0x00, 0x0E, 0x1B, 0x11, 0x11, 0x1B, 0x0E, 0x00 }, - /* Flecha arribacan */ - { 0x04, 0x0E, 0x1F, 0x15, 0x04, 0x04, 0x07, 0x00 } + // LCD_SPECIAL_CHAR_CONNECTED_SYMBOL + { 0x04, 0x0E, 0x1B, 0x1B, 0x0E, 0x04, 0x04, 0x00 }, + // LCD_SPECIAL_CHAR_WARNING_SYMBOL + { 0x0E, 0x11, 0x15, 0x15, 0x11, 0x15, 0x11, 0x0E } }; - for (int i = 0; i < 6; i++) { + for (int i = 0; i < LCD_SPECIAL_CHAR_TOTAL_CHARS; i++) { _lcd.createChar(i, customArrayChar[i]); } return true; @@ -359,36 +369,81 @@ void pantalla_handleButtonInMenu( case BUTTON_STATUS_UP: newMenu = SELECCION_MENU_CONFIG_DEBUG; break; + case BUTTON_STATUS_RIGHT: + ESP8266Utils_clearWifiNetworksList(); + newMenu = SELECCION_MENU_CONFIG_WIFI_SSID; + break; + case BUTTON_STATUS_DOWN: + case BUTTON_STATUS_LEFT: + buzzer_sound_error(); + break; + } + break; + case SELECCION_MENU_CONFIG_WIFI_SSID: { + // In this menu, an async wifi scan is performed. And we start to do RSSI avg on each + // SSID. We display the SSID in a list sorted by RSSI, first the strongest. + // Do as much as possible RSSI avg, so we can display the list ASAP, since it's cleared + // each time we enter this menu. + ESP8266Utils_startWifiScanIfNeeded(); + ESP8266Utils_checkScanResults(); + static int previousCurrentIndex = 1; + int countNetworks = ESP8266Utils_getTrackedNetworkCount(); + int currentIndex = ESP8266Utils_getIndexBySsid(adjustedSSID); + if ((currentIndex < 0) && (countNetworks > 0) && (previousCurrentIndex > 0)) { + currentIndex = previousCurrentIndex - 1; + } else if (currentIndex < 0) { + currentIndex = 0; + } + previousCurrentIndex = currentIndex; + + ESP8266Utils_getSsidAtIndex(currentIndex, adjustedSSID); + + switch (currentButtonPressed) { + case BUTTON_STATUS_UP: + if (currentIndex > 0) { + currentIndex--; + } + ESP8266Utils_getSsidAtIndex(currentIndex, adjustedSSID); + break; case BUTTON_STATUS_RIGHT: adjustedPassword = ""; newMenu = SELECCION_MENU_CONFIG_WIFI_PASSWORD; break; case BUTTON_STATUS_DOWN: + if (currentIndex < (countNetworks - 1)) { + currentIndex++; + } + ESP8266Utils_getSsidAtIndex(currentIndex, adjustedSSID); + break; case BUTTON_STATUS_LEFT: - buzzer_sound_error(); + newMenu = SELECCION_MENU_CONFIG_WIFI; break; } break; - case SELECCION_MENU_CONFIG_WIFI_PASSWORD: + } + case SELECCION_MENU_CONFIG_WIFI_PASSWORD: { static uint8_t previousButtonHolding = BUTTON_STATUS_NONE; + unsigned long now = millis(); + if ((previousButtonHolding != currentButtonHolding) && (currentButtonHolding != BUTTON_STATUS_NONE)) { - buttonHoldingTimeMs = millis(); + buttonHoldingTimeMs = now; previousButtonHolding = currentButtonHolding; } else if ( (previousButtonHolding != currentButtonHolding) && (currentButtonHolding == BUTTON_STATUS_NONE)) { - if ((millis() - buttonHoldingTimeMs) >= LCD_HOLDING_TIME_CONFIRM_MS) { + if ((now - buttonHoldingTimeMs) >= LCD_HOLDING_TIME_CONFIRM_MS) { if (previousButtonHolding == BUTTON_STATUS_DOWN) { buzzer_sound_accept(); - newMenu = SELECCION_MENU_CONFIG_WIFI; + newMenu = SELECCION_MENU_CONFIG_WIFI_RESULTADO; + ESP8266Utils_connectToWifi(adjustedSSID, adjustedPassword); } } else { switch (previousButtonHolding) { case BUTTON_STATUS_LEFT: if (adjustedPassword.length() == 0) { - newMenu = SELECCION_MENU_CONFIG_WIFI; + newMenu = SELECCION_MENU_CONFIG_WIFI_SSID; } else { adjustedPassword.remove(adjustedPassword.length() - 1); } @@ -404,13 +459,49 @@ void pantalla_handleButtonInMenu( } break; case BUTTON_STATUS_RIGHT: - adjustedPassword += 'a'; + adjustedPassword += 'A'; break; } } previousButtonHolding = currentButtonHolding; } break; + } + case SELECCION_MENU_CONFIG_WIFI_RESULTADO: { + static bool wifiCredentialStored = false; + if (ESP8266Utils_isWifiConnected()) { + if (!wifiCredentialStored) { + wifiCredentialStored = true; + memcpy(settings.wifiSettings.ssid_sta, + adjustedSSID.c_str(), + sizeof(settings.wifiSettings.ssid_sta)); + memcpy(settings.wifiSettings.password_sta, + adjustedPassword.c_str(), + sizeof(settings.wifiSettings.password_sta)); + EEPROM_Schedule_Write(100); + } + } else { + wifiCredentialStored = false; + } + switch (currentButtonPressed) { + case BUTTON_STATUS_RIGHT: + if (ESP8266Utils_isWifiConnected()) { + buzzer_sound_accept(); + newMenu = SELECCION_MENU_CONFIG_WIFI; + } else { + buzzer_sound_error(); + } + break; + case BUTTON_STATUS_LEFT: + newMenu = SELECCION_MENU_CONFIG_WIFI_PASSWORD; + break; + case BUTTON_STATUS_DOWN: + case BUTTON_STATUS_UP: + buzzer_sound_error(); + break; + } + break; + } } *currentMenu = newMenu; } @@ -712,6 +803,90 @@ void pantalla_actualizarMenuConfigWifiPassword(String* lcdBuffer) { } } +void pantalla_actualizarMenuConfigWifiSsid(String* lcdBuffer) { + *lcdBuffer += String("SSID:"); + + String mySSID = adjustedSSID; + int adjustedSSIDindex = ESP8266Utils_getIndexBySsid(adjustedSSID); + if (adjustedSSIDindex < 0) { + mySSID = "No hay redes"; + } + + static unsigned long lastScrollTime = 0; + static unsigned int scrollOffset = 0; + + // Espacio visible para SSID + const int visibleChars = 11; + + // Añadir separación al final para el efecto loop + String scrollingSSID = mySSID + " "; // espacio entre loops + + // Actualizar desplazamiento cada 200ms + if (millis() - lastScrollTime >= LCD_SLIDE_OR_FLASH_SPEED_MS) { + lastScrollTime = millis(); + scrollOffset++; + if (scrollOffset >= scrollingSSID.length()) { + scrollOffset = 0; + } + } + + // Construir ventana deslizante + String scrolled; + for (int i = 0; i < visibleChars; ++i) { + int charIndex = (scrollOffset + i) % scrollingSSID.length(); + scrolled += scrollingSSID.charAt(charIndex); + } + + *lcdBuffer += scrolled; + + // Asegurar longitud mínima de 16 + while (lcdBuffer->length() < 16) { + *lcdBuffer += " "; + } + + // Agregar navegación + *lcdBuffer += String("< "); + *lcdBuffer += LCD_SPECIAL_CHAR_UP_ARROW; + adjustedSSIDindex++; + if (adjustedSSIDindex == 0) { + *lcdBuffer += String(" "); + } else if (adjustedSSIDindex < 10) { + *lcdBuffer += String("0"); + *lcdBuffer += String(adjustedSSIDindex); + } else { + *lcdBuffer += String(adjustedSSIDindex); + } + *lcdBuffer += LCD_SPECIAL_CHAR_DOWN_ARROW; + *lcdBuffer += String(" >"); +} + +void pantalla_actualizarMenuConfigWifiResultado(String* lcdBuffer) { + int porcentaje = ESP8266Utils_getWifiConnectionPercentage(); + if (porcentaje > 100) { + porcentaje = 100; // Limit to 100% + } + if (ESP8266Utils_isWifiConnected()) { + *lcdBuffer += String("WIFI: CONECTADO "); + *lcdBuffer += String("< OK>"); + } else { + int porcentaje = ESP8266Utils_getWifiConnectionPercentage(); + if (porcentaje == 100) { + *lcdBuffer += String("WIFI: FALLIDO "); + } else { + *lcdBuffer += String("WIFI: ESPERE "); + } + *lcdBuffer += String("< ["); + for (int i = 0; i < 10; i++) { + if (i < (porcentaje / 10)) { + *lcdBuffer += String("="); + } else { + *lcdBuffer += String(" "); + } + } + *lcdBuffer += String("] "); + } +} + void pantalla_actualizarMenu(uint8_t selectedMenu) { String lcdBuffer = ""; switch (selectedMenu) { @@ -754,9 +929,15 @@ void pantalla_actualizarMenu(uint8_t selectedMenu) { case SELECCION_MENU_CONFIG_WIFI: pantalla_actualizarMenuConfigWifi(&lcdBuffer); break; + case SELECCION_MENU_CONFIG_WIFI_SSID: + pantalla_actualizarMenuConfigWifiSsid(&lcdBuffer); + break; case SELECCION_MENU_CONFIG_WIFI_PASSWORD: pantalla_actualizarMenuConfigWifiPassword(&lcdBuffer); break; + case SELECCION_MENU_CONFIG_WIFI_RESULTADO: + pantalla_actualizarMenuConfigWifiResultado(&lcdBuffer); + break; } pantalla_sendLcdBuffer(lcdBuffer); } From 3fecfcb51764be2f20be9a54caa10717051d3028 Mon Sep 17 00:00:00 2001 From: Mickyleitor Date: Wed, 6 Aug 2025 02:01:23 +0200 Subject: [PATCH 2/6] Safer eeprom scheduled writes --- Firmware_ESP8266/EEPROM_Utils.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Firmware_ESP8266/EEPROM_Utils.h b/Firmware_ESP8266/EEPROM_Utils.h index 0640604..2bc08d8 100644 --- a/Firmware_ESP8266/EEPROM_Utils.h +++ b/Firmware_ESP8266/EEPROM_Utils.h @@ -5,8 +5,9 @@ #include "basic_defines.h" -static uint32_t EEPROM_Scheduled_Write_Delay = 0; -static bool EEPROM_Scheduled_Write_Enabled = false; +static unsigned long EEPROM_Scheduled_Write_At = 0; +static unsigned long EEPROM_Scheduled_Write_Delay = 0; +static bool EEPROM_Scheduled_Write_Enabled = false; struct WifiSettings { char ssid_sta[64]; @@ -53,7 +54,8 @@ uint16_t CRC16(const uint8_t* data, uint16_t size) { } void EEPROM_Schedule_Write(unsigned long delayMs) { - EEPROM_Scheduled_Write_Delay = delayMs + millis(); + EEPROM_Scheduled_Write_At = millis(); + EEPROM_Scheduled_Write_Delay = delayMs; EEPROM_Scheduled_Write_Enabled = true; } @@ -85,15 +87,12 @@ void EEPROM_Write(Settings* data) { } void EEPROM_Handler() { - if (!EEPROM_Scheduled_Write_Enabled) { - return; - } - if (millis() < EEPROM_Scheduled_Write_Delay) { - return; + if (EEPROM_Scheduled_Write_Enabled) { + if ((millis() - EEPROM_Scheduled_Write_At) >= EEPROM_Scheduled_Write_Delay) { + EEPROM_Scheduled_Write_Enabled = false; + EEPROM_Write(&settings); + } } - EEPROM_Scheduled_Write_Enabled = false; - - EEPROM_Write(&settings); } bool EEPROM_Read(Settings* out) { From 9b85ddc0793befe172d0ab0cde206d81ad0bf1c8 Mon Sep 17 00:00:00 2001 From: Mickyleitor Date: Wed, 6 Aug 2025 22:59:05 +0200 Subject: [PATCH 3/6] Some fixes given by copilot --- Firmware_ESP8266/ESP8266_Utils.h | 2 -- Firmware_ESP8266/lcd.h | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Firmware_ESP8266/ESP8266_Utils.h b/Firmware_ESP8266/ESP8266_Utils.h index 339edb9..7a6438f 100644 --- a/Firmware_ESP8266/ESP8266_Utils.h +++ b/Firmware_ESP8266/ESP8266_Utils.h @@ -288,8 +288,6 @@ void ESP8266Utils_checkScanResults() { net.channel, net.encryption.c_str()); } - - WiFi.reconnect(); } } diff --git a/Firmware_ESP8266/lcd.h b/Firmware_ESP8266/lcd.h index 8f5caa8..04b3b78 100644 --- a/Firmware_ESP8266/lcd.h +++ b/Firmware_ESP8266/lcd.h @@ -386,7 +386,8 @@ void pantalla_handleButtonInMenu( // each time we enter this menu. ESP8266Utils_startWifiScanIfNeeded(); ESP8266Utils_checkScanResults(); - static int previousCurrentIndex = 1; + static int previousCurrentIndex = 1; // Start at 1 so in the first iteration we can + // select the first network. int countNetworks = ESP8266Utils_getTrackedNetworkCount(); int currentIndex = ESP8266Utils_getIndexBySsid(adjustedSSID); if ((currentIndex < 0) && (countNetworks > 0) && (previousCurrentIndex > 0)) { @@ -869,7 +870,6 @@ void pantalla_actualizarMenuConfigWifiResultado(String* lcdBuffer) { *lcdBuffer += String("WIFI: CONECTADO "); *lcdBuffer += String("< OK>"); } else { - int porcentaje = ESP8266Utils_getWifiConnectionPercentage(); if (porcentaje == 100) { *lcdBuffer += String("WIFI: FALLIDO "); } else { From 2daf46913693596d50844043c438cf7ff2022ffd Mon Sep 17 00:00:00 2001 From: Mickyleitor Date: Wed, 6 Aug 2025 23:08:49 +0200 Subject: [PATCH 4/6] better defines --- Firmware_ESP8266/ESP8266_Utils.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Firmware_ESP8266/ESP8266_Utils.h b/Firmware_ESP8266/ESP8266_Utils.h index 7a6438f..2c960e4 100644 --- a/Firmware_ESP8266/ESP8266_Utils.h +++ b/Firmware_ESP8266/ESP8266_Utils.h @@ -10,6 +10,9 @@ #define HTTP_SERVER_PING_INTERVAL_MS (10000) #define WIFI_CONNECTION_TIMEOUT_MS (10000) +#define WIFI_SCAN_NOT_SEEN_MAX_COUNT (5) +#define WIFI_SCAN_MINIMUM_RSSI_FOR_TRACKING (-80) +#define WIFI_SCAN_MAX_TRACKED_NETWORKS_COUNT (10) #define TEMPERATURE_DEGREE_INVALID (65535) @@ -43,7 +46,7 @@ struct WifiNetworkInfo { seenInThisScan(true) {} }; -std::vector wifiNetworks; +static std::vector wifiNetworks; static bool wifiScanInProgress = false; static unsigned long lastConnectAttemptMs = 0; @@ -191,7 +194,7 @@ void cleanNetworksNotSeen() { it->notSeenCount = 0; } - if (it->notSeenCount >= 5) { + if (it->notSeenCount >= WIFI_SCAN_NOT_SEEN_MAX_COUNT) { it = wifiNetworks.erase(it); } else { ++it; @@ -217,7 +220,7 @@ void updateOrInsertNetwork( } // Filtro para evitar agregar redes volátiles de 1 sola muestra - if (rssi < -80) { + if (rssi < WIFI_SCAN_MINIMUM_RSSI_FOR_TRACKING) { // Si la red es débil y no estaba antes, ignorarla return; } @@ -271,8 +274,8 @@ void ESP8266Utils_checkScanResults() { std::sort(wifiNetworks.begin(), wifiNetworks.end(), compareByRssiDesc); - if (wifiNetworks.size() > 10) { - wifiNetworks.resize(10); + if (wifiNetworks.size() > WIFI_SCAN_MAX_TRACKED_NETWORKS_COUNT) { + wifiNetworks.resize(WIFI_SCAN_MAX_TRACKED_NETWORKS_COUNT); } Serial.println("Lista de redes ordenada por RSSI promedio:"); From 1a8b1f403e9928cfb6c6337fbba7c6d80f20f6f9 Mon Sep 17 00:00:00 2001 From: Mickyleitor Date: Thu, 7 Aug 2025 00:24:54 +0200 Subject: [PATCH 5/6] better encapsulation of pending configuration in lcd --- Firmware_ESP8266/lcd.h | 164 ++++++++++++++++++++++++++--------------- 1 file changed, 103 insertions(+), 61 deletions(-) diff --git a/Firmware_ESP8266/lcd.h b/Firmware_ESP8266/lcd.h index 04b3b78..8f13ca0 100644 --- a/Firmware_ESP8266/lcd.h +++ b/Firmware_ESP8266/lcd.h @@ -13,15 +13,33 @@ extern struct WeatherData MyWeather; LiquidCrystal_PCF8574 _lcd(LCD_I2C_ADDRESS); -static time_t adjustedTime = 0; -static long adjustedTimeZone = 0; -static uint32_t previousBuzzerVolume = 0; -static unsigned long currentAdjustedLevelIndex = 0; -static bool previousBuzzerEnabled = false; -static bool buttonIsReleased = false; -static String adjustedSSID = ""; -static String adjustedPassword = ""; -static unsigned long buttonHoldingTimeMs = 0; +static bool buttonIsReleased = false; +static unsigned long buttonHoldingTimeMs = 0; + +struct WifiConfig { + String ssid; + String password; + bool enabled; +}; + +struct VolumeConfig { + uint32_t previousVolume; + bool previousBuzzerEnabled; +}; + +struct TimezoneConfig { + time_t time; + unsigned long whichIncrementIndex; + long timezoneShift; +}; + +struct PendingConfig { + struct WifiConfig wifi; + struct VolumeConfig volume; + struct TimezoneConfig timezone; +}; + +static PendingConfig pendingConfig; #define LCD_SPECIAL_CHAR_BASE (char)(10) #define LCD_SPECIAL_CHAR_LEFT_ARROW (char)(LCD_SPECIAL_CHAR_BASE + 0) @@ -191,9 +209,9 @@ void pantalla_handleButtonInMenu( newMenu = SELECCION_MENU_CONFIG; break; case BUTTON_STATUS_RIGHT: - adjustedTime = time(NULL); - currentAdjustedLevelIndex = 0; - newMenu = SELECCION_MENU_CONFIG_FECHA_HORA_AJUSTE; + pendingConfig.timezone.time = time(NULL); + pendingConfig.timezone.whichIncrementIndex = 0; + newMenu = SELECCION_MENU_CONFIG_FECHA_HORA_AJUSTE; break; case BUTTON_STATUS_DOWN: newMenu = SELECCION_MENU_CONFIG_VOLUMEN; @@ -216,30 +234,31 @@ void pantalla_handleButtonInMenu( switch (currentButtonPressed) { case BUTTON_STATUS_LEFT: - if (currentAdjustedLevelIndex) { - currentAdjustedLevelIndex--; + if (pendingConfig.timezone.whichIncrementIndex) { + pendingConfig.timezone.whichIncrementIndex--; } else { newMenu = SELECCION_MENU_CONFIG_FECHA_HORA; } break; case BUTTON_STATUS_RIGHT: - if (currentAdjustedLevelIndex < (incsCount - 1)) { - currentAdjustedLevelIndex++; + if (pendingConfig.timezone.whichIncrementIndex < (incsCount - 1)) { + pendingConfig.timezone.whichIncrementIndex++; } else { - adjustedTimeZone = persistentVars_get_rtcTime().timezoneShift; - newMenu = SELECCION_MENU_CONFIG_ZONA_HORARIA_AJUSTE; + pendingConfig.timezone.timezoneShift + = persistentVars_get_rtcTime().timezoneShift; + newMenu = SELECCION_MENU_CONFIG_ZONA_HORARIA_AJUSTE; } break; case BUTTON_STATUS_UP: - adjustedTime += incs[currentAdjustedLevelIndex]; + pendingConfig.timezone.time += incs[pendingConfig.timezone.whichIncrementIndex]; break; case BUTTON_STATUS_DOWN: - adjustedTime -= incs[currentAdjustedLevelIndex]; + pendingConfig.timezone.time -= incs[pendingConfig.timezone.whichIncrementIndex]; break; } - if (adjustedTime < 0) { - adjustedTime = 0; + if (pendingConfig.timezone.time < 0) { + pendingConfig.timezone.time = 0; } break; @@ -247,24 +266,24 @@ void pantalla_handleButtonInMenu( case SELECCION_MENU_CONFIG_ZONA_HORARIA_AJUSTE: { switch (currentButtonPressed) { case BUTTON_STATUS_LEFT: - currentAdjustedLevelIndex = 0; - newMenu = SELECCION_MENU_CONFIG_FECHA_HORA_AJUSTE; + pendingConfig.timezone.whichIncrementIndex = 0; + newMenu = SELECCION_MENU_CONFIG_FECHA_HORA_AJUSTE; break; case BUTTON_STATUS_RIGHT: buzzer_sound_accept(); - rtc_set(adjustedTime, adjustedTimeZone); + rtc_set(pendingConfig.timezone.time, pendingConfig.timezone.timezoneShift); newMenu = SELECCION_MENU_CONFIG; break; case BUTTON_STATUS_UP: - adjustedTimeZone += 3600; // Increase by 1 hour - if (adjustedTimeZone > 43200) { // 12 hours in seconds - adjustedTimeZone = 43200; + pendingConfig.timezone.timezoneShift += 3600; // Increase by 1 hour + if (pendingConfig.timezone.timezoneShift > 43200) { // 12 hours in seconds + pendingConfig.timezone.timezoneShift = 43200; } break; case BUTTON_STATUS_DOWN: - adjustedTimeZone -= 3600; // Decrease by 1 hour - if (adjustedTimeZone < -43200) { // -12 hours in seconds - adjustedTimeZone = -43200; + pendingConfig.timezone.timezoneShift -= 3600; // Decrease by 1 hour + if (pendingConfig.timezone.timezoneShift < -43200) { // -12 hours in seconds + pendingConfig.timezone.timezoneShift = -43200; } break; } @@ -277,10 +296,10 @@ void pantalla_handleButtonInMenu( newMenu = SELECCION_MENU_CONFIG_FECHA_HORA; break; case BUTTON_STATUS_RIGHT: - previousBuzzerVolume = buzzer_get_volume(); - previousBuzzerEnabled = buzzer_is_enabled(); - buttonIsReleased = false; - newMenu = SELECCION_MENU_CONFIG_VOLUMEN_AJUSTE; + pendingConfig.volume.previousVolume = buzzer_get_volume(); + pendingConfig.volume.previousBuzzerEnabled = buzzer_is_enabled(); + buttonIsReleased = false; + newMenu = SELECCION_MENU_CONFIG_VOLUMEN_AJUSTE; break; case BUTTON_STATUS_DOWN: newMenu = SELECCION_MENU_CONFIG_DEBUG; @@ -324,8 +343,8 @@ void pantalla_handleButtonInMenu( newMenu = SELECCION_MENU_CONFIG; break; case BUTTON_STATUS_LEFT: - buzzer_set_volume(previousBuzzerVolume); - if (previousBuzzerEnabled) { + buzzer_set_volume(pendingConfig.volume.previousVolume); + if (pendingConfig.volume.previousBuzzerEnabled) { buzzer_enable(); } else { buzzer_disable(); @@ -371,7 +390,7 @@ void pantalla_handleButtonInMenu( break; case BUTTON_STATUS_RIGHT: ESP8266Utils_clearWifiNetworksList(); - newMenu = SELECCION_MENU_CONFIG_WIFI_SSID; + newMenu = SELECCION_MENU_CONFIG_WIFI_HABILITAR; break; case BUTTON_STATUS_DOWN: case BUTTON_STATUS_LEFT: @@ -379,6 +398,20 @@ void pantalla_handleButtonInMenu( break; } break; + case SELECCION_MENU_CONFIG_WIFI_HABILITAR: + switch (currentButtonPressed) { + case SELECCION_MENU_CONFIG_WIFI: + newMenu = SELECCION_MENU_CONFIG_DEBUG; + break; + case BUTTON_STATUS_RIGHT: + newMenu = SELECCION_MENU_CONFIG_WIFI_SSID; + break; + case BUTTON_STATUS_DOWN: + case BUTTON_STATUS_UP: + buzzer_sound_error(); + break; + } + break; case SELECCION_MENU_CONFIG_WIFI_SSID: { // In this menu, an async wifi scan is performed. And we start to do RSSI avg on each // SSID. We display the SSID in a list sorted by RSSI, first the strongest. @@ -389,7 +422,7 @@ void pantalla_handleButtonInMenu( static int previousCurrentIndex = 1; // Start at 1 so in the first iteration we can // select the first network. int countNetworks = ESP8266Utils_getTrackedNetworkCount(); - int currentIndex = ESP8266Utils_getIndexBySsid(adjustedSSID); + int currentIndex = ESP8266Utils_getIndexBySsid(pendingConfig.wifi.ssid); if ((currentIndex < 0) && (countNetworks > 0) && (previousCurrentIndex > 0)) { currentIndex = previousCurrentIndex - 1; } else if (currentIndex < 0) { @@ -397,24 +430,24 @@ void pantalla_handleButtonInMenu( } previousCurrentIndex = currentIndex; - ESP8266Utils_getSsidAtIndex(currentIndex, adjustedSSID); + ESP8266Utils_getSsidAtIndex(currentIndex, pendingConfig.wifi.ssid); switch (currentButtonPressed) { case BUTTON_STATUS_UP: if (currentIndex > 0) { currentIndex--; } - ESP8266Utils_getSsidAtIndex(currentIndex, adjustedSSID); + ESP8266Utils_getSsidAtIndex(currentIndex, pendingConfig.wifi.ssid); break; case BUTTON_STATUS_RIGHT: - adjustedPassword = ""; - newMenu = SELECCION_MENU_CONFIG_WIFI_PASSWORD; + pendingConfig.wifi.password = ""; + newMenu = SELECCION_MENU_CONFIG_WIFI_PASSWORD; break; case BUTTON_STATUS_DOWN: if (currentIndex < (countNetworks - 1)) { currentIndex++; } - ESP8266Utils_getSsidAtIndex(currentIndex, adjustedSSID); + ESP8266Utils_getSsidAtIndex(currentIndex, pendingConfig.wifi.ssid); break; case BUTTON_STATUS_LEFT: newMenu = SELECCION_MENU_CONFIG_WIFI; @@ -438,29 +471,38 @@ void pantalla_handleButtonInMenu( if (previousButtonHolding == BUTTON_STATUS_DOWN) { buzzer_sound_accept(); newMenu = SELECCION_MENU_CONFIG_WIFI_RESULTADO; - ESP8266Utils_connectToWifi(adjustedSSID, adjustedPassword); + ESP8266Utils_connectToWifi( + pendingConfig.wifi.ssid, + pendingConfig.wifi.password); } } else { switch (previousButtonHolding) { case BUTTON_STATUS_LEFT: - if (adjustedPassword.length() == 0) { + if (pendingConfig.wifi.password.length() == 0) { newMenu = SELECCION_MENU_CONFIG_WIFI_SSID; } else { - adjustedPassword.remove(adjustedPassword.length() - 1); + pendingConfig.wifi.password.remove( + pendingConfig.wifi.password.length() - 1); } break; case BUTTON_STATUS_UP: - if (adjustedPassword[adjustedPassword.length() - 1] < '~') { - adjustedPassword[adjustedPassword.length() - 1]++; + if (pendingConfig.wifi + .password[pendingConfig.wifi.password.length() - 1] + < '~') { + pendingConfig.wifi + .password[pendingConfig.wifi.password.length() - 1]++; } break; case BUTTON_STATUS_DOWN: - if (adjustedPassword[adjustedPassword.length() - 1] > '!') { - adjustedPassword[adjustedPassword.length() - 1]--; + if (pendingConfig.wifi + .password[pendingConfig.wifi.password.length() - 1] + > '!') { + pendingConfig.wifi + .password[pendingConfig.wifi.password.length() - 1]--; } break; case BUTTON_STATUS_RIGHT: - adjustedPassword += 'A'; + pendingConfig.wifi.password += 'A'; break; } } @@ -474,10 +516,10 @@ void pantalla_handleButtonInMenu( if (!wifiCredentialStored) { wifiCredentialStored = true; memcpy(settings.wifiSettings.ssid_sta, - adjustedSSID.c_str(), + pendingConfig.wifi.ssid.c_str(), sizeof(settings.wifiSettings.ssid_sta)); memcpy(settings.wifiSettings.password_sta, - adjustedPassword.c_str(), + pendingConfig.wifi.password.c_str(), sizeof(settings.wifiSettings.password_sta)); EEPROM_Schedule_Write(100); } @@ -623,7 +665,7 @@ void pantalla_actualizarMenuConfigFechaHora(String* lcdBuffer) { } void pantalla_actualizarMenuConfigFechaHoraAjuste(String* lcdBuffer) { - struct tm* timeinfo = localtime(&adjustedTime); + struct tm* timeinfo = localtime(&pendingConfig.timezone.time); static unsigned long lastFlashMs = 0; static bool flashOn = false; @@ -634,7 +676,7 @@ void pantalla_actualizarMenuConfigFechaHoraAjuste(String* lcdBuffer) { } auto printField = [&](int value, unsigned long index, int width) { - bool visible = (currentAdjustedLevelIndex != index) || flashOn; + bool visible = (pendingConfig.timezone.whichIncrementIndex != index) || flashOn; if (visible) { if (value < 10 && width >= 2) { *lcdBuffer += '0'; @@ -666,7 +708,7 @@ void pantalla_actualizarMenuConfigFechaHoraAjuste(String* lcdBuffer) { void pantalla_actualizarMenuConfigZonaHorariaAjuste(String* lcdBuffer) { *lcdBuffer += String("ZONA UTC: "); - *lcdBuffer += String(adjustedTimeZone / 3600); + *lcdBuffer += String(pendingConfig.timezone.timezoneShift / 3600); *lcdBuffer += String(" h"); // Add spaces to fill the line. while (lcdBuffer->length() < 16) { @@ -745,8 +787,8 @@ void pantalla_actualizarMenuConfigWifiPassword(String* lcdBuffer) { // If password is larger than 11 characters, truncate it from the // left to right, keeping the last 11 characters. - String truncatedPassword = adjustedPassword; - if (adjustedPassword.length() > 11) { + String truncatedPassword = pendingConfig.wifi.password; + if (truncatedPassword.length() > 11) { truncatedPassword = truncatedPassword.substring(truncatedPassword.length() - 11); } *lcdBuffer += truncatedPassword; @@ -807,8 +849,8 @@ void pantalla_actualizarMenuConfigWifiPassword(String* lcdBuffer) { void pantalla_actualizarMenuConfigWifiSsid(String* lcdBuffer) { *lcdBuffer += String("SSID:"); - String mySSID = adjustedSSID; - int adjustedSSIDindex = ESP8266Utils_getIndexBySsid(adjustedSSID); + String mySSID = pendingConfig.wifi.ssid; + int adjustedSSIDindex = ESP8266Utils_getIndexBySsid(pendingConfig.wifi.ssid); if (adjustedSSIDindex < 0) { mySSID = "No hay redes"; } From 3af121a7535ef0a8905eab9aa711423a39380449 Mon Sep 17 00:00:00 2001 From: Mickyleitor Date: Fri, 8 Aug 2025 15:33:41 +0200 Subject: [PATCH 6/6] Refactor WiFi settings and update handling; add able to disable/enable ble and display wifi/weater indication icon in screen --- Firmware_ESP8266/EEPROM_Utils.h | 12 +- Firmware_ESP8266/ESP8266_Utils.h | 291 ++++++++++++++------------ Firmware_ESP8266/Firmware_ESP8266.ino | 15 +- Firmware_ESP8266/basic_defines.h | 13 +- Firmware_ESP8266/lcd.h | 134 ++++++++---- Firmware_ESP8266/persistentVars.h | 21 ++ 6 files changed, 305 insertions(+), 181 deletions(-) diff --git a/Firmware_ESP8266/EEPROM_Utils.h b/Firmware_ESP8266/EEPROM_Utils.h index 2bc08d8..bcec943 100644 --- a/Firmware_ESP8266/EEPROM_Utils.h +++ b/Firmware_ESP8266/EEPROM_Utils.h @@ -12,9 +12,8 @@ static bool EEPROM_Scheduled_Write_Enabled = false; struct WifiSettings { char ssid_sta[64]; char password_sta[64]; - char ssid_ap[64]; - char password_ap[64]; - char hostname[64]; + bool wifi_enabled; + bool ota_enabled; }; struct OpenWeatherMapSettings { @@ -135,16 +134,15 @@ void EEPROM_Write_Default(Settings* data) { } Settings defaultSettings = { 0 }; - strcpy(defaultSettings.wifiSettings.hostname, DEFAULT_HOSTNAME); strcpy(defaultSettings.wifiSettings.ssid_sta, DEFAULT_STA_SSID); strcpy(defaultSettings.wifiSettings.password_sta, DEFAULT_STA_PASSWORD); - strcpy(defaultSettings.wifiSettings.ssid_ap, DEFAULT_AP_SSID_AND_PASSWORD); - strcpy(defaultSettings.wifiSettings.password_ap, DEFAULT_AP_SSID_AND_PASSWORD); + defaultSettings.wifiSettings.wifi_enabled = DEFAULT_WIFI_ENABLED; + defaultSettings.wifiSettings.ota_enabled = DEFAULT_WIFI_OTA_ENABLED; strcpy(defaultSettings.openWeatherMapSettings.appid, DEFAULT_OPENWEATHERMAP_APPID); defaultSettings.openWeatherMapSettings.lat = DEFAULT_OPENWEATHERMAP_LOCATION_LAT; defaultSettings.openWeatherMapSettings.lon = DEFAULT_OPENWEATHERMAP_LOCATION_LON; defaultSettings.buzzerSettings.general_volume = DEFAULT_BUZZER_VOLUME; - defaultSettings.buzzerSettings.isEnabled = false; + defaultSettings.buzzerSettings.isEnabled = DEFAULT_BUZZER_ENABLED; EEPROM_Write(&defaultSettings); *data = defaultSettings; } diff --git a/Firmware_ESP8266/ESP8266_Utils.h b/Firmware_ESP8266/ESP8266_Utils.h index 2c960e4..13d495e 100644 --- a/Firmware_ESP8266/ESP8266_Utils.h +++ b/Firmware_ESP8266/ESP8266_Utils.h @@ -6,21 +6,29 @@ #include "basic_defines.h" #include "persistentVars.h" -#define HTTP_SERVER_PING_ADDRESS "1.1.1.1" -#define HTTP_SERVER_PING_INTERVAL_MS (10000) - #define WIFI_CONNECTION_TIMEOUT_MS (10000) +#define WIFI_CONNECTION_INTERVAL_MS (60 * 60 * 1000) // 60 min +#define WIFI_CONNECTION_MAX_CONSECUTIVE_ATTEMPTS (5) + +#define WEATHER_UPDATE_INTERVAL_MS (30 * 60 * 1000) // 30 min +#define WEATHER_UPDATE_MAX_CONSECUTIVE_ATTEMPTS (10) +#define WEATHER_SERVER_REQUEST_TIMEOUT (2000) + #define WIFI_SCAN_NOT_SEEN_MAX_COUNT (5) #define WIFI_SCAN_MINIMUM_RSSI_FOR_TRACKING (-80) #define WIFI_SCAN_MAX_TRACKED_NETWORKS_COUNT (10) -#define TEMPERATURE_DEGREE_INVALID (65535) +#define TEMPERATURE_DEGREE_INVALID (0xFFFF) -extern struct Settings settings; +enum WifiErrorType { + WIFI_ERROR_NONE = (0 << 0), + WIFI_ERROR_CONNECTION_FAILED_MASK = (1 << 0), + WIFI_ERROR_WEATHER_UPDATE_FAILED_MASK = (1 << 1), +}; -struct WeatherData { - double TemperatureDegree = TEMPERATURE_DEGREE_INVALID; -} MyWeather; +typedef uint8_t WifiErrorType_t; + +extern struct Settings settings; struct WifiNetworkInfo { String ssid; @@ -47,132 +55,71 @@ struct WifiNetworkInfo { }; static std::vector wifiNetworks; -static bool wifiScanInProgress = false; -static unsigned long lastConnectAttemptMs = 0; - -bool ESP8266Utils_Connect_STA( - const char* ssid, - const char* password, - const char* hostname, - int32_t timeout_ms = 10000) { - Serial.println(""); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED && timeout_ms > 0) { - delay(100); - timeout_ms -= 100; - yield(); +static bool wifiScanInProgress = false; +static unsigned long lastConnectUpdateMs = WIFI_CONNECTION_TIMEOUT_MS; +static unsigned long lastWeatherUpdateMs = WEATHER_UPDATE_INTERVAL_MS; +static double TemperatureDegree = TEMPERATURE_DEGREE_INVALID; +static bool wifiError = false; +static bool weatherError = false; + +bool ESP8266Utils_get_TemperatureDegree(double* temperature) { + if ((temperature == nullptr) || (TemperatureDegree == TEMPERATURE_DEGREE_INVALID)) { + return false; // Invalid temperature or null pointer } - - if (timeout_ms <= 0) { - Serial.println("STA Failed"); - return false; - } - - Serial.println(""); - Serial.print("Iniciado STA:\t"); - Serial.println(ssid); - Serial.print("IP address:\t"); - Serial.println(WiFi.localIP()); - + *temperature = TemperatureDegree; return true; } -bool ESP8266Utils_is_STA_connected() { return WiFi.isConnected(); } +bool ESP8266Utils_update_WeatherData(void) { + bool success = false; -bool ESP8266Utils_is_STA_online() { - if (!ESP8266Utils_is_STA_connected()) { - return false; - } - static bool isOnline; - static uint32_t timeout_ms = 0; - if ((millis() - timeout_ms) > HTTP_SERVER_PING_INTERVAL_MS) { - timeout_ms = millis(); - isOnline = true; - WiFiClient client; - // Ping the server to see if it is online - client.setTimeout(HTTP_SERVER_REQUEST_TIMEOUT); - if (!client.connect(HTTP_SERVER_PING_ADDRESS, 80)) { - isOnline = false; - } - client.stop(); - } - return isOnline; -} - -int8_t ESP8266Utils_get_STA_RSSI() { return WiFi.RSSI(); } - -String ESP8266Utils_get_STA_SSID() { return WiFi.SSID(); } + Serial.println("Updating weather data..."); -bool ESP8266Utils_update_WeatherData(struct Settings* myData) { - if (!ESP8266Utils_is_STA_online()) { - Serial.println("No internet connection"); - return false; - } - - String default_appid = DEFAULT_OPENWEATHERMAP_APPID; - if ((String(myData->openWeatherMapSettings.appid) == default_appid) - || (String(myData->openWeatherMapSettings.appid) == String(""))) { - Serial.println("Invalid Weather API key : " + String(myData->openWeatherMapSettings.appid)); - return false; - } - - WiFiClient client; - // Connect to HTTP server - client.setTimeout(HTTP_SERVER_REQUEST_TIMEOUT); - if (!client.connect(OPENWEATHERMAP_HOST, OPENWEATHERMAP_PORT)) { - Serial.println("Connection failed"); - // Disconnect - client.stop(); - return false; - } + if (String(settings.openWeatherMapSettings.appid) == String("")) { + Serial.println("Empty Weather API key"); + } else { + WiFiClient client; + client.setTimeout(WEATHER_SERVER_REQUEST_TIMEOUT); - // Send HTTP request - String HTTPrequest = DEFAULT_OPENWEATHERMAP_HTTP_REQUEST( - myData->openWeatherMapSettings.appid, - myData->openWeatherMapSettings.lat, - myData->openWeatherMapSettings.lon); - client.println(HTTPrequest); - client.println("Host: " + String(OPENWEATHERMAP_HOST)); - client.println("Connection: close"); - if (client.println() == 0) { - Serial.println("Failed to send request"); - // Disconnect - client.stop(); - return false; - } - // Skip HTTP headers - if (!client.find("\r\n\r\n")) { - Serial.println("Invalid response"); - // Disconnect - client.stop(); - return false; - } - if (client.find("\"temp\":")) { - double NewTemp = client.readStringUntil(',').toDouble(); - if (NewTemp > 273) { - NewTemp -= 273.15; + if (!client.connect(OPENWEATHERMAP_HOST, OPENWEATHERMAP_PORT)) { + Serial.println("Connection failed"); + } else { + String HTTPrequest = OPENWEATHERMAP_HTTP_REQUEST( + settings.openWeatherMapSettings.appid, + settings.openWeatherMapSettings.lat, + settings.openWeatherMapSettings.lon); + client.println(HTTPrequest); + client.println("Host: " + String(OPENWEATHERMAP_HOST)); + client.println("Connection: close"); + + if (client.println() == 0) { + Serial.println("Failed to send request"); + } else if (!client.find("\r\n\r\n")) { + Serial.println("Invalid response"); + } else if (client.find("\"temp\":")) { + double NewTemp = client.readStringUntil(',').toDouble(); + if (NewTemp > 273) { + NewTemp -= 273.15; + } + Serial.print("Temperature: "); + Serial.println(NewTemp); + TemperatureDegree = NewTemp; + + if (client.find("\"timezone\":")) { + long timezoneshift = strtol(client.readStringUntil(',').c_str(), NULL, 10); + Serial.print("Timezone shift: "); + Serial.println(timezoneshift); + struct rtcTime_t rtcTime + = { .myTime = time(NULL), .timezoneShift = timezoneshift }; + persistentVars_store_rtcTime(&rtcTime); + success = true; + } + } } - Serial.print("Temperature: "); - Serial.println(NewTemp); - MyWeather.TemperatureDegree = NewTemp; - } else { - Serial.println("No Temperature JSON object found"); - } - if (client.find("\"timezone\":")) { - long timezoneshift = strtol(client.readStringUntil(',').c_str(), NULL, 10); - Serial.print("Timezone shift: "); - Serial.println(timezoneshift); - struct rtcTime_t rtcTime = { .myTime = time(NULL), .timezoneShift = timezoneshift }; - persistentVars_store_rtcTime(&rtcTime); - } else { - Serial.println("No timezoneshift JSON object found"); + client.stop(); } - - // Disconnect - client.stop(); - return true; + lastWeatherUpdateMs = millis(); + return success; } void ESP8266Utils_clearWifiNetworksList() { @@ -316,17 +263,99 @@ int ESP8266Utils_getIndexBySsid(const String& targetSsid) { void ESP8266Utils_connectToWifi(const String& ssid, const String& password) { WiFi.mode(WIFI_STA); WiFi.begin(ssid.c_str(), password.c_str()); - lastConnectAttemptMs = millis(); + lastConnectUpdateMs = millis(); } -bool ESP8266Utils_isWifiConnected() { return WiFi.status() == WL_CONNECTED; } +bool ESP8266Utils_isWifiConnected(void) { return WiFi.status() == WL_CONNECTED; } -int ESP8266Utils_getWifiConnectionPercentage() { - if (lastConnectAttemptMs == 0) { +int ESP8266Utils_getWifiConnectionPercentage(void) { + if (lastConnectUpdateMs == 0) { return 0; } - unsigned long elapsed = millis() - lastConnectAttemptMs; + unsigned long elapsed = millis() - lastConnectUpdateMs; return (elapsed * 100) / WIFI_CONNECTION_TIMEOUT_MS; } -void Wifi_handler() {} +bool ESP8266Utils_getWifiConnectAttemptTmo(void) { + if (lastConnectUpdateMs == 0) { + return true; // No hay intento previo, se considera un timeout + } + return (millis() - lastConnectUpdateMs) >= WIFI_CONNECTION_INTERVAL_MS; +} + +bool ESP8266Utils_getWifiWeatherAttemptTmo(void) { + if (lastWeatherUpdateMs == 0) { + return true; // No hay intento previo, se considera un timeout + } + return (millis() - lastWeatherUpdateMs) >= WEATHER_UPDATE_INTERVAL_MS; +} + +WifiErrorType_t ESP8266Utils_get_errors(void) { + WifiErrorType_t error_bitmask = WIFI_ERROR_NONE; + if (wifiError) { + error_bitmask |= WIFI_ERROR_CONNECTION_FAILED_MASK; + } + if (weatherError) { + error_bitmask |= WIFI_ERROR_WEATHER_UPDATE_FAILED_MASK; + } + return error_bitmask; +} + +void Wifi_handler(bool inConfigMode) { + // Persistent state between calls + static unsigned long connectAttemptCount = 0; + static unsigned long weatherUpdateCount = 0; + static bool backFromConfigMode = false; // This is to force immediate reconnection + // attempts after leaving config mode + if (inConfigMode) { + connectAttemptCount = 0; + weatherUpdateCount = 0; + backFromConfigMode = true; // Force immediate actions after config mode + return; + } + + bool wifiEnabled = settings.wifiSettings.wifi_enabled; + bool wifiConnected = ESP8266Utils_isWifiConnected(); + bool WifiTmo = ESP8266Utils_getWifiConnectAttemptTmo() || backFromConfigMode; + bool WeatherTmo = ESP8266Utils_getWifiWeatherAttemptTmo() || backFromConfigMode; + + // ===== WiFi auto connection handling ===== + if (wifiEnabled && wifiConnected && connectAttemptCount > 0) { + Serial.println("Connected to WiFi"); + connectAttemptCount = 0; + wifiError = false; + } else if ((wifiEnabled && !wifiConnected) && WifiTmo) { + if (++connectAttemptCount < WIFI_CONNECTION_MAX_CONSECUTIVE_ATTEMPTS) { + Serial.println("Attempt " + String(connectAttemptCount) + " to connect to WiFi..."); + ESP8266Utils_connectToWifi( + settings.wifiSettings.ssid_sta, + settings.wifiSettings.password_sta); + } else { + wifiError = true; + } + } else if (!wifiEnabled && wifiConnected) { + Serial.println("Disconnecting WiFi..."); + WiFi.disconnect(); + connectAttemptCount = 0; + wifiError = false; + } + + // ===== Weather update handling ===== + if (wifiEnabled && wifiConnected && WeatherTmo) { + if (ESP8266Utils_update_WeatherData()) { + weatherUpdateCount = 0; + weatherError = false; + } else if (++weatherUpdateCount > WEATHER_UPDATE_MAX_CONSECUTIVE_ATTEMPTS) { + TemperatureDegree = TEMPERATURE_DEGREE_INVALID; + Serial.println("Attempt " + String(weatherUpdateCount) + " to update weather failed."); + weatherError = true; + } + } else if (!wifiConnected) { + weatherUpdateCount = 0; + TemperatureDegree = TEMPERATURE_DEGREE_INVALID; + weatherError = false; + } + + backFromConfigMode = false; // Indicate we are no longer back from config mode +} + diff --git a/Firmware_ESP8266/Firmware_ESP8266.ino b/Firmware_ESP8266/Firmware_ESP8266.ino index 5fd1e8e..59c7201 100644 --- a/Firmware_ESP8266/Firmware_ESP8266.ino +++ b/Firmware_ESP8266/Firmware_ESP8266.ino @@ -85,5 +85,18 @@ void loop() { buzzer_handler(); shutterHandler(); EEPROM_Handler(); - Wifi_handler(); + Wifi_handler(_seleccionMenu > SELECCION_MENU_CONFIG); + + static Settings previousSettings; + if (memcmp(&settings, &previousSettings, sizeof(Settings)) != 0) { + Serial.println("Cambio de configuración de settings detectado."); + Serial.print("Habilitado: "); + Serial.println(settings.wifiSettings.wifi_enabled ? "Si" : "No"); + Serial.print("OTA: "); + Serial.println(settings.wifiSettings.ota_enabled ? "Si" : "No"); + Serial.print("SSID: "); + Serial.println(settings.wifiSettings.ssid_sta); + + memcpy(&previousSettings, &settings, sizeof(Settings)); + } } diff --git a/Firmware_ESP8266/basic_defines.h b/Firmware_ESP8266/basic_defines.h index d4b3f46..d0b4d38 100644 --- a/Firmware_ESP8266/basic_defines.h +++ b/Firmware_ESP8266/basic_defines.h @@ -3,22 +3,20 @@ #define SLAVE_I2C_ADDRESS (0x08) #define LCD_I2C_ADDRESS (0x3F) +#define DEFAULT_BUZZER_ENABLED false #define DEFAULT_BUZZER_VOLUME (4000) #define DEFAULT_STA_SSID "YOUR_SSID" #define DEFAULT_STA_PASSWORD "YOUR_PASSWORD" -#define DEFAULT_AP_SSID_AND_PASSWORD "ESP8266Config" -#define DEFAULT_HOSTNAME "esp8266config" +#define DEFAULT_WIFI_ENABLED false +#define DEFAULT_WIFI_OTA_ENABLED false #define OPENWEATHERMAP_HOST "api.openweathermap.org" #define OPENWEATHERMAP_PORT (80) -#define DEFAULT_OPENWEATHERMAP_APPID "YOUR_API_KEY" +#define DEFAULT_OPENWEATHERMAP_APPID "" #define DEFAULT_OPENWEATHERMAP_LOCATION_LAT (0) #define DEFAULT_OPENWEATHERMAP_LOCATION_LON (0) -#define HTTP_SERVER_REQUEST_TIMEOUT (2000) -#define WIFI_CONNECTION_TIMEOUT (10000) - -#define DEFAULT_OPENWEATHERMAP_HTTP_REQUEST(appid, lat, long) \ +#define OPENWEATHERMAP_HTTP_REQUEST(appid, lat, long) \ "GET /data/2.5/weather?lat=" + \ String(lat) + \ "&lon=" + \ @@ -54,6 +52,7 @@ enum seleccionMenu { SELECCION_MENU_CONFIG_DEBUG_SOFT_RST_COUNT, SELECCION_MENU_CONFIG_WIFI, SELECCION_MENU_CONFIG_WIFI_HABILITAR, + SELECCION_MENU_CONFIG_WIFI_OTA_HABILITAR, SELECCION_MENU_CONFIG_WIFI_SSID, SELECCION_MENU_CONFIG_WIFI_PASSWORD, SELECCION_MENU_CONFIG_WIFI_RESULTADO, diff --git a/Firmware_ESP8266/lcd.h b/Firmware_ESP8266/lcd.h index 8f13ca0..1eb90c3 100644 --- a/Firmware_ESP8266/lcd.h +++ b/Firmware_ESP8266/lcd.h @@ -10,8 +10,6 @@ #include "persistentVars.h" #include "rtcTime.h" -extern struct WeatherData MyWeather; - LiquidCrystal_PCF8574 _lcd(LCD_I2C_ADDRESS); static bool buttonIsReleased = false; static unsigned long buttonHoldingTimeMs = 0; @@ -20,6 +18,7 @@ struct WifiConfig { String ssid; String password; bool enabled; + bool ota_enabled; }; struct VolumeConfig { @@ -389,8 +388,8 @@ void pantalla_handleButtonInMenu( newMenu = SELECCION_MENU_CONFIG_DEBUG; break; case BUTTON_STATUS_RIGHT: - ESP8266Utils_clearWifiNetworksList(); - newMenu = SELECCION_MENU_CONFIG_WIFI_HABILITAR; + pendingConfig.wifi.enabled = settings.wifiSettings.wifi_enabled; + newMenu = SELECCION_MENU_CONFIG_WIFI_HABILITAR; break; case BUTTON_STATUS_DOWN: case BUTTON_STATUS_LEFT: @@ -400,15 +399,39 @@ void pantalla_handleButtonInMenu( break; case SELECCION_MENU_CONFIG_WIFI_HABILITAR: switch (currentButtonPressed) { - case SELECCION_MENU_CONFIG_WIFI: - newMenu = SELECCION_MENU_CONFIG_DEBUG; + case BUTTON_STATUS_LEFT: + settings.wifiSettings.wifi_enabled = pendingConfig.wifi.enabled; + EEPROM_Schedule_Write(0); + newMenu = SELECCION_MENU_CONFIG_WIFI; break; case BUTTON_STATUS_RIGHT: + pendingConfig.wifi.ota_enabled = settings.wifiSettings.ota_enabled; + settings.wifiSettings.wifi_enabled = pendingConfig.wifi.enabled; + EEPROM_Schedule_Write(0); + newMenu = SELECCION_MENU_CONFIG_WIFI_OTA_HABILITAR; + break; + case BUTTON_STATUS_DOWN: + case BUTTON_STATUS_UP: + pendingConfig.wifi.enabled = !pendingConfig.wifi.enabled; + break; + } + break; + case SELECCION_MENU_CONFIG_WIFI_OTA_HABILITAR: + switch (currentButtonPressed) { + case BUTTON_STATUS_LEFT: + settings.wifiSettings.ota_enabled = pendingConfig.wifi.ota_enabled; + EEPROM_Schedule_Write(0); + newMenu = SELECCION_MENU_CONFIG_WIFI_HABILITAR; + break; + case BUTTON_STATUS_RIGHT: + settings.wifiSettings.ota_enabled = pendingConfig.wifi.ota_enabled; + EEPROM_Schedule_Write(0); + ESP8266Utils_clearWifiNetworksList(); newMenu = SELECCION_MENU_CONFIG_WIFI_SSID; break; case BUTTON_STATUS_DOWN: case BUTTON_STATUS_UP: - buzzer_sound_error(); + pendingConfig.wifi.ota_enabled = !pendingConfig.wifi.ota_enabled; break; } break; @@ -450,7 +473,7 @@ void pantalla_handleButtonInMenu( ESP8266Utils_getSsidAtIndex(currentIndex, pendingConfig.wifi.ssid); break; case BUTTON_STATUS_LEFT: - newMenu = SELECCION_MENU_CONFIG_WIFI; + newMenu = SELECCION_MENU_CONFIG_WIFI_OTA_HABILITAR; break; } break; @@ -470,10 +493,10 @@ void pantalla_handleButtonInMenu( if ((now - buttonHoldingTimeMs) >= LCD_HOLDING_TIME_CONFIRM_MS) { if (previousButtonHolding == BUTTON_STATUS_DOWN) { buzzer_sound_accept(); - newMenu = SELECCION_MENU_CONFIG_WIFI_RESULTADO; ESP8266Utils_connectToWifi( pendingConfig.wifi.ssid, pendingConfig.wifi.password); + newMenu = SELECCION_MENU_CONFIG_WIFI_RESULTADO; } } else { switch (previousButtonHolding) { @@ -511,25 +534,17 @@ void pantalla_handleButtonInMenu( break; } case SELECCION_MENU_CONFIG_WIFI_RESULTADO: { - static bool wifiCredentialStored = false; - if (ESP8266Utils_isWifiConnected()) { - if (!wifiCredentialStored) { - wifiCredentialStored = true; - memcpy(settings.wifiSettings.ssid_sta, - pendingConfig.wifi.ssid.c_str(), - sizeof(settings.wifiSettings.ssid_sta)); - memcpy(settings.wifiSettings.password_sta, - pendingConfig.wifi.password.c_str(), - sizeof(settings.wifiSettings.password_sta)); - EEPROM_Schedule_Write(100); - } - } else { - wifiCredentialStored = false; - } switch (currentButtonPressed) { case BUTTON_STATUS_RIGHT: if (ESP8266Utils_isWifiConnected()) { buzzer_sound_accept(); + memcpy(settings.wifiSettings.ssid_sta, + pendingConfig.wifi.ssid.c_str(), + sizeof(settings.wifiSettings.ssid_sta)); + memcpy(settings.wifiSettings.password_sta, + pendingConfig.wifi.password.c_str(), + sizeof(settings.wifiSettings.password_sta)); + EEPROM_Schedule_Write(0); newMenu = SELECCION_MENU_CONFIG_WIFI; } else { buzzer_sound_error(); @@ -550,7 +565,12 @@ void pantalla_handleButtonInMenu( } void pantalla_actualizarReloj(String* lcdBuffer) { - *lcdBuffer = " "; + if (ESP8266Utils_isWifiConnected()) { + *lcdBuffer = LCD_SPECIAL_CHAR_CONNECTED_SYMBOL; + } else { + *lcdBuffer = " "; + } + *lcdBuffer += " "; time_t now; struct tm* timeinfo; now = time(&now) + persistentVars_get_rtcTime().timezoneShift; @@ -568,17 +588,31 @@ void pantalla_actualizarReloj(String* lcdBuffer) { *lcdBuffer += String(timeinfo->tm_min); *lcdBuffer += String(" "); - uint8_t _localLength = String((int)MyWeather.TemperatureDegree).length(); - // Limit degree to 2 digits - if (_localLength < 4) { - for (int i = 0; i < (3 - _localLength); i++) { - *lcdBuffer += String(" "); - } - *lcdBuffer += String((int)MyWeather.TemperatureDegree); - *lcdBuffer += (char)223; - *lcdBuffer += String("C"); + if ((ESP8266Utils_get_errors() & WIFI_ERROR_WEATHER_UPDATE_FAILED_MASK)) { + *lcdBuffer += " "; + *lcdBuffer += LCD_SPECIAL_CHAR_WARNING_SYMBOL; } else { - *lcdBuffer += String(" "); + double temp; + if (ESP8266Utils_get_TemperatureDegree(&temp)) { + int t = (int)temp; + + if (t < 0) { + *lcdBuffer += " <0"; + } else if (t > 50) { + *lcdBuffer += ">50"; + } else { + *lcdBuffer += " "; + if (t < 10) { + *lcdBuffer += " "; // leading space for single digit + } + *lcdBuffer += String(t); + } + + *lcdBuffer += (char)223; // degree symbol + *lcdBuffer += "C"; + } else { + *lcdBuffer += " "; // blank when no data + } } if ((timeinfo->tm_mday) < 10) { @@ -782,6 +816,30 @@ void pantalla_actualizarMenuConfigWifi(String* lcdBuffer) { *lcdBuffer += String(" >"); } +void pantalla_actualizarMenuConfigWifiHabilitar(String* lcdBuffer) { + if (pendingConfig.wifi.enabled) { + *lcdBuffer += String(" WIFI : SI "); + } else { + *lcdBuffer += String(" WIFI : NO "); + } + *lcdBuffer += String("< "); + *lcdBuffer += LCD_SPECIAL_CHAR_UP_ARROW; + *lcdBuffer += LCD_SPECIAL_CHAR_DOWN_ARROW; + *lcdBuffer += String(" >"); +} + +void pantalla_actualizarMenuConfigWifiOTAHabilitar(String* lcdBuffer) { + if (pendingConfig.wifi.ota_enabled) { + *lcdBuffer += String(" WIFI OTA: SI "); + } else { + *lcdBuffer += String(" WIFI OTA: NO "); + } + *lcdBuffer += String("< "); + *lcdBuffer += LCD_SPECIAL_CHAR_UP_ARROW; + *lcdBuffer += LCD_SPECIAL_CHAR_DOWN_ARROW; + *lcdBuffer += String(" >"); +} + void pantalla_actualizarMenuConfigWifiPassword(String* lcdBuffer) { *lcdBuffer += String("PWD: "); @@ -971,6 +1029,12 @@ void pantalla_actualizarMenu(uint8_t selectedMenu) { case SELECCION_MENU_CONFIG_WIFI: pantalla_actualizarMenuConfigWifi(&lcdBuffer); break; + case SELECCION_MENU_CONFIG_WIFI_HABILITAR: + pantalla_actualizarMenuConfigWifiHabilitar(&lcdBuffer); + break; + case SELECCION_MENU_CONFIG_WIFI_OTA_HABILITAR: + pantalla_actualizarMenuConfigWifiOTAHabilitar(&lcdBuffer); + break; case SELECCION_MENU_CONFIG_WIFI_SSID: pantalla_actualizarMenuConfigWifiSsid(&lcdBuffer); break; diff --git a/Firmware_ESP8266/persistentVars.h b/Firmware_ESP8266/persistentVars.h index 490bca7..5520885 100644 --- a/Firmware_ESP8266/persistentVars.h +++ b/Firmware_ESP8266/persistentVars.h @@ -31,9 +31,15 @@ struct rtcTime_t { static_assert(sizeof(rtcTime_t) % 4 == 0, "rtcTime_t must be aligned to 4 bytes"); +struct weatherData_t { + double TemperatureDegree; // Temperature in degrees Celsius + // Other weather data can be added here in the future +}; + struct persistentVars_t { uint32_t softResetCount; struct rtcTime_t rtcTime; + struct weatherData_t weatherData; uint32_t magicWord; }; @@ -74,6 +80,21 @@ void persistentVars_store_rtcTime(const struct rtcTime_t* rtcTime) { struct rtcTime_t persistentVars_get_rtcTime(void) { return persistentVars_data.rtcTime; } +struct weatherData_t persistentVars_get_weatherData(void) { + return persistentVars_data.weatherData; +} + +void persistentVars_store_weatherData(const struct weatherData_t* weatherData) { + if (weatherData == nullptr) { + return; + } + + memcpy(&persistentVars_data.weatherData, weatherData, sizeof(struct weatherData_t)); + persistentVars_data.magicWord = PERSISTENTVARS_USER_MEMORY_MAGIC_WORD; + + ESP.rtcUserMemoryWrite(0, (uint32_t*)&persistentVars_data, sizeof(persistentVars_data)); +} + // This function initializes the persistent variables by reading them from no-init RAM. void persistentVars_init(void) { // This will just call persistentVars_is_stored() which will read the data from no-init RAM.