ESP32 y Arduino

Tutorial ESP32-C6 MQTT: de una placa Wi-Fi 6 a un broker en la nube con Arduino

Haz que un ESP32-C6 publique en broker.connectmq.com con el core de Arduino 3.x, controla su LED RGB desde la línea de comandos y entiende las diferencias con el ESP32 clásico de doble núcleo.

Placa ESP32-C6 DevKitC-1 con un LED RGB encendido conectada a un broker en la nube en un tutorial esp32-c6 mqtt
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Este tutorial ESP32-C6 MQTT consigue que una placa C6 publique telemetría y reciba comandos en unos quince minutos. Instalarás el core de Arduino adecuado, publicarás la temperatura interna del chip en broker.connectmq.com, cambiarás el LED RGB integrado desde tu portátil y aprenderás qué costumbres del ESP32 clásico ya no sirven.

Qué hace diferente al ESP32-C6

El ESP32-C6 no es simplemente un ESP32 más nuevo. Usa otra arquitectura de CPU y otro conjunto de radios, y algunos de esos cambios se notan de inmediato en los sketches de Arduino.

Característica ESP32 clásico ESP32-C6
CPU Xtensa LX6 de doble núcleo, hasta 240 MHz RISC-V de un núcleo, hasta 160 MHz, más un núcleo RISC-V de bajo consumo
Wi-Fi 802.11 b/g/n, 2,4 GHz 802.11ax (Wi-Fi 6), solo 2,4 GHz
Bluetooth Classic y BLE 4.2 Solo BLE 5, sin Classic
802.15.4 No Sí (Thread, Zigbee)
Core de Arduino 2.x y 3.x Solo 3.x
USB Chip USB-UART externo USB Serial/JTAG nativo más UART en la mayoría de DevKits
LED integrado (DevKitC-1) Normalmente un LED simple en GPIO 2 LED RGB direccionable en GPIO 8

Para MQTT, las consecuencias prácticas son:

  • Necesitas el core de Arduino 3.x. El C6 no está disponible en los paquetes de placas 2.x.
  • Solo hay un núcleo de aplicación. Cualquier código que fije tareas al núcleo 1 debe cambiar al núcleo 0.
  • El puerto serie puede aparecer en otro puerto. Si no se imprime nada, activa "USB CDC On Boot" o conéctate al puerto UART.
  • Wi-Fi 6 es opcional, no obligatorio. El C6 también se conecta a puntos de acceso 802.11n normales. Aun así, no puede ver redes de 5 GHz.

Al protocolo MQTT nada de esto le importa. El mismo código de PubSubClient que funciona en un ESP32 funciona en un C6, y por eso este tutorial se centra en los detalles de configuración que suelen dar problemas.

Requisitos previos

  • Una placa ESP32-C6. Los pasos asumen la ESP32-C6-DevKitC-1 de Espressif; otras placas C6 funcionan con pequeños cambios de pines.
  • Arduino IDE 2.x.
  • El paquete de placas esp32 de Espressif Systems, versión 3.0 o posterior, desde el Boards Manager.
  • La librería PubSubClient de Nick O'Leary desde el Library Manager.
  • Los clientes de línea de comandos de Mosquitto en tu equipo.

Configurar Arduino para el ESP32-C6

  1. Abre el Boards Manager, busca esp32 e instala o actualiza el paquete de Espressif a una versión 3.x.
  2. Selecciona Tools > Board > esp32 > ESP32C6 Dev Module.
  3. En la DevKitC-1, conecta el puerto USB-C marcado como UART para la experiencia más sencilla. Si usas el puerto marcado como USB, configura Tools > USB CDC On Boot > Enabled para que Serial se asigne al USB nativo.
  4. Elige el puerto COM correspondiente y sube una vez un sketch vacío para confirmar que la cadena de herramientas funciona.

Si la subida falla con un timeout de conexión, mantén pulsado BOOT, pulsa RESET, suelta BOOT y vuelve a intentarlo. Así fuerzas el bootloader de la ROM.

El sketch ESP32-C6 MQTT

El sketch publica la lectura del sensor de temperatura interno, la intensidad de la señal Wi-Fi y el heap libre cada diez segundos, se suscribe a un topic de comandos para el LED e informa del estado del LED como mensaje retenido.

#include <WiFi.h>
#include <PubSubClient.h>

const char* WIFI_SSID     = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST     = "broker.connectmq.com";
const uint16_t MQTT_PORT  = 1883;
const char* PREFIX        = "connectmq/demo/c6x41z";   // cámbialo por tu propio id aleatorio

WiFiClient   net;
PubSubClient mqtt(net);
String clientId;
String topicTelemetry, topicLedSet, topicLedState, topicStatus;
unsigned long lastPublish = 0;
uint8_t ledR = 0, ledG = 0, ledB = 0;

void setLed(uint8_t r, uint8_t g, uint8_t b) {
  ledR = r; ledG = g; ledB = b;
  rgbLedWrite(RGB_BUILTIN, r, g, b);   // API del core de Arduino 3.x
  char state[40];
  snprintf(state, sizeof(state), "{\"r\":%u,\"g\":%u,\"b\":%u}", r, g, b);
  mqtt.publish(topicLedState.c_str(), state, true);
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  String msg;
  for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];
  msg.trim();
  msg.toUpperCase();
  Serial.printf("Command on %s: %s\n", topic, msg.c_str());

  if (msg == "OFF")        setLed(0, 0, 0);
  else if (msg == "RED")   setLed(40, 0, 0);
  else if (msg == "GREEN") setLed(0, 40, 0);
  else if (msg == "BLUE")  setLed(0, 0, 40);
  else if (msg == "WHITE") setLed(30, 30, 30);
}

void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.printf("\nIP %s, RSSI %d dBm\n", WiFi.localIP().toString().c_str(), WiFi.RSSI());
}

void connectMqtt() {
  while (!mqtt.connected()) {
    Serial.print("Connecting to MQTT... ");
    if (mqtt.connect(clientId.c_str(), topicStatus.c_str(), 1, true, "offline")) {
      Serial.println("connected");
      mqtt.publish(topicStatus.c_str(), "online", true);
      mqtt.subscribe(topicLedSet.c_str(), 1);
    } else {
      Serial.printf("failed, state %d, retrying in 5 s\n", mqtt.state());
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  delay(500);

  clientId       = "esp32c6-" + String((uint32_t)ESP.getEfuseMac(), HEX);
  topicTelemetry = String(PREFIX) + "/telemetry";
  topicLedSet    = String(PREFIX) + "/led/set";
  topicLedState  = String(PREFIX) + "/led/state";
  topicStatus    = String(PREFIX) + "/status";

  connectWifi();
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
  mqtt.setBufferSize(512);
  connectMqtt();
  setLed(0, 0, 0);
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) connectWifi();
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  if (millis() - lastPublish >= 10000) {
    lastPublish = millis();
    char payload[160];
    snprintf(payload, sizeof(payload),
             "{\"chipTemp\":%.1f,\"rssi\":%d,\"freeHeap\":%lu,\"uptime\":%lu}",
             temperatureRead(), WiFi.RSSI(),
             (unsigned long)ESP.getFreeHeap(), millis() / 1000);
    mqtt.publish(topicTelemetry.c_str(), payload);
    Serial.println(payload);
  }
}

El sensor de temperatura interno mide el silicio del chip, no la habitación, así que espera valores varios grados por encima del ambiente. Es útil como indicador de salud y como valor de demostración sin cableado.

Probar los mensajes ESP32-C6 MQTT

Abre una terminal y suscríbete a todo lo que cuelga de tu prefijo:

mosquitto_sub -h broker.connectmq.com -p 1883 -i c6-viewer-x41z -t "connectmq/demo/c6x41z/#" -v

Deberías ver status online, el estado retenido del LED y un mensaje de telemetría cada diez segundos. En una segunda terminal, envía un comando:

mosquitto_pub -h broker.connectmq.com -p 1883 -i c6-cmd-x41z -t "connectmq/demo/c6x41z/led/set" -m "green" -q 1

El LED RGB se pone verde y aparece un nuevo estado retenido. Como el estado es retenido, cualquier cliente que se suscriba más tarde conoce de inmediato el color actual. El área pública de ConnectMQ no requiere cuenta, pero es visible para todos, así que usa solo datos de demostración; la página del servidor MQTT público gratuito explica sus límites, entre ellos 10 mensajes por segundo por cliente.

Portar código del ESP32 clásico al C6

La mayoría de los sketches compilan sin cambios. Estas son las modificaciones que probablemente necesites:

  1. Fijación de tareas. Sustituye xTaskCreatePinnedToCore(..., 1) por el núcleo 0, o llama a xTaskCreate. La guía de ESP32 FreeRTOS MQTT muestra una distribución de tareas que funciona en ambas familias de chips con este único cambio.
  2. Pines del LED. digitalWrite(2, HIGH) no enciende nada en una DevKitC-1. Usa rgbLedWrite(RGB_BUILTIN, r, g, b).
  3. Pines del ADC. El C6 tiene un solo ADC en los GPIO 0 a 6. Números de pin como 34 o 36 de los ejemplos del ESP32 clásico no existen.
  4. APIs obsoletas. El core 3.x renombró o eliminó varias funciones; por ejemplo, neopixelWrite pasó a ser rgbLedWrite y la API de PWM LEDC cambió a ledcAttach. Contrasta los errores del compilador con las notas de migración de la documentación de Arduino-ESP32.
  5. Bluetooth Classic. BluetoothSerial no está soportado. Usa BLE en su lugar.

Si compilas con PlatformIO, configura la plataforma con una versión que incluya el core de Arduino 3.x para el C6; la configuración de MQTT con PlatformIO explica paso a paso un archivo de proyecto reproducible.

Solución de problemas

  • mqtt.state() devuelve -2. La conexión TCP ha fallado. Comprueba que la placa tiene realmente una dirección IP y que tu red permite el puerto 1883 saliente. Algunas redes de invitados lo bloquean; prueba en su lugar el puerto 8883 con TLS.
  • mqtt.state() devuelve 2. El broker rechazó el client ID. En el área pública no puede estar vacío y debe ser único, algo que garantiza el sufijo con la MAC del eFuse.
  • Se conecta y se cae cada pocos segundos. Dos dispositivos usan el mismo client ID, y cada nueva conexión expulsa a la otra. Ocurre a menudo cuando grabas el mismo ID fijo en dos placas.
  • El Wi-Fi nunca se conecta a un router Wi-Fi 6. Asegúrate de que la banda de 2,4 GHz está activada y no queda oculta tras un ajuste de band steering que empuja a los clientes solo a 5 GHz. Las redes solo WPA3 también pueden dar problemas; prueba el modo mixto WPA2/WPA3.
  • No hay salida serie. Cambia USB CDC On Boot o pásate al puerto UART.

Pasar a producción con un broker en la nube

Para dispositivos reales, cambia a TLS en el puerto 8883 con credenciales. Crea un broker en app.connectmq.com y copia el usuario, la contraseña y el client ID que genera. Cambia WiFiClient por WiFiClientSecure, carga el certificado ISRG Root X1 con net.setCACert(...), configura el puerto 8883 y pasa las credenciales a mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", ...). El C6 gestiona el handshake TLS sin problemas, aunque tarda un poco más que un ESP32 clásico a 240 MHz.

A partir de ahí, el explorador de topics en vivo del portal muestra los mensajes de tu C6 en cuanto llegan, y la vista de dispositivos agrupa las placas por planta y línea si usas nombres de topic al estilo ISA-95. Si los brokers son nuevos para ti, qué hace un broker MQTT es una introducción breve, y el tutorial de IoT con ESP32 enumera todos los proyectos de esta serie.

Gestiona tu flota de ESP32-C6 con ConnectMQ

El ESP32-C6 es una opción sólida para nuevos diseños: eficiencia de Wi-Fi 6, BLE 5 y una cadena de herramientas moderna. Combínalo con un broker MQTT en la nube que no tengas que operar. ConnectMQ es un broker MQTT gestionado que te ofrece TLS en el 8883, MQTT 3.1.1 y 5.0 y un plan gratuito Serverless sin tarjeta de crédito, para que pases del área pública de demostración a dispositivos autenticados en minutos. Si quieres propiedades de MQTT 5 en el C6, ESP-IDF es el camino; consulta esp-mqtt con MQTT 5.

Preguntas frecuentes

¿El ESP32-C6 admite MQTT sobre Wi-Fi 6?

Sí. MQTT funciona sobre TCP, así que trabaja con cualquier estándar Wi-Fi que admita el C6, incluido 802.11ax en 2,4 GHz. Wi-Fi 6 ayuda sobre todo en eficiencia energética y en redes saturadas.

¿Puedo usar Thread o Zigbee en el C6 para llegar a un broker MQTT?

La radio del C6 admite 802.15.4, pero MQTT necesita una ruta IP hasta el broker. Una red Thread necesita un border router, y los dispositivos Zigbee suelen necesitar una pasarela que traduzca a MQTT.

¿Por qué mi antiguo sketch de ESP32 no compila para el C6?

El C6 requiere el core de Arduino 3.x, que cambió varias APIs, y carece de Bluetooth Classic y del segundo núcleo. Actualiza las funciones renombradas y elimina la fijación al núcleo 1.

¿Es el sensor de temperatura interno lo bastante preciso para la temperatura ambiente?

No. Mide el silicio del chip y marca más que la habitación. Usa un sensor externo como un DHT22 o un BME280 para lecturas ambientales.

Artículos relacionados

Ejemplo de ESP-IDF MQTT: crea un cliente esp-mqtt desde cero

Construye un proyecto ESP-IDF desde una carpeta vacía con el componente esp-mqtt: configuración de Wi-Fi en modo estación, el manejador de eventos MQTT, publicación y suscripción, propiedades de MQTT 5 y TLS con el bundle de certificados.

9 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.