DEV Community

Cover image for Saber si un ESP32 está conectado: eventos de ciclo de vida en AWS IoT
Steven Carvajal
Steven Carvajal

Posted on Originally published at iot.gripe

Saber si un ESP32 está conectado: eventos de ciclo de vida en AWS IoT

Publicado originalmente en iot.gripe, como parte 19 de la serie "Domótica con ESP32 y AWS desde cero".

El Device Shadow guarda el estado aunque el dispositivo esté apagado (parte 5). Eso es bueno para no perder órdenes, pero tiene un efecto secundario: la app puede mostrar "encendido" para una luz cuyo ESP32 lleva horas desconectado. El usuario necesita saber si el dispositivo está en línea.

AWS IoT Core publica un evento cada vez que un cliente MQTT se conecta o se desconecta. En esta parte vemos cómo leerlos, cómo guardar el estado de conexión para la app y qué hacer con los nodos que no hablan directamente con AWS.

Los eventos de conexión

AWS IoT publica en dos tópicos reservados:

$aws/events/presence/connected/<clientId>
$aws/events/presence/disconnected/<clientId>
Enter fullscreen mode Exit fullscreen mode

Un evento de desconexión se ve así:

{
  "clientId": "mi-esp32",
  "timestamp": 1760180400000,
  "eventType": "disconnected",
  "clientInitiatedDisconnect": false,
  "sessionIdentifier": "00000000-0000-0000-0000-000000000000",
  "principalIdentifier": "…",
  "disconnectReason": "MQTT_KEEP_ALIVE_TIMEOUT",
  "versionNumber": 12
}
Enter fullscreen mode Exit fullscreen mode

El campo disconnectReason es oro para depurar:

Motivo Qué significa
CLIENT_INITIATED_DISCONNECT El dispositivo cerró la conexión a propósito
MQTT_KEEP_ALIVE_TIMEOUT Dejó de responder: sin energía, sin Wi-Fi o bloqueado
CONNECTION_LOST Se cortó la conexión de red
DUPLICATE_CLIENTID Otro cliente se conectó con el mismo client ID
AUTHORIZATION_FAILURE Intentó algo que su política no permite

Para verlos en vivo, suscríbete a $aws/events/presence/# desde el MQTT test client de la consola y reinicia tu ESP32.

Cuánto tarda en detectarse una desconexión

Si el dispositivo se desconecta limpiamente, el evento es inmediato. Si se queda sin energía, AWS no se entera hasta que vence el keepalive: espera 1,5 veces el intervalo de keepalive sin recibir nada. Con el valor por defecto de muchas librerías (60 segundos), son 90 segundos.

Para detectarlo antes, baja el keepalive en el ESP32. Con la librería MQTT de 256dpi:

client.setKeepAlive(30);  // segundos; AWS detectaría la caída en unos 45 s
Enter fullscreen mode Exit fullscreen mode

Un keepalive más bajo envía más pings (un mensaje pequeño cada intervalo), con un costo de conexión y de batería algo mayor.

Guardar el estado de conexión en el Shadow

La app podría suscribirse a los eventos, pero si abre después de la desconexión, se la pierde. Es mejor guardar el estado donde la app ya mira: el Shadow. Una regla de IoT (parte 14) lo hace sin código. La consulta arma el documento con el formato del Shadow:

SELECT { 'reported': { 'conectado': eventType = 'connected', 'desde': timestamp } } AS state
FROM '$aws/events/presence/+/+'
Enter fullscreen mode Exit fullscreen mode

Con la acción Republish al tópico de un Shadow con nombre:

$$aws/things/${topic(5)}/shadow/name/conexion/update
Enter fullscreen mode Exit fullscreen mode
  • topic(5) es el client ID (el quinto segmento del tópico). Funciona si el client ID coincide con el nombre del Thing, como exige la política de la parte 13.
  • $$aws: en la acción Republish, el $ inicial de un tópico reservado se escribe doble.
  • Un Shadow con nombre (conexion) separa el estado de conexión del estado de las luces: actualizarlo no genera deltas en el otro.

La app lee conectado y muestra el dispositivo en gris cuando es false.

El orden de los eventos

Los eventos pueden llegar desordenados: si un ESP32 se reinicia rápido, el connected de la sesión nueva puede llegar antes que el disconnected de la vieja. Si guardas el último que llega, el dispositivo aparecería desconectado estando en línea.

Dos formas de protegerse:

  • comparar el timestamp (o versionNumber) antes de sobrescribir, en una Lambda;
  • ignorar un disconnected si su sessionIdentifier no es el de la sesión actual.

Para un panel doméstico, una alternativa simple: cuando la app ve conectado: false, pide el Shadow de estado; si el dispositivo responde a una orden, está en línea.

Last Will: el aviso del propio dispositivo

MQTT tiene un mecanismo estándar: al conectar, el dispositivo registra un mensaje de última voluntad (Last Will and Testament). Si la conexión se pierde sin un cierre limpio, el broker lo publica en su nombre:

client.setWill("casa-demo/mi-esp32/estado", "{\"conectado\":false}", true, 1);
client.connect(THING_NAME);
client.publish("casa-demo/mi-esp32/estado", "{\"conectado\":true}", true, 1);
Enter fullscreen mode Exit fullscreen mode

AWS IoT Core admite Last Will y mensajes retenidos. La política del dispositivo debe permitir publicar en ese tópico (y iot:RetainPublish si el mensaje es retenido).

Eventos de ciclo de vida Last Will
Configuración en el dispositivo Ninguna Sí, al conectar
Incluye el motivo Sí No
Estándar MQTT No, propio de AWS Sí

Nodos detrás de un hub

Los nodos ESP-NOW no se conectan a AWS: para AWS IoT, solo existe el hub. Si el hub está en línea pero un nodo se quedó sin energía, ningún evento lo dirá.

La solución es que el hub vigile a los nodos:

  • cada nodo envía un latido (heartbeat) cada cierto tiempo, o el hub detecta que no confirma órdenes (parte 4);
  • el hub publica en su Shadow qué nodos responden, por ejemplo "nodos": {"sala": true, "patio": false}.

Consultar la conexión sin guardar nada

Si activas la indexación de flota (Fleet Indexing) con datos de conectividad, puedes consultar qué dispositivos están conectados:

aws iot search-index --query-string "connectivity.connected:false"
Enter fullscreen mode Exit fullscreen mode

Útil para un panel de administración con muchos dispositivos. Tiene un costo propio por indexación y consultas.

Preguntas frecuentes

¿Los eventos de conexión cuestan algo?

Se publican como mensajes MQTT y se cobran como tales cuando alguien los recibe (una suscripción o una regla). Para una casa, fracciones de centavo.

¿Por qué mi dispositivo aparece y desaparece cada pocos segundos?

Mira el disconnectReason. DUPLICATE_CLIENTID indica dos clientes con el mismo client ID; AUTHORIZATION_FAILURE, un permiso que falta en la política.

¿Y si el Wi-Fi funciona pero el dispositivo está bloqueado?

Si el programa se bloquea, deja de responder a los pings y AWS lo verá como MQTT_KEEP_ALIVE_TIMEOUT. Para que se recupere solo, activa el watchdog del ESP32.

Top comments (0)