Cloud, DevOps e IoT en español

Parte 14 de 22 de la serie Domótica con ESP32 y AWS desde cero

Reglas de AWS IoT: guardar datos y enviar alertas sin servidores

8 de octubre de 2026 · Steven Carvajal · Tutoriales

Código de este artículo en GitHub →

Un ESP32 que publica la temperatura cada minuto genera datos, pero esos mensajes MQTT desaparecen si nadie los está escuchando. Para guardarlos, o para recibir un aviso cuando algo se sale de lo normal, no hace falta un servidor: AWS IoT Core tiene un motor de reglas que procesa cada mensaje y lo envía a otros servicios.

En esta parte creamos dos reglas: una que guarda las lecturas de un sensor en DynamoDB y otra que envía un correo cuando la temperatura pasa de un límite.

Cómo funciona una regla

Una regla tiene dos partes:

  1. Una consulta SQL que dice qué mensajes le interesan y qué campos extrae.
  2. Una o varias acciones: a dónde envía el resultado (DynamoDB, SNS, Lambda, S3, otro tópico...).
SELECT temperatura, humedad, topic(2) AS dispositivoId, timestamp() AS ts
FROM 'casa-demo/+/telemetria'
WHERE temperatura > 30

El dispositivo: publicar la telemetría

Siguiendo la convención de tópicos de la parte 13, el ESP32 publica en un tópico con su nombre:

void publicarTelemetria(float temperatura, float humedad) {
  JsonDocument doc;
  doc["temperatura"] = temperatura;
  doc["humedad"] = humedad;
  char buffer[128];
  size_t n = serializeJson(doc, buffer);
  String topico = String("casa-demo/") + THING_NAME + "/telemetria";
  client.publish(topico.c_str(), buffer, n);
}

Recuerda permitir ese tópico en la política del dispositivo (iot:Publish sobre topic/casa-demo/${iot:Connection.Thing.ThingName}/telemetria).

Regla 1: guardar las lecturas en DynamoDB

Con la tabla de lecturas de la parte 7 (clave de partición dispositivoId, de ordenación ts):

SELECT temperatura, humedad,
       topic(2) AS dispositivoId,
       parse_time("yyyy-MM-dd'T'HH:mm:ss'Z'", timestamp()) AS ts,
       floor(timestamp() / 1000) + 2592000 AS expira
FROM 'casa-demo/+/telemetria'

La acción DynamoDBv2 escribe cada fila del resultado como un item, con un atributo por columna. El campo expira (ahora + 30 días, en segundos) es el atributo de TTL: DynamoDB borrará la lectura sola al mes.

En la consola: AWS IoT Core → Message routing → Rules → Create rule, pega la consulta, elige la acción DynamoDBv2, la tabla y un rol. La consola puede crear el rol con el permiso exacto (dynamodb:PutItem sobre esa tabla).

Con la CLI, la regla es un JSON:

{
  "sql": "SELECT temperatura, humedad, topic(2) AS dispositivoId, parse_time(\"yyyy-MM-dd'T'HH:mm:ss'Z'\", timestamp()) AS ts, floor(timestamp() / 1000) + 2592000 AS expira FROM 'casa-demo/+/telemetria'",
  "awsIotSqlVersion": "2016-03-23",
  "actions": [
    { "dynamoDBv2": { "roleArn": "arn:aws:iam::CUENTA:role/regla-lecturas", "putItem": { "tableName": "lecturas" } } }
  ],
  "errorAction": {
    "cloudwatchLogs": { "roleArn": "arn:aws:iam::CUENTA:role/regla-lecturas", "logGroupName": "/iot/reglas/errores" }
  }
}
aws iot create-topic-rule --rule-name guardar_lecturas --topic-rule-payload file://regla.json

Los nombres de reglas solo admiten letras, números y guion bajo.

Regla 2: una alerta por correo con SNS

Primero, un tema de SNS con tu correo suscrito:

aws sns create-topic --name alertas-casa
aws sns subscribe --topic-arn arn:aws:sns:REGION:CUENTA:alertas-casa \
  --protocol email --notification-endpoint tu@correo.com
# Confirma la suscripción desde el enlace que llega al correo

Después, la regla:

SELECT concat('Temperatura alta en ', topic(2), ': ', cast(temperatura AS String), ' °C') AS mensaje
FROM 'casa-demo/+/telemetria'
WHERE temperatura > 30

Con la acción SNS y el formato de mensaje RAW, llega un correo cada vez que un sensor publica más de 30 °C.

Cuidado: si el sensor publica cada minuto y la temperatura sigue alta, llega un correo por minuto. Para un aviso único hay que guardar estado (por ejemplo, con una Lambda que recuerde la última alerta, o con AWS IoT Events, que modela estados como "normal" y "alarma").

La acción de error

Si una acción falla (la tabla no existe, el rol no tiene permiso), el mensaje se pierde en silencio. La acción de error (errorAction) envía el detalle del fallo a otro destino, como CloudWatch Logs o un tema de SNS. Configúrala siempre: es la única forma de enterarte.

Probar sin el ESP32

Desde AWS IoT Core → Test → MQTT test client, publica en casa-demo/sensor-patio/telemetria:

{ "temperatura": 31.5, "humedad": 40 }

Deberías ver el item nuevo en la tabla de DynamoDB y recibir el correo. Si no pasa nada, revisa el grupo de registros de la acción de error, o activa los registros de AWS IoT en CloudWatch.

Errores comunes

¿Cuánto cuesta?

Se cobra por regla disparada y por acción ejecutada, por millón, más el costo del servicio de destino (escrituras de DynamoDB, mensajes de SNS). Una casa con unos pocos sensores que publican cada minuto genera unas decenas de miles de mensajes al mes: fracciones de centavo en reglas. Los correos de SNS tienen su propia capa gratuita. La estimación completa está en la parte 22.

Preguntas frecuentes

¿Reglas o una Lambda suscrita a todo?

Las reglas no necesitan código ni servidores, escalan solas y cuestan menos. Usa una Lambda como acción solo cuando necesites lógica que el SQL no permite.

¿Puede una regla escribir en el Device Shadow?

Sí, con la acción de republicar en el tópico $aws/things/<thing>/shadow/update. Es útil, por ejemplo, para que un sensor cambie el estado deseado de otro dispositivo.

¿Las reglas leen los mensajes del Shadow?

Sí: puedes usar los tópicos reservados del Shadow en el FROM, por ejemplo $aws/things/+/shadow/update/accepted, para guardar un historial de cambios de estado.

Sigue leyendo