Cómo conectar el ESP32 a AWS mediante MQTT

Hola. En este tutorial aprenderás a conectar un ESP32 a AWS y usar el protocolo MQTT para enviar los datos de temperatura y humedad leídos por un sensor DHT11, también puedes utilizar el modelo DHT22.

¿Qué necesitas para este tutorial?

Hardware

  • ESP32
  • DHT11 o DHT22
  • Protoboard
  • Cables

Software

  • Cuenta activa en AWS
  • Arduino IDE
  • Librería PubSubClient. Descarga aquí o desde el Administrador de Bibliotecas de Arduino IDE.
  • SPIFFS. Descarga aquí.
  • Librería DHT. Descarga desde el Administrador de Bibliotecas de Arduino IDE.

¿Qué es AWS?

AWS o Amazon Web Service es una plataforma que renta servicios computacionales a través de internet, lo que se conoce como computación en la nube. Estos servicios van desde hospedaje de máquinas virtuales, almacenamiento de datos, análisis de datos, seguridad y entre muchos otros también nos brinda servicios de Internet de las Cosas.

AWS IoT Core

AWS IoT Core es un servicio en la nube en el que puedes registrar y conectar objetos. Desde allí puedes administrarlos y también las configuraciones de seguridad que necesites.

Para acceder a AWS IoT Core debes iniciar sesión en tu cuenta de AWS. Una vez en la consola ve al buscador y escribe “iot”. Se te mostrarán varios servicios.

Entra al que doce “IoT Core”.

Estoy usando la nueva consola. Puedes cambiar entre la nueva interfaz o la anterior desde el switch en la parte inferior izquierda. Recomiendo que sigas el tutorial con la nueva versión porque algunas cosas a nivel visual y texto son diferentes. Sin embargo, el proceso y ajustes son los mismos.

Configuración en AWS IoT Core

Crear una “cosa”

Dentro del servicio de AWS IoT Core navega por el panel izquierdo hasta llegar al menú desplegable “Manage”, después entra a la opción “Things”.

Después haz clic en el botón del centro, o también el botón naranja, que dice “Create things”.

Selecciona la opción de crear solo un objeto o también “Create single thing”. Después haz clic en el botón “Next”.

Ahora nombra tu objeto en el espacio debajo de “Thing name”.

Deja las demás opciones por defecto y presiona en “Next”.

En la siguiente ventana te preguntara sobre la creación de un certificado. Lo haremos después, así que selecciona “Skip creating a certificate at this time” y luego haz clic en el botón “Create thing”.

Crear una política

Ahora crearemos una política para el objeto. Ve al panel izquierda, abre el menú “Secure” y después en la opción “Policies”.

Entrarás a una nueva ventana. Presiona el botón que dice “Create policy” o “Create” en la parte inferior si la lista de políticas está vacía.

Dale un nombre a tu política.

En esta sección deja todo como en la imagen. Seleccionando “Builder”. “Policy effect” como “Allow” y escribiendo un asterisco “*” en los espacios de texto. Esto equivale a seleccionar todas las opciones disponibles en esos campos.

Crear certificado

Ahora hay que crear un certificado, estos certificados se subirán al ESP32 usando SPIFFS.

Ve al panel izquierdo y vuelve a al menú “Secure”. Después entra en “Certificates”.

Cuando estés en la nueva sección haz clic en el botón “Create certificate” que está en la zona central.

Escoge la opción “Auto-generate new certificate (recommended)”. En “Certificate status” puedes elegir si quieres que el certificado esté activo o inactivo al crearlo. Podemos cambiar esto después, así que lo dejaremos inactivo “Inactive”.

Descarga los archivos de los certificados con el botón a la derecha “Download”. Es importante que lo hagas en ese momento porque no podrás volverlos a ver.

Debes descargar el “Device certificate”, “Public key file” y “Private key file”.

En la sección de “Root RCA certicificates” descarga el archivo de 2048 bit.

Cuando hayas descargado los certificados haz clic en el botón “Continue”.

En la carpeta en donde tengas el archivo de Arduino crea una carpeta y nómbrala “data” y guarda allí los certificados.

También debes renombrar los archivos quitando parte del nombre. Recuerda que el nombre sumado a las extensiones de archivo no deben superar los 30 caracteres.

Asignar certificados a una política

Empieza activando el certificado que se creó anteriormente. En la lista de certificados selecciona el que quieras activar, en este caso solo hay uno.

Cuando lo hayas seleccionado ve al menú que está arriba que dice “Actions” y escoge la opción “Activate”.

Repite el procesos pero ahora selecciona la opción “Attach policy”.

Tendrás un cuadro de texto en el que debes escribir el nombre de la política que quieras vincular. También aparecerá una lista con las políticas que hayas creado de la cual debes escoger alguna.

Después presiona el botón “Attach policies”.

Programación

Escribir código de Arduino

Aquí puedes ver el código a utilizar. También se va a explicar lo que hace.

/*
 Conectar ESP32 a AWS
 https://www.todomaker.com
 Colaboración: Néstor Ccencho
 Todos los derechos reservados.
*/

//Añadir librerías
#include "SPIFFS.h"
#include <WiFiClientSecure.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <DHT.h>                

//Credenciales de red Wifi
const char* ssid = "Nombre de red";
const char* password = "Contraseña"; 

//Servidor MQTT
const char* mqtt_server = "servidor.amazonaws.com";
const int mqtt_port = 8883;

String Read_rootca;
String Read_cert;
String Read_privatekey;
//********************************
#define BUFFER_LEN  256
long lastMsg = 0;
char msg[BUFFER_LEN];
int value = 0;
byte mac[6];
char mac_Id[18];
int count = 1;
//********************************

//Configuración de cliente MQTT
WiFiClientSecure espClient;
PubSubClient client(espClient);

//Configuración de DHTXX
#define DHTPIN 19 //Pin
DHT dht(DHTPIN, DHT11); //Modelo

//Conectar a red Wifi
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Conectando.. ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi conectado");
  Serial.println("Direccion IP: ");
  Serial.println(WiFi.localIP());
}

//Callback
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensaje recibido [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

//Conectar a broker MQTT
void reconnect() {
  
  // Loop para reconección
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    
    // Creando un ID como ramdon
    String clientId = "ESP32-";
    clientId += String(random(0xffff), HEX);
    
    // Intentando conectarse
    if (client.connect(clientId.c_str())) {
      Serial.println("conectada");
      
    // Conectado, publicando un payload...
      client.publish("ei_out", "hello world");
    
    // ... y suscribiendo
      client.subscribe("ei_in");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" Esperando 5 segundos");
      
      // Tiempo muerto de 5 segundos
      delay(5000);
    }
  }
}

void setup() {
  
  Serial.begin(115200);
  dht.begin();
  Serial.setDebugOutput(true);
  
  // Inicializa con el PIN led2.
  pinMode(2, OUTPUT);
  setup_wifi();
  delay(1000);
  
  //****************
  if (!SPIFFS.begin(true)) {
    Serial.println("Se ha producido un error al montar SPIFFS");
    return;
  }
  //**********************
  //Root CA leer archivo.
  File file2 = SPIFFS.open("/AmazonRootCA1.pem", "r");
  if (!file2) {
    Serial.println("No se pudo abrir el archivo para leerlo");
    return;
  }
  Serial.println("Root CA File Content:");
  while (file2.available()) {
    Read_rootca = file2.readString();
    Serial.println(Read_rootca);
  }
  //*****************************
  // Cert leer archivo
  File file4 = SPIFFS.open("/e349f5eb7e-certificate.pem.crt", "r");
  if (!file4) {
    Serial.println("No se pudo abrir el archivo para leerlo");
    return;
  }
  Serial.println("Cert File Content:");
  while (file4.available()) {
    Read_cert = file4.readString();
    Serial.println(Read_cert);
  }
  //***************************************
  //Privatekey leer archivo
  File file6 = SPIFFS.open("/e349f5eb7e-private.pem.key", "r");
  if (!file6) {
    Serial.println("No se pudo abrir el archivo para leerlo");
    return;
  }
  Serial.println("privateKey contenido:");
  while (file6.available()) {
    Read_privatekey = file6.readString();
    Serial.println(Read_privatekey);
  }
  //=====================================================

  char* pRead_rootca;
  pRead_rootca = (char *)malloc(sizeof(char) * (Read_rootca.length() + 1));
  strcpy(pRead_rootca, Read_rootca.c_str());

  char* pRead_cert;
  pRead_cert = (char *)malloc(sizeof(char) * (Read_cert.length() + 1));
  strcpy(pRead_cert, Read_cert.c_str());

  char* pRead_privatekey;
  pRead_privatekey = (char *)malloc(sizeof(char) * (Read_privatekey.length() + 1));
  strcpy(pRead_privatekey, Read_privatekey.c_str());

  Serial.println("================================================================================================");
  Serial.println("Certificados que pasan adjuntan al espClient");
  Serial.println();
  Serial.println("Root CA:");
  Serial.write(pRead_rootca);
  Serial.println("================================================================================================");
  Serial.println();
  Serial.println("Cert:");
  Serial.write(pRead_cert);
  Serial.println("================================================================================================");
  Serial.println();
  Serial.println("privateKey:");
  Serial.write(pRead_privatekey);
  Serial.println("================================================================================================");

  espClient.setCACert(pRead_rootca);
  espClient.setCertificate(pRead_cert);
  espClient.setPrivateKey(pRead_privatekey);

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  //******************************************
  WiFi.macAddress(mac);
  snprintf(mac_Id, sizeof(mac_Id), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  Serial.println(mac_Id);
  //****************************************
  delay(2000);
 
}


void loop() {

  // ******************** SENSOR DHTxx *********************************
  float h = dht.readHumidity();         // Lectura de Temperatura
  float t = dht.readTemperature();      // Lectura de humedad
  if (isnan(h) || isnan(t))
  {
    Serial.println("¡Error al leer del sensor DHT!");
    return;
  }

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - lastMsg > 5000) {
    lastMsg = now;
    //=============================================================================================
    String macIdStr = mac_Id;
    String Temprature = String(t);
    String Humidity = String(h);
    snprintf (msg, BUFFER_LEN, "{\"mac_Id\" : \"%s\", \"Temperatura\" : %s, \"Humedad\" : %s}", macIdStr.c_str(), Temprature.c_str(), Humidity.c_str());
    Serial.print("Publicando mensaje: ");
    Serial.print(count);
    Serial.println(msg);
    client.publish("sensor", msg);
    count = count + 1;
    //================================================================================================
  }
  digitalWrite(2, HIGH);   
  delay(1000);                      
  digitalWrite(2, LOW);   
  delay(1000);                       
}

Se empieza añadiendo las librerías necesarias.

SPIFFS para subir los archivos a la memoria del ESP32. Puedes ver cómo instalarlo y usarlo en esta entrada.

WifiClientSeure nos dará funciones para crear un cliente.

Wire y DHT son necesarios para usar el sensor DHT11 y DHT22.

PubSubClient es para realizar la comunicación mediante MQTT.

#include "SPIFFS.h"
#include <WiFiClientSecure.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <DHT.h>  

En esta sección debes añadir la dirección del broker MQTT. La puedes encontrar en la ventana de IoT Core. En el panel izquierdo y luego entrando a la opción “Settings”. Allí verás la dirección de tu broker.

const char* mqtt_server = "servidor.amazonaws.com";
const int mqtt_port = 8883;

Variables que usaremos después para los datos de comunicación y autenticación del ESP32.

String Read_rootca;
String Read_cert;
String Read_privatekey;
//********************************
#define BUFFER_LEN  256
long lastMsg = 0;
char msg[BUFFER_LEN];
int value = 0;
byte mac[6];
char mac_Id[18];
int count = 1;

Instancia el cliente MQTT usando, a la vez, una instancia de un cliente Wifi.

WiFiClientSecure espClient;
PubSubClient client(espClient);

Se realiza la conexión a la red Wifi e imprime la IP del ESP32 en el Monitor Serie.

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Conectando.. ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi conectado");
  Serial.println("Direccion IP: ");
  Serial.println(WiFi.localIP());
}

Función de callback.

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensaje recibido [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

Función para realizar la conexión con el broker MQTT.

void reconnect() {
  
  // Loop para reconección
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    
    // Creando un ID como ramdon
    String clientId = "ESP32-";
    clientId += String(random(0xffff), HEX);
    
    // Intentando conectarse
    if (client.connect(clientId.c_str())) {
      Serial.println("conectada");
      
    // Conectado, publicando un payload...
      client.publish("ei_out", "hello world");
    
    // ... y suscribiendo
      client.subscribe("ei_in");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" Esperando 5 segundos");
      
      // Tiempo muerto de 5 segundos
      delay(5000);
    }
  }
}

En setup se inicia la comunicación serial, el sensor DHTXX e iniciar la conexión Wifi.

  Serial.begin(115200);
  dht.begin();
  Serial.setDebugOutput(true);
  
  // Inicializa con el PIN led2.
  pinMode(2, OUTPUT);
  setup_wifi();
  delay(1000);

Inicia el sistema de archivos SPIFFS. y notifica en caso de haber un error.

  if (!SPIFFS.begin(true)) {
    Serial.println("Se ha producido un error al montar SPIFFS");
    return;
  }

Abre el certificado que se subió a la memoria y almacena su valor en un variable de tipo String para usarla.

Se hizo uno para cada archivo.

  File file2 = SPIFFS.open("/AmazonRootCA1.pem", "r");
  if (!file2) {
    Serial.println("No se pudo abrir el archivo para leerlo");
    return;
  }
  Serial.println("Root CA File Content:");
  while (file2.available()) {
    Read_rootca = file2.readString();
    Serial.println(Read_rootca);
  }

Debes añadir los nombres del archivo en el código como se ve en las imágenes.

Después de procesar los archivos el programa asignará sus valores o contenido como parámetros para las funciones de la librería de MQTT.

  espClient.setCACert(pRead_rootca);
  espClient.setCertificate(pRead_cert);
  espClient.setPrivateKey(pRead_privatekey);

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

También se obtiene la dirección MAC del ESP32.

  WiFi.macAddress(mac);
  snprintf(mac_Id, sizeof(mac_Id), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  Serial.println(mac_Id);
  //****************************************
  delay(2000);

Subir certificados con SPIFFS

Comprobar conexión

También puedes ver un video del tutorial.

Conclusión

Como viste, es posible conectar el ESP32 a AWS IoT Core mediante el protocolo MQTT utilizando certificados para aumentar la seguridad. Esto te da la posibilidad de enviar datos a internet y tener en donde alojarlos.

Síguenos para ver más tutoriales para ver más tutoriales usando estas herramientas. Y comparte este tutorial para ayudar a más personas.

Te invitamos a tomar el curso de Introducción al ESP32: Introducción al ESP32 | TodoMaker’s School

Previous Post
Next Post