Ejemplo de integración con ESP32 (MQTT)
Este ejemplo conecta una placa ESP32 a Cloud Studio IoT por MQTT con TLS, usando el intercambio de datos flexible. Al terminar, la placa va a:
- Enviar cada minuto la temperatura y la humedad que mide un sensor DHT22 (uplink).
- Encender o apagar su LED al recibir un comando desde un panel o una regla (downlink), e informar el nuevo estado.
El mismo código sirve para cualquier placa de la familia ESP32 compatible con el núcleo de Arduino para ESP32 (ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6). Solo pueden cambiar los números de pin.
Qué se necesita
- Una placa de desarrollo ESP32 y un sensor DHT22 conectado al GPIO 4. Casi todas las placas DevKit tienen un LED en el GPIO 2; si la placa no lo tiene, se puede conectar uno con una resistencia.
- El Arduino IDE con el paquete de placas esp32 de Espressif Systems, instalado desde el Gestor de placas.
- Dos librerías del Gestor de librerías: PubSubClient (de Nick O'Leary) y DHT sensor library (de Adafruit).
- Acceso a la aplicación Manager de la instancia de Cloud Studio IoT.
Paso 1: obtener las credenciales y los datos de conexión MQTT
Cada instancia tiene su propio servidor MQTT. En el Manager, debe abrirse la opción Configuración MQTT. La página tiene dos pestañas:
- Usuarios MQTT: contiene el usuario y la opción para ver su contraseña. El usuario es también el prefijo de todos los topics MQTT.
- Datos de conexión: contiene el servidor y el puerto (normalmente 8883), y la opción Descargar certificado, que entrega el archivo
mqtt_cert.pem. El ESP32 lo usa para comprobar que está conectado al servidor correcto.
Más detalles en integración MQTT.
Paso 2: crear el modelo de dispositivo
El modelo le dice a la plataforma qué endpoints tiene el dispositivo y cómo leer sus mensajes. En el Manager, debe elegirse la opción Modelos de dispositivo, dentro de la sección Dispositivos, y después Agregar, con una descripción (por ejemplo, "ESP32 DHT22") y un código de modelo. Después se edita el modelo para agregar los dos scripts siguientes. Más detalles en modelos de dispositivo.
Script de configuración. Crea tres endpoints en cada dispositivo de este modelo: temperatura, humedad y el LED.
function getConfiguration(config)
{
config.addressLabel = {en: "MAC address", es: "Dirección MAC"};
}
function getEndpoints(deviceAddress, endpoints)
{
endpoints.addEndpoint("1", "Temperatura", endpointType.temperatureSensor);
endpoints.addEndpoint("2", "Humedad", endpointType.humiditySensor);
endpoints.addEndpoint("3", "LED", endpointType.appliance);
}Script de conversión de datos. parseUplink lee el JSON que publica el ESP32 y actualiza los endpoints. buildDownlink convierte un comando de encendido o apagado en un mensaje JSON para la placa.
function parseUplink(device, payload)
{
var data = payload.asJsonObject();
if (data === undefined || data === null)
return;
if (data.temperature !== undefined)
device.endpoints.byAddress("1").updateTemperatureSensorStatus(data.temperature);
if (data.humidity !== undefined)
device.endpoints.byAddress("2").updateHumiditySensorStatus(data.humidity);
if (data.led !== undefined)
device.endpoints.byAddress("3").updateApplianceStatus(data.led);
}
function buildDownlink(device, endpoint, command, payload)
{
payload.buildResult = downlinkBuildResult.unsupported;
if (endpoint === null || command.type !== commandType.onOff)
return;
switch (command.onOff.type) {
case onOffCommandType.turnOn:
payload.setAsJsonObject({ on: true });
break;
case onOffCommandType.turnOff:
payload.setAsJsonObject({ on: false });
break;
default:
return;
}
payload.buildResult = downlinkBuildResult.ok;
}La referencia completa de estas funciones está en procesamiento de datos.
Paso 3: crear el dispositivo
Se crea un dispositivo nuevo con el modelo del paso 2. Como dirección se usa la dirección MAC de la placa sin los dos puntos, por ejemplo 24A160F1B2C4. La plataforma crea los tres endpoints automáticamente.
Con el usuario y la dirección, los dos topics del dispositivo son:
- Uplink (el ESP32 publica):
{MQTTUserID}/uplink/{DeviceAddress} - Downlink (el ESP32 se suscribe):
{MQTTUserID}/downlink/{DeviceAddress}
Paso 4: programar el ESP32
Los valores del principio del sketch se reemplazan por los propios, y el contenido de mqtt_cert.pem se pega entre las dos líneas del certificado.
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <DHT.h>
const char* WIFI_SSID = "nombre-wifi";
const char* WIFI_PASSWORD = "clave-wifi";
const char* MQTT_HOST = "servidor-mqtt"; // pestaña Datos de conexión
const uint16_t MQTT_PORT = 8883;
const char* MQTT_USER = "USUARIO_MQTT"; // pestaña Usuarios MQTT
const char* MQTT_PASSWORD = "CLAVE_MQTT";
const char* DEVICE_ADDRESS = "24A160F1B2C4"; // igual que en la plataforma
// Contenido de mqtt_cert.pem
const char* MQTT_CA_CERT = R"PEM(
-----BEGIN CERTIFICATE-----
PEGA AQUI EL CERTIFICADO
-----END CERTIFICATE-----
)PEM";
const int DHT_PIN = 4;
const int LED_PIN = 2;
const unsigned long PUBLISH_INTERVAL_MS = 60000;
DHT dht(DHT_PIN, DHT22);
WiFiClientSecure tlsClient;
PubSubClient mqtt(tlsClient);
char uplinkTopic[96];
char downlinkTopic[96];
bool ledOn = false;
unsigned long lastPublish = 0;
void publishState() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
char message[96];
if (isnan(temperature) || isnan(humidity)) {
snprintf(message, sizeof(message), "{\"led\":%s}", ledOn ? "true" : "false");
} else {
snprintf(message, sizeof(message), "{\"temperature\":%.1f,\"humidity\":%.1f,\"led\":%s}",
temperature, humidity, ledOn ? "true" : "false");
}
mqtt.publish(uplinkTopic, message);
Serial.printf("Sent %s\n", message);
}
void onMessage(char* topic, byte* payload, unsigned int length) {
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
message.replace(" ", "");
if (message.indexOf("\"on\":true") >= 0) {
ledOn = true;
} else if (message.indexOf("\"on\":false") >= 0) {
ledOn = false;
} else {
return;
}
digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
publishState();
}
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.printf("\nWi-Fi connected, IP %s\n", WiFi.localIP().toString().c_str());
}
void connectMqtt() {
String clientId = String(MQTT_USER) + DEVICE_ADDRESS;
while (!mqtt.connected()) {
if (mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASSWORD)) {
mqtt.subscribe(downlinkTopic);
Serial.println("MQTT connected");
} else {
Serial.printf("MQTT connection failed, state %d. Retrying in 5 s\n", mqtt.state());
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
dht.begin();
snprintf(uplinkTopic, sizeof(uplinkTopic), "%s/uplink/%s", MQTT_USER, DEVICE_ADDRESS);
snprintf(downlinkTopic, sizeof(downlinkTopic), "%s/downlink/%s", MQTT_USER, DEVICE_ADDRESS);
connectWiFi();
tlsClient.setCACert(MQTT_CA_CERT);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
connectWiFi();
}
if (!mqtt.connected()) {
connectMqtt();
}
mqtt.loop();
if (lastPublish == 0 || millis() - lastPublish >= PUBLISH_INTERVAL_MS) {
lastPublish = millis();
publishState();
}
}El ESP32 publica en el topic de uplink mensajes como este:
{"temperature":22.4,"humidity":48.0,"led":false}Y recibe en el topic de downlink mensajes como este:
{"on":true}Paso 5: comprobar que funciona
- En el monitor serie, a 115200 baudios, deben aparecer "MQTT connected" y una línea "Sent" por minuto.
- El dispositivo debe mostrar los valores de temperatura y humedad en la plataforma. Para ver los mensajes crudos a medida que llegan, se puede usar el real-time log broker.
- Al encender el endpoint del LED desde la plataforma, el LED de la placa se enciende y el endpoint muestra el nuevo estado.
Con los datos llegando, ya se pueden crear paneles y alarmas.
Si la conexión falla: en PubSubClient, el estado -2 suele indicar que no se pudo establecer la conexión TLS (conviene revisar el servidor, el puerto y que el certificado sea el descargado de la instancia), y los estados 4 o 5 indican que se rechazó el usuario o la contraseña. Si la placa se conecta pero no aparecen datos, hay que revisar que el topic use el mismo usuario y la misma dirección de dispositivo que la plataforma, carácter por carácter.
Última actualización
Ejemplo integración Raspberry Pi Pico W
Ejemplo paso a paso de integración de una Raspberry Pi Pico W con Cloud Studio IoT para enviar datos, crear alarmas y armar dashboards.
Control de dispositivos
Cómo controlar desde Gear Studio los dispositivos que admiten actuación, como dimmers, termostatos o cortinas, si el usuario tiene permiso.