// https://www.hivemq.com/mqtt/public-mqtt-broker/
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Configuración OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Configuración DHT11/22
#define DHTPIN 14
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// Configuración LEDs
#define LED1_PIN 25
#define LED2_PIN 26
// Configuración Pulsador
#define BUTTON_PIN 27
int currentScreen = 0;
const int totalScreens = 4;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 200;
bool lastButtonState = HIGH;
// Configuración WiFi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Configuración MQTT (HiveMQ)
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char* temp_topic = "profelopera/dht11/temperatura";
const char* hum_topic = "profelopera/dht11/humedad";
const char* led1_topic = "profelopera/led1/control";
const char* led2_topic = "profelopera/led2/control";
WiFiClient espClient;
PubSubClient client(espClient);
// Variables globales
unsigned long lastMsg = 0;
int counter = 0;
float temperatura = 0;
float humedad = 0;
// Función para conectar WiFi
void setup_wifi() {
delay(10);
Serial.println("\nConectando a WiFi: " + String(ssid));
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✅ WiFi conectado");
Serial.print("📡 IP: ");
Serial.println(WiFi.localIP());
Serial.print("📶 RSSI: ");
Serial.println(WiFi.RSSI());
Serial.print("🖧 MAC: ");
Serial.println(WiFi.macAddress());
}
// Función para conectar MQTT
void reconnect_mqtt() {
while (!client.connected()) {
Serial.print("Conectando a MQTT...");
String clientId = "ESP32profeLopera-" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) {
Serial.println("✅ Conectado a HiveMQ");
client.subscribe(led1_topic);
client.subscribe(led2_topic);
Serial.println("📡 Suscrito a topics de control");
} else {
Serial.print("❌ Falló, rc=");
Serial.print(client.state());
Serial.println(" Reintentando en 5 segundos");
delay(5000);
}
}
}
// Callback para mensajes MQTT entrantes
void callback(char* topic, byte* payload, unsigned int length) {
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.print("📨 Mensaje recibido en: ");
Serial.print(topic);
Serial.print(" -> ");
Serial.println(message);
if (String(topic) == led1_topic) {
if (message == "ON") { digitalWrite(LED1_PIN, HIGH); Serial.println("💡 LED 1 ENCENDIDO"); }
else if (message == "OFF") { digitalWrite(LED1_PIN, LOW); Serial.println("💡 LED 1 APAGADO"); }
}
if (String(topic) == led2_topic) {
if (message == "ON") { digitalWrite(LED2_PIN, HIGH); Serial.println("💡 LED 2 ENCENDIDO"); }
else if (message == "OFF") { digitalWrite(LED2_PIN, LOW); Serial.println("💡 LED 2 APAGADO"); }
}
}
// Función para leer pulsador con debounce
void check_button() {
bool buttonState = digitalRead(BUTTON_PIN);
if (buttonState == LOW && lastButtonState == HIGH) {
unsigned long now = millis();
if (now - lastDebounceTime > debounceDelay) {
lastDebounceTime = now;
currentScreen = (currentScreen + 1) % totalScreens;
Serial.println("🔘 Pantalla: " + String(currentScreen));
update_display();
}
}
lastButtonState = buttonState;
}
// Función para actualizar OLED
void update_display() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Indicador de pantalla (esquina superior derecha)
display.setCursor(100, 0);
display.print("P:");
display.print(currentScreen + 1);
display.print("/");
display.println(totalScreens);
switch (currentScreen) {
case 0: // ── PANTALLA 1: Info WiFi + Sensores + LEDs (original) ──
display.setCursor(0, 0);
display.println("=== WiFi Info ===");
display.print("");
display.println(ssid);
display.print("");
display.print(WiFi.localIP());
display.print(" (");
display.print(WiFi.RSSI());
display.println(" dBm)");
display.print("MAC ");
display.println(WiFi.macAddress());
display.println("=== Sensores ===");
display.print("T: ");
display.print(temperatura, 1);
display.print("C H: ");
display.print(humedad, 0);
display.println("%");
display.println("=== Actuadores ===");
display.print("LED1: ");
display.print(digitalRead(LED1_PIN) ? "ON " : "OFF");
display.print(" LED2: ");
display.println(digitalRead(LED2_PIN) ? "ON " : "OFF");
break;
case 1: // ── PANTALLA 2: Vacía — agrega tu contenido aquí ──
display.setCursor(0, 0);
// TODO: Agrega aquí el contenido de la pantalla 2
// Ejemplo:
// display.println("=== Mi Pantalla 2 ===");
// display.print("Variable: ");
// display.println(miVariable);
display.println("=== Sensores ===");
display.print("T: ");
display.print(temperatura, 1);
display.print("C H: ");
display.print(humedad, 0);
display.println("%");
break;
case 2: // ── PANTALLA 3: Vacía — agrega tu contenido aquí ──
display.setCursor(0, 0);
// TODO: Agrega aquí el contenido de la pantalla 3
// Ejemplo:
// display.println("=== Mi Pantalla 3 ===");
// display.print("Dato: ");
// display.println(miDato);
display.println("=== Actuadores ===");
display.print("LED1: ");
display.print(digitalRead(LED1_PIN) ? "ON " : "OFF");
display.print(" LED2: ");
display.println(digitalRead(LED2_PIN) ? "ON " : "OFF");
break;
case 3: // ── PANTALLA 4: Vacía — agrega tu contenido aquí ──
display.setCursor(0, 0);
// TODO: Agrega aquí el contenido de la pantalla 4
// Ejemplo:
// display.println("=== Mi Pantalla 4 ===");
// display.print("Info: ");
// display.println(miInfo);
display.setCursor(0, 0);
display.println("=== WiFi Info ===");
display.print("");
display.println(ssid);
display.print("");
display.print(WiFi.localIP());
display.print(" (");
display.print(WiFi.RSSI());
display.println(" dBm)");
display.print("MAC ");
display.println(WiFi.macAddress());
break;
}
display.display();
}
void setup() {
Serial.begin(115200);
// Inicializar LEDs
pinMode(LED1_PIN, OUTPUT);
pinMode(LED2_PIN, OUTPUT);
digitalWrite(LED1_PIN, LOW);
digitalWrite(LED2_PIN, LOW);
// Inicializar Pulsador
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Inicializar OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println("❌ Error en OLED");
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Iniciando...");
display.display();
// Inicializar DHT
dht.begin();
// Conectar WiFi
setup_wifi();
// Configurar MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
update_display();
}
void loop() {
// Mantener conexión MQTT
if (!client.connected()) {
reconnect_mqtt();
}
client.loop();
// Leer pulsador
check_button();
// Enviar datos cada 3 segundos
unsigned long now = millis();
if (now - lastMsg > 3000) {
lastMsg = now;
counter++;
temperatura = dht.readTemperature();
humedad = dht.readHumidity();
if (isnan(temperatura) || isnan(humedad)) {
Serial.println("❌ Error leyendo DHT");
temperatura = 0;
humedad = 0;
}
Serial.print("🌡️ Temperatura: "); Serial.print(temperatura);
Serial.print(" °C - 💧 Humedad: "); Serial.print(humedad);
Serial.print(" % - ");
char tempStr[8], humStr[8];
dtostrf(temperatura, 1, 2, tempStr);
dtostrf(humedad, 1, 2, humStr);
client.publish(temp_topic, tempStr);
client.publish(hum_topic, humStr);
client.publish("profelopera/network/ssid", ssid);
client.publish("profelopera/network/ip", WiFi.localIP().toString().c_str());
client.publish("profelopera/network/rssi", String(WiFi.RSSI()).c_str());
client.publish("profelopera/network/mac", WiFi.macAddress().c_str());
Serial.print("✅ MQTT - ");
Serial.println("📊 Contador: " + String(counter));
update_display();
}
delay(100);
}