Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions Firmware_ESP8266/EEPROM_Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down
189 changes: 189 additions & 0 deletions Firmware_ESP8266/ESP8266_Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
#define HTTP_SERVER_PING_ADDRESS "1.1.1.1"
#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)

extern struct Settings settings;
Expand All @@ -17,6 +22,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) {}
};

static std::vector<WifiNetworkInfo> wifiNetworks;
static bool wifiScanInProgress = false;
static unsigned long lastConnectAttemptMs = 0;

bool ESP8266Utils_Connect_STA(
const char* ssid,
const char* password,
Expand Down Expand Up @@ -141,3 +174,159 @@ 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 >= WIFI_SCAN_NOT_SEEN_MAX_COUNT) {
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 < WIFI_SCAN_MINIMUM_RSSI_FOR_TRACKING) {
// 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...");
Comment on lines +234 to +240
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disconnecting from WiFi when starting a scan could interrupt an existing connection that the user wants to maintain. Consider checking if a scan is actually needed before disconnecting.

Suggested change
if (WiFi.status() == WL_CONNECTED) {
WiFi.disconnect();
}
WiFi.mode(WIFI_STA);
WiFi.scanNetworks(true); // Async scan
wifiScanInProgress = true;
Serial.println("Started async WiFi scan...");
// Only scan if we have no known networks
if (wifiNetworks.empty()) {
if (WiFi.status() == WL_CONNECTED) {
WiFi.disconnect();
}
WiFi.mode(WIFI_STA);
WiFi.scanNetworks(true); // Async scan
wifiScanInProgress = true;
Serial.println("Started async WiFi scan...");
} else {
Serial.println("WiFi scan not needed: known networks present.");
}

Copilot uses AI. Check for mistakes.
}
}

// 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() > WIFI_SCAN_MAX_TRACKED_NETWORKS_COUNT) {
wifiNetworks.resize(WIFI_SCAN_MAX_TRACKED_NETWORKS_COUNT);
}

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());
}
}
}

bool ESP8266Utils_getSsidAtIndex(int index, String& outSsid) {
if (index < 0 || index >= static_cast<int>(wifiNetworks.size())) {
return false;
}
outSsid = wifiNetworks[index].ssid;
return true;
}

int ESP8266Utils_getTrackedNetworkCount() { return static_cast<int>(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<int>(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() {}
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Wifi_handler() function is empty but is called in the main loop. Either implement the function or remove it to avoid unnecessary function calls.

Suggested change
void Wifi_handler() {}

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty function implementation that is called from the main loop serves no purpose and should either be implemented or removed to avoid confusion.

Suggested change
void Wifi_handler() {}

Copilot uses AI. Check for mistakes.
1 change: 1 addition & 0 deletions Firmware_ESP8266/Firmware_ESP8266.ino
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,5 @@ void loop() {
buzzer_handler();
shutterHandler();
EEPROM_Handler();
Wifi_handler();
}
3 changes: 3 additions & 0 deletions Firmware_ESP8266/basic_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
Loading
Loading