Ir al contenido

Arquitectura del Sketch Básico

Arquitectura del Sketch Básico

Esta sección presenta la arquitectura completa del “Sketch Básico” que combina conexión Wi-Fi, comunicación MQTT y temporización no bloqueante. Al finalizar esta sección, podrás:

  • Entender la estructura de proyecto multi-archivo de un sketch ESP32 en PlatformIO
  • Implementar el sketch básico canónico de Wi-Fi + MQTT que sirve como base para todos los proyectos del curso
  • Organizar el código ESP32 en módulos funcionales (Wi-Fi, MQTT, sensores, main)
  • Implementación de conexión Wi-Fi (01-09)
  • Configuración del cliente MQTT (01-10)
  • Configuración del IDE PlatformIO (01-05)

Todos los proyectos IoT de este curso siguen el mismo patrón arquitectónico:

┌──────────────────────────────────────────────────┐
│ main.cpp │
│ setup() → init serial → conectar WiFi → │
│ init MQTT → init sensores │
│ loop() → mantener MQTT → leer sensores → │
│ publicar datos → retardos no bloqueantes│
└──────────────────────────────────────────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌──────────┐ ┌──────────────┐
│ wifi_mqtt.h │ │credentials.h│ │ sensor.h │
│ - Conectar WiFi │ │ - SSID │ │ - leer datos │
│ - Callback MQTT │ │ - Contraseña│ │ - procesar │
│ - Reconexión │ │ - Broker │ │ - formatear │
└─────────────────┘ └──────────┘ └──────────────┘

Esta separación de responsabilidades significa:

  • El código Wi-Fi/MQTT es reutilizable entre proyectos
  • Las credenciales están aisladas en un solo archivo (excluido del control de versiones)
  • La lógica de sensores es modular e intercambiable
  • main.cpp es el orquestador, no la implementación
basic-sketch/
├── platformio.ini # Placa, framework, librerías
└── src/
├── main.cpp # Orquestación de setup() y loop()
├── wifi_mqtt.h # Funciones de conexión Wi-Fi y MQTT
└── credentials.h # SSID, contraseña, dirección del broker
  1. Crea un nuevo proyecto PlatformIO: esp32-basic-sketch
  2. Placa: Espressif ESP32 Dev Module
  3. Framework: Arduino
  4. Agrega a platformio.ini:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps =
knolleary/PubSubClient @ ^2.8
bblanchon/ArduinoJson @ ^7.0
#ifndef CREDENTIALS_H
#define CREDENTIALS_H
// Wi-Fi
const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";
// Broker MQTT
const char* mqttServer = "192.168.1.100";
const int mqttPort = 1883;
const char* mqttUser = ""; // Dejar vacío si no hay autenticación
const char* mqttPassword = "";
#endif
#ifndef WIFI_MQTT_H
#define WIFI_MQTT_H
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
// Declaraciones anticipadas
void connectToWiFi();
void connectToMQTT();
void mqttCallback(char* topic, byte* payload, unsigned int length);
void sendMQTTValues();
// Objetos de cliente Wi-Fi y cliente MQTT
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
// Identificador del cliente
const char* clientId = "esp32-basic";
// Topics MQTT
const char* topicPublish = "esp32/data";
const char* topicSubscribe = "esp32/commands";
void connectToWiFi() {
Serial.print("Connecting to Wi-Fi");
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 40) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println();
Serial.println("Wi-Fi connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println();
Serial.println("Wi-Fi connection failed!");
Serial.println("Restarting in 2 seconds...");
delay(2000);
ESP.restart();
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("MQTT message arrived [");
Serial.print(topic);
Serial.print("]: ");
String message = "";
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// Enrutamiento por topic
if (String(topic) == "esp32/commands") {
if (message == "ON") {
Serial.println("Command: ON");
// Agrega tu lógica de ON aquí
} else if (message == "OFF") {
Serial.println("Command: OFF");
// Agrega tu lógica de OFF aquí
}
}
}
void connectToMQTT() {
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(mqttCallback);
while (!mqttClient.connected()) {
Serial.print("Attempting MQTT connection...");
if (mqttClient.connect(clientId, mqttUser, mqttPassword)) {
Serial.println("connected!");
// Suscribirse a los topics
mqttClient.subscribe(topicSubscribe);
// Publicar estado en línea
mqttClient.publish("esp32/status", "online");
} else {
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" retrying in 5 seconds");
delay(5000);
}
}
}
#endif
#include <Arduino.h>
#include "credentials.h"
#include "wifi_mqtt.h"
// Constantes
const unsigned long PUBLISH_INTERVAL = 5000; // Publicar cada 5 segundos
const int LED_PIN = 2; // LED integrado en la mayoría de los DevKits
// Variables globales
unsigned long previousMillis = 0;
int ledState = LOW;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("ESP32 Basic Sketch");
Serial.println("=================");
// Inicializar hardware
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Conectar a Wi-Fi
connectToWiFi();
// Conectar a MQTT
connectToMQTT();
}
void loop() {
unsigned long currentMillis = millis();
// 1. Mantener la conexión MQTT (debe llamarse con frecuencia)
if (!mqttClient.connected()) {
// Verificar Wi-Fi primero
if (WiFi.status() != WL_CONNECTED) {
connectToWiFi();
}
connectToMQTT();
}
mqttClient.loop();
// 2. Parpadeo de LED no bloqueante (indicador de estado)
digitalWrite(LED_PIN, ledState);
// 3. Publicación periódica de datos
if (currentMillis - previousMillis >= PUBLISH_INTERVAL) {
previousMillis = currentMillis;
// Alternar el LED en cada publicación
ledState = !ledState;
// Publicar datos del sensor
sendMQTTValues();
}
}
void sendMQTTValues() {
// Simular datos del sensor (reemplazar con lecturas reales)
int temperature = random(20, 35);
int humidity = random(40, 80);
// Crear payload JSON
String payload = "{\"temperature\":";
payload += temperature;
payload += ",\"humidity\":";
payload += humidity;
payload += "}";
// Publicar en el topic MQTT
if (mqttClient.publish(topicPublish, payload.c_str())) {
Serial.print("Published: ");
Serial.println(payload);
} else {
Serial.println("Publish failed!");
}
}
  1. Encendido: El ESP32 inicia y ejecuta setup()
  2. Inicio Serial: El puerto serial se abre a 115200 baudios
  3. Inicio del LED: El pin del LED integrado se configura como salida
  4. Conexión Wi-Fi: Se conecta a la red Wi-Fi (reintenta hasta 40 veces = ~20 segundos)
  5. Conexión MQTT: Se conecta al broker MQTT y se suscribe al topic de comandos
  6. Inicio del Loop: Entra al bucle principal
  7. Mantenimiento MQTT: Llama a client.loop() para procesar mensajes entrantes y mantener viva la conexión
  8. Verificación del Temporizador: Cada 5 segundos, publica datos simulados del sensor
  9. Alternancia del LED: El LED integrado se alterna con cada publicación (indicador visual de latido)
  1. Carga el sketch en el ESP32
  2. Abre el Monitor Serial (115200 baudios)
  3. Observa la secuencia de conexión
  4. Verifica que los mensajes “Published” aparezcan cada 5 segundos
  5. Desde una línea de comandos, suscríbete para recibir datos:
    Ventana de terminal
    mosquitto_sub -h 192.168.1.100 -t "esp32/data"
  6. Envía un comando:
    Ventana de terminal
    mosquitto_pub -h 192.168.1.100 -t "esp32/commands" -m "ON"
  • El Monitor Serial muestra la secuencia completa de conexión (Wi-Fi → MQTT)
  • Los datos se publican cada 5 segundos en el topic MQTT correcto
  • El LED integrado se alterna con cada publicación (confirmación visual)
  • El suscriptor MQTT recibe los payloads JSON correctamente
  • El envío de un comando mediante mosquitto_pub se recibe en el callback
  • La desconexión y reconexión del broker se recupera automáticamente

El sketch no inicia, solo aparece “Connecting to Wi-Fi”

Sección titulada «El sketch no inicia, solo aparece “Connecting to Wi-Fi”»

Causas: Credenciales Wi-Fi incorrectas o el router no es alcanzable.

Soluciones:

  1. Verifica el SSID y la contraseña en credentials.h
  2. Verifica que el router esté encendido y transmitiendo
  3. Verifica que el ESP32 esté dentro del alcance
  4. Verifica 2.4 GHz vs 5 GHz: el ESP32 solo soporta 2.4 GHz

Causas:

  • El temporizador del intervalo de publicación no se reinicia
  • El cliente MQTT se desconectó sin detección

Soluciones:

  1. Verifica que PUBLISH_INTERVAL esté configurado a un valor razonable (5000 ms)
  2. Verifica que mqttClient.connected() devuelva true
  3. Asegúrate de que mqttClient.loop() se llame en cada iteración
  4. Usa el valor de retorno de mqttClient.publish() para detectar fallas

El ESP32 se desconecta del Wi-Fi después de algunas horas

Sección titulada «El ESP32 se desconecta del Wi-Fi después de algunas horas»

Causas:

  • Tiempo de espera del arrendamiento DHCP del router
  • Interferencia de radio Wi-Fi
  • Problemas de fuente de alimentación

Soluciones:

  1. Habilita la reconexión automática: WiFi.setAutoReconnect(true) en setup()
  2. Agrega una verificación periódica del estado de Wi-Fi en loop()
  3. Implementa un temporizador de vigilancia (watchdog, integrado en el ESP32) que reinicie si la conexión se pierde por más de 5 minutos
  • Comienza cada proyecto nuevo desde este Sketch Básico: Proporciona infraestructura comprobada de Wi-Fi, MQTT y temporización
  • Usa la estructura multi-archivo: Separa credenciales, Wi-Fi/MQTT y lógica de sensores en archivos diferentes
  • Implementa el patrón no bloqueante: Nunca uses delay() para temporización en código de producción
  • Agrega un LED de estado: Un LED de latido (que se alterna en cada publicación de datos) proporciona retroalimentación visual inmediata
  • Registra todos los cambios de estado de conexión: Esto ayuda a diagnosticar problemas en campo de forma remota
  • Usa random() o datos ficticios inicialmente: Haz que la capa de comunicación funcione antes de agregar sensores reales
  1. La arquitectura del Sketch Básico separa responsabilidades en main.cpp, wifi_mqtt.h y credentials.h
  2. La función loop() mantiene MQTT, verifica temporizadores, publica datos y maneja callbacks
  3. La lógica de reconexión de Wi-Fi y MQTT asegura robustez ante interrupciones de red
  4. La temporización no bloqueante con millis() permite múltiples tareas concurrentes
  5. Esta arquitectura es la base de todos los proyectos posteriores del curso

¿Desarrollas un producto IoT comercial?

Ofrecemos servicios ODM de ESP32, del diseño a la fabricación. Del prototipo a la producción: el equipo detrás de este tutorial puede construirlo contigo.

Hablemos →