#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h> // Necesario para I2C (LCD)
#include <LiquidCrystal_I2C.h> // Para el LCD I2C
// --- Configuración WiFi ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// --- Configuración Pines (SEGÚN TU DIAGRAM.JSON VERIFICADO) ---
const int LED_VERDE_PIN = 4; // Pin para LED Verde (Todo OK) - Conectado a D4
const int LED_ROJO_PIN = 2; // Pin para LED Rojo (Fallo) - Conectado a D2
// LCD I2C usa SDA (GPIO21) y SCL (GPIO22) por defecto
// --- Configuración Monitoreo ---
// URLs de los servicios a monitorear
// RECUERDA: URLs externas requieren Wokwi Gateway ejecutándose en tu PC.
// Alternativa: Simula servidores web en otros ESP32 dentro de Wokwi.
const char* targets[] = {
"http://detectportal.firefox.com/success.txt", // Suele devolver 200 OK rápido
"http://httpbin.org/delay/2", // Servicio que responde después de 2 segundos
"http://google.com", // Ejemplo externo (necesita Gateway)
"http://esto-no-existe-probablemente.xyz" // Ejemplo de host inexistente
};
const int NUM_TARGETS = sizeof(targets) / sizeof(targets[0]);
bool target_status[NUM_TARGETS]; // Array para guardar estado (true=ONLINE, false=OFFLINE)
// Intervalo de chequeo (en milisegundos)
const unsigned long CHECK_INTERVAL_MS = 30000; // Chequear cada 30 segundos
unsigned long previousMillis = 0;
// --- Objetos ---
HTTPClient http;
// LCD: Cambia 0x27 por 0x3F si tu LCD usa esa dirección
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool lcd_present = false;
// =========================================================================
// SETUP - Se ejecuta una vez al inicio
// =========================================================================
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); } // Esperar a que el Serial esté listo
Serial.println("\nIniciando Monitor de Servicios v1.0...");
// Configurar LEDs
pinMode(LED_VERDE_PIN, OUTPUT);
pinMode(LED_ROJO_PIN, OUTPUT);
digitalWrite(LED_VERDE_PIN, LOW); // Apagados inicialmente
digitalWrite(LED_ROJO_PIN, LOW);
// Inicializar LCD
Wire.begin(); // Iniciar I2C (SDA=21, SCL=22 por defecto en ESP32)
Wire.beginTransmission(0x27); // Intentar comunicar con la dirección del LCD
if (Wire.endTransmission() == 0) { // 0 = Dispositivo encontrado (ACK)
Serial.println("LCD I2C Encontrado en 0x27.");
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Monitor Red");
lcd.setCursor(0, 1);
lcd.print("Iniciando...");
lcd_present = true;
} else {
Serial.println("LCD I2C NO Encontrado en 0x27. Verifica direccion/conexion.");
// Podrías intentar con 0x3F aquí si es necesario
}
// Conectar a WiFi
connectWiFi();
// Estado inicial: chequear targets por primera vez
if (WiFi.status() == WL_CONNECTED) {
Serial.println("Realizando chequeo inicial...");
checkTargets();
updateStatusDisplay();
previousMillis = millis(); // Iniciar temporizador para próximos chequeos
} else {
Serial.println("No conectado a WiFi. No se puede realizar chequeo inicial.");
digitalWrite(LED_ROJO_PIN, HIGH); // Indicar error de conexión WiFi
if(lcd_present) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Error WiFi");
}
}
}
// =========================================================================
// LOOP PRINCIPAL - Se ejecuta repetidamente
// =========================================================================
void loop() {
// Solo chequear si estamos conectados a WiFi
if (WiFi.status() == WL_CONNECTED) {
unsigned long currentMillis = millis();
// Es tiempo de chequear de nuevo?
if (currentMillis - previousMillis >= CHECK_INTERVAL_MS) {
previousMillis = currentMillis; // Resetear temporizador
Serial.println("\n--- Realizando chequeo periódico ---");
checkTargets();
updateStatusDisplay();
}
} else {
// Intentar reconectar si se pierde la conexión
Serial.println("WiFi desconectado. Intentando reconectar...");
digitalWrite(LED_VERDE_PIN, LOW); // Apagar LED verde si estaba encendido
digitalWrite(LED_ROJO_PIN, HIGH); // Encender LED rojo
if(lcd_present) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Reconectando...");
}
connectWiFi();
if(WiFi.status() != WL_CONNECTED) {
delay(5000); // Esperar antes de reintentar conexión
} else {
// Si reconecta, forzar un chequeo inmediato
previousMillis = millis() - CHECK_INTERVAL_MS; // Truco para forzar chequeo en la siguiente iteración
}
}
// Pequeña pausa para ceder tiempo a otros procesos (WiFi, etc.)
delay(100);
}
// =========================================================================
// FUNCIONES AUXILIARES
// =========================================================================
// --- Conexión WiFi ---
void connectWiFi() {
Serial.print("Conectando a WiFi '");
Serial.print(ssid);
Serial.print("'...");
WiFi.mode(WIFI_STA); // Modo Estación
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
attempts++;
if (attempts > 20) { // Timeout de conexión (10 segundos)
Serial.println("\nFallo al conectar a WiFi!");
return; // Salir si no conecta
}
}
Serial.println("\nConectado a WiFi!");
Serial.print("Dirección IP: ");
Serial.println(WiFi.localIP());
}
// --- Chequeo de Targets ---
void checkTargets() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Error: Se perdió WiFi antes de chequear.");
return; // No chequear si no hay WiFi
}
for (int i = 0; i < NUM_TARGETS; i++) {
Serial.print("Chequeando [");
Serial.print(targets[i]);
Serial.print("]... ");
// Configurar cliente HTTP
// WiFiClient client; // Necesario si http.begin() toma un cliente
// http.begin(client, targets[i]); // Algunas versiones necesitan el cliente
http.begin(targets[i]); // Versión más común
http.setTimeout(5000); // Timeout de 5 segundos
int httpCode = 0;
String payload = ""; // Para guardar la respuesta si fuera necesaria
// Intentar petición GET
httpCode = http.GET();
if (httpCode > 0) {
// Código HTTP recibido
Serial.print("HTTP CODE: ");
Serial.print(httpCode);
// Consideramos ONLINE si es 2xx (Éxito) o 3xx (Redirección)
if (httpCode >= HTTP_CODE_OK && httpCode < HTTP_CODE_MULTIPLE_CHOICES + 100 ) { // Códigos 200-399
Serial.println(" -> ONLINE");
target_status[i] = true;
} else {
Serial.println(" -> OFFLINE (Codigo Error HTTP)");
target_status[i] = false;
}
// Opcional: leer payload para liberar buffers
// payload = http.getString();
// Serial.print("Payload len: "); Serial.println(payload.length());
} else {
// Error < 0: Fallo en conexión o envío
Serial.print(" -> OFFLINE (Error: ");
Serial.print(http.errorToString(httpCode).c_str());
Serial.println(")");
target_status[i] = false;
}
http.end(); // Liberar recursos
delay(100); // Pequeña pausa entre chequeos de diferentes targets
}
}
// --- Actualizar Displays (Serial, LEDs, LCD) ---
void updateStatusDisplay() {
Serial.println("\n--- Estado Actual ---");
bool all_online = true;
int offline_count = 0;
// Preparar string para LCD
String lcd_line0 = "";
String lcd_line1 = "";
for (int i = 0; i < NUM_TARGETS; i++) {
Serial.print("Target ");
Serial.print(i + 1);
// Extraer nombre corto para display (opcional)
String targetName = String(targets[i]);
targetName.replace("http://", "");
targetName.replace("https://", "");
int slashPos = targetName.indexOf('/');
if (slashPos != -1) targetName = targetName.substring(0, slashPos);
if (targetName.length() > 8) targetName = targetName.substring(0, 8); // Acortar si es largo
Serial.print(" (");
Serial.print(targetName);
Serial.print("): ");
if (target_status[i]) {
Serial.println("ONLINE");
// Añadir al display LCD si está ONLINE (ej. O=OK, X=Fail)
if(i < 8) lcd_line0 += "O"; else lcd_line1 += "O"; // Simple OK indicator
} else {
Serial.println("OFFLINE");
all_online = false; // Marcar que al menos uno falló
offline_count++;
if(i < 8) lcd_line0 += "X"; else lcd_line1 += "X"; // Simple Fail indicator
}
// Añadir espacio para separar indicadores en LCD
if(i < 7) lcd_line0 += " ";
if(i >=8 && i < 15) lcd_line1 += " ";
}
Serial.println("--------------------");
// Actualizar LEDs
if (all_online) {
digitalWrite(LED_VERDE_PIN, HIGH);
digitalWrite(LED_ROJO_PIN, LOW);
Serial.println("[STATUS] Todo OK");
} else {
digitalWrite(LED_VERDE_PIN, LOW);
digitalWrite(LED_ROJO_PIN, HIGH);
Serial.println("[STATUS] Alerta! Algun servicio OFFLINE");
}
// Actualizar LCD
if (lcd_present) {
lcd.clear();
lcd.setCursor(0, 0);
// Mostrar indicadores O/X (hasta 8 en cada línea)
lcd.print(lcd_line0.substring(0,15)); // Max 16 chars
lcd.setCursor(0, 1);
lcd.print(lcd_line1.substring(0,15)); // Max 16 chars
// Mostrar contador de offline en esquina si hay fallos
if (offline_count > 0) {
lcd.setCursor(13, 1); // Esquina inferior derecha
lcd.print(offline_count);
lcd.print(" F"); // F de Fallo
} else {
lcd.setCursor(13, 1);
lcd.print("OK");
}
}
}