#include <WiFi.h>
#include <WebServer.h>
#include <DHTesp.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP32Servo.h>
// --- CONFIGURACIÓN DE PINES ---
#define PIN_DHT 15
#define PIN_RELAY_HEAT 26
#define PIN_RELAY_HUM 25
#define PIN_SERVO 19
#define PIN_BUZZER 27
#define PIN_LED_ERR 12
#define PIN_LED_WIFI 13
#define PIN_LED_OK 2
// --- PARÁMETROS ---
const double setpointT = 37.8;
const float humMinima = 53.0;
float tActual = 0, hActual = 0;
// --- OBJETOS ---
DHTesp dht;
Adafruit_SSD1306 display(128, 64, &Wire, -1);
Servo servoTurn;
WebServer server(80);
// --- DISEÑO DE LA PÁGINA WEB ---
String getHTML() {
String html = "<!DOCTYPE html><html lang='es'><head>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1' charset='utf-8'>";
html += "<meta http-equiv='refresh' content='3'>"; // Refresco cada 3 seg
html += "<title>Incubadora 30 Huevos - IoT</title>";
html += "<style>body{font-family:sans-serif; text-align:center; background:#eceff1; padding:20px;}";
html += ".card{background:white; padding:20px; border-radius:15px; display:inline-block; margin:10px; box-shadow:0 4px 6px rgba(0,0,0,0.1); min-width:180px;}";
html += "h1{color:#37474f;} .val{font-size:2.5em; font-weight:bold;} .t{color:#d32f2f;} .h{color:#1976d2;}";
html += ".status{margin-top:20px; font-size:1.2em; color:#455a64;}</style></head><body>";
html += "<h1>Control de Incubadora</h1>";
html += "<div class='card'><div class='val t'>" + String(tActual, 1) + "°C</div><div>Temperatura</div></div>";
html += "<div class='card'><div class='val h'>" + String(hActual, 0) + "%</div><div>Humedad</div></div>";
html += "<div class='status'>Calefactor: " + String((tActual < setpointT) ? "<b style='color:red'>ENCENDIDO</b>" : "APAGADO") + "</div>";
html += "</body></html>";
return html;
}
void handleRoot() {
server.send(200, "text/html", getHTML());
}
void setup() {
Serial.begin(115200);
// Configurar Pines
pinMode(PIN_RELAY_HEAT, OUTPUT);
pinMode(PIN_RELAY_HUM, OUTPUT);
pinMode(PIN_LED_WIFI, OUTPUT);
pinMode(PIN_LED_OK, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
// Lógica de seguridad inicial
digitalWrite(PIN_RELAY_HEAT, HIGH); // Apagado
digitalWrite(PIN_RELAY_HUM, HIGH);
// Sensores y Pantalla
dht.setup(PIN_DHT, DHTesp::DHT22);
servoTurn.attach(PIN_SERVO);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0,20);
display.print("Conectando WiFi...");
display.display();
// Iniciar WiFi
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
digitalWrite(PIN_LED_WIFI, HIGH);
server.on("/", handleRoot);
server.begin();
Serial.println("\n--- SISTEMA ONLINE ---");
Serial.print("IP Local: "); Serial.println(WiFi.localIP());
Serial.println("En Wokwi, haz click en el enlace que aparece arriba del monitor serial.");
}
void loop() {
server.handleClient();
TempAndHumidity data = dht.getTempAndHumidity();
if (!isnan(data.temperature)) {
tActual = data.temperature;
hActual = data.humidity;
}
// Lógica de Control
bool calentar = (tActual < setpointT);
digitalWrite(PIN_RELAY_HEAT, calentar ? LOW : HIGH);
digitalWrite(PIN_LED_OK, calentar ? HIGH : LOW);
digitalWrite(PIN_RELAY_HUM, (hActual < humMinima) ? LOW : HIGH);
// Movimiento del Servo (Volteo automático)
int pos = ((millis() / 10000) % 2 == 0) ? 45 : 135;
servoTurn.write(pos);
// Mostrar en Pantalla OLED
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.print("IP: "); display.print(WiFi.localIP());
display.setTextSize(2);
display.setCursor(0,25);
display.print("T:"); display.print(tActual, 1); display.print("C");
display.setCursor(0,48);
display.print("H:"); display.print(hActual, 0); display.print("%");
display.display();
delay(200);
}