// Configuración WiFi
// const char* ssid = "Wokwi-GUEST";
// const char* password = "";
/*
Instrucciones de conexión de la pantalla
0.96 inch SSD1306 OLED display
Screen ESP32
Vin --> 3.3V
GND --> GND
SCL --> GPIO 22
SDA --> GPIO 21
*/
/* * PROYECTO: Smart Farm - Panel de Control Optimizado
* AUTOR: Ramiro Lopera
* HARDWARE: ESP32, DHT11, OLED SSD1306, Relé (Bomba), Servo (Cerradura)
*/
// --- LIBRERÍAS ---
#include <myimages.h>
#include "DHT.h"
#include <Wire.h>
#include <WiFi.h>
#include <WebServer.h>
#include <Adafruit_SSD1306.h>
#include <ESP32Servo.h>
// Datos de red
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// --- CONFIGURACIÓN DE PINES (GPIO) ---
const int LuzSala = 27;
const int LuzPuerta = 26;
const int BombaRiego = 25;
const int PinServo = 33;
#define DHTPIN 32
#define DHTTYPE DHT22
// --- OBJETOS Y VARIABLES GLOBALES ---
DHT DatosDHT(DHTPIN, DHTTYPE);
Servo CerraduraCorral;
WebServer server(80);
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Variables de estado
bool EstadoLuzSala = false;
bool EstadoLuzPuerta = false;
bool EstadoBomba = false;
bool EstadoCerradura = false;
// Variables de caché para el DHT (Mejora de eficiencia)
float tempCache = 0.0;
int humCache = 0;
// Gestión de tiempo
unsigned long tiempoAnterior = 0;
const long intervalo = 10000;
// --- SETUP ---
void setup() {
Serial.begin(115200);
DatosDHT.begin();
// Configuración de salidas
pinMode(LuzSala, OUTPUT);
pinMode(LuzPuerta, OUTPUT);
pinMode(BombaRiego, OUTPUT);
// Estado inicial
digitalWrite(LuzSala, LOW);
digitalWrite(LuzPuerta, LOW);
digitalWrite(BombaRiego, LOW);
// Inicializar Servo
CerraduraCorral.attach(PinServo);
CerraduraCorral.write(0);
// Iniciar OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Error OLED"));
while (true);
}
display.setRotation(2);
ActualizaPantalla();
// Conectar WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(WiFi.localIP());
// RUTAS DEL SERVIDOR (AJAX para privacidad de URL)
server.on("/", ActualizaServidor);
server.on("/L1", AccionLuz);
server.on("/L2", AccionPuerta);
server.on("/L3", AccionBomba);
server.on("/L4", AccionCerradura);
server.begin();
Serial.println(F("Servidor Online"));
}
// --- BUCLE PRINCIPAL ---
void loop() {
server.handleClient();
unsigned long tiempoActual = millis();
if (tiempoActual - tiempoAnterior >= intervalo) {
tiempoAnterior = tiempoActual;
LecturaEficienteDHT();
ActualizaPantalla();
}
}
// --- FUNCIONES ---
void LecturaEficienteDHT() {
float h = DatosDHT.readHumidity();
float t = DatosDHT.readTemperature();
if (!isnan(h) && !isnan(t)) {
humCache = (int)h;
tempCache = t;
} else {
Serial.println(F("Error de lectura DHT"));
}
}
void ActualizaPantalla() {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// Iconos
display.drawBitmap(5, 2, EstadoLuzSala ? luz_on : luz_off, 15, 20, 1);
display.drawBitmap(30, 2, EstadoLuzPuerta ? puerta_on : puerta_off, 15, 20, 1);
display.drawBitmap(55, 2, EstadoBomba ? aire_on : aire_off, 15, 20, 1);
display.drawBitmap(80, 2, EstadoCerradura ? Cerradura_on : Cerradura_off, 15, 20, 1);
// Clima
display.setCursor(15, 25);
display.setTextSize(2); display.print(tempCache, 1);
display.setTextSize(1); display.print((char)247); display.print("C");
display.setCursor(95, 25);
display.setTextSize(2); display.print(humCache);
display.setTextSize(1); display.print("%");
// Red
display.setCursor(0, 48); display.print(WiFi.SSID());
display.setCursor(0, 56); display.print("IP: "); display.print(WiFi.localIP());
display.display();
}
void ActualizaServidor() {
String p;
p.reserve(3000);
p = F("<html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1'>");
p += F("<script>");
p += F("function cmd(r){fetch(r).then(()=>setTimeout(()=>location.reload(),150));}");
p += F("</script>");
p += F("<style>body{font-family:Arial;text-align:center;} button{border:none;background:none;cursor:pointer;}</style>");
p += F("</head><body>");
p += F("<h3>Smart Farm - Panel de Control</h3>");
p += F("<table align='center' width='100%'><tr>");
p += "<td>Luz<br><button onclick=\"cmd('/L1')\"><img src='" + String(EstadoLuzSala ? luzON : luzOFF) + "' width='80'></button></td>";
p += "<td>Puerta<br><button onclick=\"cmd('/L2')\"><img src='" + String(EstadoLuzPuerta ? puertaON : puertaOFF) + "' width='80'></button></td>";
p += "<td>Bomba<br><button onclick=\"cmd('/L3')\"><img src='" + String(EstadoBomba ? aireON : aireOFF) + "' width='80'></button></td>";
p += "<td>Cerradura<br><button onclick=\"cmd('/L4')\"><img src='" + String(EstadoCerradura ? CerraduraON : CerraduraOFF) + "' width='80'></button></td>";
p += F("</tr></table><br>");
p += F("<table align='center' style='font-size:30pt;'><tr>");
p += "<td>" + String(tempCache, 1) + "°C</td>";
p += "<td><img src='" + String(Weather) + "' width='100'></td>";
p += "<td>" + String(humCache) + "%</td>";
p += F("</tr></table>");
p += F("<p>WiFi: "); p += String(WiFi.RSSI()); p += F(" dBm | MAC: "); p += WiFi.macAddress(); p += F("</p>");
p += F("</body></html>");
server.send(200, "text/html", p);
}
void AccionLuz() {
EstadoLuzSala = !EstadoLuzSala;
digitalWrite(LuzSala, EstadoLuzSala);
ActualizaPantalla();
server.send(204);
}
void AccionPuerta() {
EstadoLuzPuerta = !EstadoLuzPuerta;
digitalWrite(LuzPuerta, EstadoLuzPuerta);
ActualizaPantalla();
server.send(204);
}
void AccionBomba() {
EstadoBomba = !EstadoBomba;
digitalWrite(BombaRiego, EstadoBomba);
ActualizaPantalla();
server.send(204);
}
void AccionCerradura() {
EstadoCerradura = !EstadoCerradura;
if (EstadoCerradura) CerraduraCorral.write(90);
else CerraduraCorral.write(0);
ActualizaPantalla();
server.send(204);
}