Control Remoto de Luces IoT: Creación de una Interfaz Web con AWS Amplify, API Gateway, Lambda y ESP32

Claudia Márquez
Caleidos
Published in
6 min readOct 9, 2023

En este post, continuaremos desde donde lo dejamos en nuestro artículo anterior, donde explicamos cómo crear un “Thing” en AWS IoT Core y configurar la comunicación con un ESP32 con el protocolo MQQT. Ahora, daremos un paso más allá al explorar cómo crear un sitio web que nos permita controlar de forma remota la activación y desactivación de una luz conectada a nuestro dispositivo IoT. Esta implementación se basará en una arquitectura serverless y aprovechará herramientas como AWS Amplify, API Gateway, Lambda, y AWS IoT Core, junto con nuestro fiel compañero, el ESP32.

Comenzaremos creando una función Lambda y otorgándole los permisos necesarios para interactuar con IoT Core. Luego, configuramos un API Gateway para exponer nuestra Lambda al mundo exterior. Con Amplify, desplegamos una página web que nos permite enviar comandos a nuestro dispositivo IoT por el API que creamos. Al hacer clic en el botón “Encender / Apagar Luz” de la web podremos controlar la luz conectada a nuestro ESP32 de forma remota.

Crear la función Lambda

En la página principal de AWS Lambda, haz clic en el botón “Create function” (Crear función). Ingresa un nombre para la función y selecciona el Runtime Node.js 18.x.

En la sección “Code”, copia el código del archivo index.mjs y luego haz clic en “Deploy”.

// Import necessary modules using ESM syntax
import { IoTDataPlaneClient, PublishCommand } from "@aws-sdk/client-iot-data-plane";

// Initialize the IoT Data client
const client = new IoTDataPlaneClient({ endpoint: 'https://YOUR_IOT_ENDPOINT.iot.us-east-1.amazonaws.com' }); // Reemplaza 'YOUR_IOT_ENDPOINT' con el endpoint de IoT Core

// Lambda function handler
export const handler = async (event, context) => {
try {
// Parse the JSON body from the event
const requestBody = JSON.parse(event.body);
console.log(event.body);

// Verify the JSON structure
if (!requestBody || typeof requestBody.light === 'undefined' || (requestBody.light !== 0 && requestBody.light !== 1)) {
return {
statusCode: 400,
headers: {
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify({ error: 'Invalid request' })
};
}

// Construct the message to publish to AWS IoT Core
const message = { led: requestBody.light };

// Publish the message to the desired IoT Core topic
const params = {
topic: 'esp32/sub',
payload: JSON.stringify(message),
qos: 0
};

const command = new PublishCommand(params);
const response = await client.send(command);

return {
statusCode: 200,
body: JSON.stringify({ message: 'Message sent to IoT Core' }),
headers: {
"Access-Control-Allow-Origin": "*",
},
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify({ error: 'Internal server error' })
};
}
};

Ve a la sección “Configuration” y haz clic en el rol generado para la Lambda. Aquí agregaremos una política para otorgar permisos para publicar en el tópico de IoT Core.

En la página del rol, haz clic en “Add permissions” y luego en “Create Inline Policy”.

En la pantalla para especificar el permiso, selecciona JSON y copia la política en el “Policy editor”.

Una vez configurado, asigna un nombre a la política y haz clic en “Create Policy”.

Crear el API Gateway

Accede a la consola de API Gateway y selecciona “Build” en la sección “REST API”.

Agrega un nombre para el API y haz clic en “Create API”.

En la nueva API, haz clic en “Actions” y luego en “Create Resource”.

En la pantalla “New Child Resource”, escribe “led” en el campo “Resource Name” y luego haz clic en “Create Resource”

Luego de crear el recurso seleccionamos “Actions” y “Create Method”, seleccionamos “POST” y damos clic en el check.

En lal nueva pantalla hacemos clic en la casilla “Use Lambda Proxy Integration”, escribimos “led” en la función lambda y luego hacemos clic en “Save”.

Luego, ve a “Actions” y selecciona “Enable CORS”. Haz clic en el botón “Enable CORS and replace existing CORS headers”.

Con la configuración realizada, ve a la opción “Actions” y selecciona “Deploy API”. Ingresa un nombre para tu stage y haz clic en “Deploy”.

Una vez desplegado, la consola de API Gateway mostrará la URL. Deberás usar esta URL en la siguiente sección.

Crear Web con Amplify

Crea un archivo llamado “index.html” y copia el contenido proporcionado, asegurándote de cambiar los parámetros indicados. Luego, genera un archivo ZIP con el contenido.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Control de Luz</title>
<!-- Agregar Tailwind CSS desde el CDN -->
<link
href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
rel="stylesheet"
/>
<!-- Agregar Font Awesome desde el CDN -->
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
rel="stylesheet"
/>
</head>
<body class="bg-gray-100 flex items-center justify-center h-screen">
<div class="text-center">
<!-- Icono de luz usando Font Awesome (puedes reemplazarlo con otro icono si lo deseas) -->
<i class="fas fa-lightbulb text-4xl text-yellow-500 mb-4"></i>
<h1 class="text-2xl font-semibold mb-2">Control de Luz</h1>
<button
id="toggleButton"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline-blue active:bg-blue-800"
>
Encender / Apagar Luz
</button>
</div>

<script>
// Event listener para el botón
let light = 1
document
.getElementById('toggleButton')
.addEventListener('click', function () {
// Realizar una solicitud POST (aquí debes especificar la URL y los datos de la solicitud)
fetch(
'https://tu-url.execute-api.us-east-1.amazonaws.com/test/led', // Cambia la URL obtenida desde API Gateway
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
light: light,
}),
}
)
.then((response) => {
if (response.ok) {
alert('Solicitud POST exitosa')
light = light === 1 ? 0 : 1
} else {
console.error('Error en la solicitud POST')
}
})
.catch((error) => {
console.error('Error en la solicitud POST:', error)
})
})
</script>
</body>
</html>

Para cargar tu página web, utiliza AWS Amplify. Accede a la consola de Amplify y crea un nuevo proyecto de tipo “Amplify Hosting”.

Selecciona la opción “Deploy without Git provider”.

Luego, selecciona el archivo comprimido que contiene tu “index.html”.

Una vez desplegado, la consola de Amplify te proporcionará la dirección de tu sitio web.

Verlo en acción

Ingresamos y hacemos clic en el botón Encender / Apagar Luz y la luz de nuestro ESP32 se encenderá y apagará.

Conclusión

En conclusión, hemos demostrado cómo construir una solución serverless que permite controlar nuestra luz led desde una interfaz web. Si bien esta implementación nos permite encender o apagar la luz, todavía no tenemos un mecanismo para conocer el estado actual de la luz. En futuros posts, exploraremos la funcionalidad de “IoT shadow” para mantener un seguimiento del estado real de la luz y proporcionar una interfaz web más informativa y reactiva.

--

--