01 · Punto de partida
El esquema como contrato
En los cuatro temas anteriores aprendiste las piezas de MQTT: qué es un broker, cómo se escriben los tópicos, cómo se conecta un cliente y qué garantías hay. Falta decidir qué nombres usar y qué poner en los mensajes, y esa decisión se parece más al diseño de una interfaz que a la programación de un dispositivo. Los nombres de los tópicos quedan grabados en el firmware de miles de equipos; las suscripciones de los servicios, los paneles y las listas de acceso del broker dependen de ellos; y cualquier cambio exige coordinar a todos.
Un esquema bien diseñado es invisible: los servicios nuevos se suscriben con un filtro y funcionan, las listas de acceso se escriben con una sola regla, y agregar un tipo de sensor no rompe nada. Uno mal diseñado se paga durante años: filtros imposibles, permisos que no se pueden expresar, tráfico desperdiciado y migraciones dolorosas.
Los números del laboratorio salen de armar los mensajes y contar sus bytes reales con la codificación de MQTT 3.1.1; podés reproducirlos con el código del tema.
02 · Reglas de oro
Principios de un buen esquema
Los temas 26 y 27 dieron las reglas sintácticas. Estos son los principios de diseño, que las completan:
- De lo general a lo particular. Cada nivel acota al anterior:
sitio / dispositivo / canal / recurso. Así un filtro con comodines selecciona por sitio, por dispositivo o por tipo de dato, y una lista de acceso puede otorgar permisos por rama. - Cada nivel significa una sola cosa, siempre la misma en todo el árbol. Si el segundo nivel es a veces un dispositivo y a veces una habitación, ningún filtro con
+funciona. - El tópico es una dirección estable, no un dato. No lleva horas, contadores ni valores variables (tema 26). Lo que cambia con cada mensaje va en la carga.
- La dirección del mensaje está en el nombre. Se distingue lo que publica el dispositivo (telemetría, estado, eventos, respuestas) de lo que publica el servicio para el dispositivo (comandos, configuración). Esa separación permite que las listas de acceso digan «el dispositivo escribe aquí y lee allá».
- El identificador del dispositivo va en el tópico, no solo en la carga: es lo que permite filtrar, autorizar y enrutar sin abrir los mensajes (el broker no los interpreta).
- Minúsculas, ASCII, sin espacios, cortos. Cada byte del tópico viaja en cada publicación, y los nombres con tildes o espacios generan errores de codificación.
- Sin datos personales ni secretos en el tópico: aparece en registros, listas de acceso y herramientas de monitoreo.
- Pocos niveles. Entre tres y cinco alcanzan; más profundidad complica los filtros sin aportar claridad.
03 · Estructura
Un esquema modelo: los seis canales
Casi todos los dispositivos intercambian seis clases de información, y conviene darle a cada una su propio canal (un nivel del tópico), con su calidad de servicio y su retención. Es la aplicación de lo visto en el tema 28 a un esquema concreto.
| Canal | Quién publica | Ejemplo de tópico | QoS | Retenido | Contenido |
|---|---|---|---|---|---|
tel | Dispositivo | casa/camara07/tel/temperatura | 0 | No (o sí, con la hora) | Mediciones periódicas |
estado | Dispositivo (y el broker por el testamento) | casa/camara07/estado | 1 | Sí | En línea o fuera de línea, versión del firmware |
evt | Dispositivo | casa/camara07/evt/puerta | 1 | No | Eventos puntuales: puerta abierta, batería baja |
cmd | Servicio | casa/camara07/cmd | 1 | No | Órdenes con identificador y vencimiento |
ack | Dispositivo | casa/camara07/ack | 1 | No | Resultado de cada orden, con su identificador |
cfg | Servicio | casa/camara07/cfg | 1 | Sí | Configuración vigente, con su versión |
La separación en canales tiene una recompensa inmediata en la seguridad. Con la regla de patrón por usuario del tema 26, el control de acceso de toda la flota se escribe en cuatro líneas, y expresa justo lo que cada actor debe poder hacer:
# acl: el dispositivo (usuario = identificador) escribe lo suyo y lee solo órdenes y configuración
pattern write casa/%u/tel/#
pattern write casa/%u/estado
pattern write casa/%u/evt/#
pattern write casa/%u/ack
pattern read casa/%u/cmd
pattern read casa/%u/cfg
# el servicio de control: lee la telemetría, el estado, los eventos y las respuestas; escribe órdenes y configuración
user control
topic read casa/+/tel/#
topic read casa/+/estado
topic read casa/+/evt/#
topic read casa/+/ack
topic write casa/+/cmd
topic write casa/+/cfg
Con ese esquema, un dispositivo comprometido no puede dar órdenes a otro, ni leer su telemetría, ni siquiera publicar fuera de su rama. La estructura del tópico es la que hace posible la regla.
04 · Una decisión con costo
Granularidad: un tópico por dato o uno por dispositivo
Un dispositivo que mide temperatura, humedad, presión y batería tiene dos formas naturales de publicar:
- Un tópico por magnitud (
…/tel/temperatura,…/tel/humedad…), cada uno con su mensaje. Quien solo quiere la temperatura se suscribe a esos tópicos y recibe únicamente eso; cada magnitud puede tener su propia retención, su permiso y su ritmo. - Un tópico por dispositivo (
…/tel) con un JSON que lleva todas las magnitudes juntas. El broker maneja un mensaje por ciclo en lugar de varios.
Ninguna es la correcta en abstracto, porque pagan costos distintos. Con un tópico por magnitud, el broker recibe y reparte más mensajes pequeños (cada uno arrastra su tópico y sus encabezados) y hay más tópicos distintos que mantener; con un mensaje único, quien quiere un solo dato recibe todos los demás. El laboratorio de este tema mide ese compromiso con mensajes reales: con 10.000 dispositivos y 10 magnitudes, el diseño por magnitud pasa de 167 a 1667 mensajes por segundo y de 10.000 a 100.000 tópicos, mientras que el mensaje único hace que un suscriptor que solo quiere la temperatura reciba 29,5 KB/s en lugar de 14,8.
| Criterio | Favorece un tópico por magnitud | Favorece un mensaje por dispositivo |
|---|---|---|
| Quién consume | Muchos suscriptores, cada uno con interés en pocas magnitudes | Pocos consumidores que usan casi todos los datos juntos |
| Ritmo de cada dato | Cada magnitud cambia a su propio ritmo (la temperatura cada minuto, la batería cada hora) | Todas se miden y se envían a la vez |
| Permisos | Hay datos que algunos servicios no deben ver | Todos los consumidores pueden ver todo |
| Retención | Interesa el último valor de cada magnitud por separado | Interesa el último «paquete» completo |
| Batería del dispositivo | — | Un solo mensaje por ciclo es lo más barato: menos paquetes y menos tiempo con la radio encendida |
| Carga del broker | Flota chica o mediana | Flota grande; decenas de miles de mensajes por segundo |
| Consistencia de los datos | — | Las magnitudes de un mismo instante llegan juntas, con la misma marca de tiempo |
Una solución intermedia, frecuente en la práctica, es publicar el mensaje único desde el dispositivo (lo más barato para la batería y para el canal) y dejar que el broker o un servicio intermedio lo descomponga en tópicos por magnitud para quienes los quieren separados. El costo de abrir el mensaje se paga en el servidor, que tiene energía de sobra, y no en el dispositivo.
05 · El contenido
Las cargas útiles
El broker no interpreta las cargas, por lo que el formato es un acuerdo entre quienes publican y quienes leen. Todo lo visto en los temas 12 y 21 vale acá, con estas pautas específicas:
- Un formato único para todo el sistema, idealmente JSON compacto (o CBOR si el canal es muy exigente). Mezclar texto plano, JSON y binario en tópicos hermanos complica a todos los lectores.
- Siempre la hora de la medición, en segundos Unix o ISO 8601 UTC, y no la de recepción. Es lo que permite ordenar, detectar retrasos y reprocesar. Enviar «solo el valor» ahorra unos bytes y cuesta la capacidad de entender cuándo ocurrió.
- Unidades fijas y documentadas (enteros escalados con la escala en el esquema, nombres con la unidad cuando haga falta).
- Un campo de versión o una forma de saber qué estructura tiene el mensaje, para poder evolucionarla.
- Un identificador de mensaje o de secuencia en los que puedan duplicarse (QoS 1): permite descartar repeticiones.
- Los comandos llevan identificador, acción, parámetros y vencimiento; las respuestas, el identificador de la orden y el resultado (tema 11).
| Canal | Carga de ejemplo |
|---|---|
tel | {"t":1794061920,"temp":43,"hum":612,"bat":87} |
estado | {"e":"online","fw":"1.2.0","t":1794061800} (el testamento publica {"e":"offline"}) |
evt/puerta | {"id":8812,"e":"abierta","t":1794061921} |
cmd | {"id":401,"a":"abrir","min":10,"vence":1794062520} |
ack | {"id":401,"r":"ok","t":1794061950} |
cfg | {"ver":17,"periodo_s":900,"umbral_c":8.5} |
MQTT 5 agrega una ayuda para esto: una propiedad de tipo de contenido (por ejemplo application/json) que acompaña al mensaje y le dice al lector cómo interpretarlo, y propiedades de usuario (pares nombre-valor) que sirven de metadatos sin tocar la carga. Si el broker y la biblioteca lo soportan, evitan poner información de transporte dentro del JSON.
06 · Preguntar y responder
Comandos con respuesta
La publicación y suscripción es un modelo de «uno dice, todos oyen». Pero un comando es una conversación: el servicio pide algo y espera saber si se hizo. MQTT no tiene un pedido-respuesta nativo (en la versión 3.1.1), y se construye con dos canales y un identificador:
- El servicio publica en
…/cmdun mensaje con un identificador único ("id":401), la acción y un vencimiento. - El dispositivo, suscrito a
…/cmd, valida y ejecuta la orden (idempotente). - El dispositivo publica en
…/ackel resultado, repitiendo el identificador ("id":401,"r":"ok"). - El servicio, suscrito a
casa/+/ack, empareja la respuesta con la orden por el identificador. Si no llega en cierto tiempo, la da por fallida o la reenvía (por eso la orden es idempotente).
Dos detalles. Primero, el identificador debe ser único y viajar en ambos sentidos: es lo que permite varias órdenes en vuelo a la vez sin confundirlas. Segundo, MQTT 5 incorpora esto al protocolo con las propiedades tópico de respuesta (el servicio indica dónde quiere la respuesta) y datos de correlación (un identificador que el dispositivo devuelve tal cual), lo que simplifica el esquema cuando está disponible.
07 · Con el tiempo
Evolución y gobierno del esquema
El esquema va a cambiar: aparecerán sensores nuevos, canales nuevos, requisitos que hoy no existen. Algunas decisiones lo hacen soportable:
- Versionar la carga, no el tópico, cuando se pueda. Agregar un campo opcional a un JSON no rompe a nadie; renombrar un tópico rompe a todos. Un campo
"v"en la carga permite cambiar la estructura sin tocar las direcciones. - Si hay que cambiar un tópico, publicar en ambos durante la transición. Los dispositivos nuevos usan el nombre nuevo; el servicio escucha los dos; los viejos se retiran cuando ya no queden en campo (tema 22).
- Un prefijo de versión en la raíz (
v1/casa/…) es una opción cuando se prevén cambios incompatibles frecuentes, a costa de un nivel más en cada mensaje. - Un registro del esquema: un documento (o mejor, un archivo versionado) que lista cada tópico, quién publica, quién se suscribe, la calidad de servicio, la retención y el formato de la carga. Es la fuente de verdad para firmware, servicios y listas de acceso.
- Pruebas del esquema: un verificador automático (como el del código de este tema) que examina los nombres propuestos antes de que lleguen a producción.
Para dominios específicos existen esquemas ya definidos que vale la pena conocer antes de inventar uno. En la industria, Sparkplug B fija tópicos, formato de carga (binario), nacimiento y muerte de dispositivos y gestión del estado, de modo que equipos de distintos fabricantes se entiendan. En el hogar, plataformas como Home Assistant definen un mecanismo de descubrimiento por el que un dispositivo publica una descripción de sí mismo en un tópico conocido y la plataforma lo integra sola. Si tu sistema va a convivir con esos ecosistemas, adoptar su convención es más barato que traducir.
08 · Analogía con programación
Verificar tópicos y comparar diseños en Python
El programa tiene dos partes. La primera es un verificador de nombres de tópico que separa los errores (nivel vacío, comodines al publicar) de los avisos (mayúsculas, espacios y tildes, demasiados niveles o largo excesivo, una fecha o un contador dentro del tópico), y lo prueba con seis nombres. La segunda arma los mensajes reales de tres diseños para un dispositivo con 1, 4 o 10 magnitudes (un tópico por magnitud con JSON que lleva valor y hora, un tópico por magnitud con solo el valor, y un mensaje único por dispositivo) y calcula, para 10.000 dispositivos que publican cada 60 segundos, los mensajes por segundo, los kilobytes por segundo hacia el broker y los que recibe un suscriptor interesado solo en la temperatura. Cuenta los bytes con la codificación de MQTT 3.1.1 más 40 bytes de encabezados de red por paquete.
Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.
import json
import re
# ---------- Parte 1: un verificador de nombres de tópico ----------
def revisar(topico):
errores, avisos = [], []
if not topico or "+" in topico or "#" in topico:
errores.append("vacío o con comodines")
if topico.startswith("/") or topico.endswith("/") or "//" in topico:
errores.append("nivel vacío (barra inicial, final o doble)")
if any(c.isupper() for c in topico):
avisos.append("mayúsculas")
if " " in topico or not topico.isascii():
avisos.append("espacios, tildes o símbolos")
niveles = topico.strip("/").split("/")
if len(niveles) > 6:
avisos.append("más de 6 niveles")
if len(topico) > 64:
avisos.append("más de 64 caracteres")
if any(re.fullmatch(r"\d{4}-\d{2}-\d{2}.*|\d{9,}", n) for n in niveles):
avisos.append("una fecha o un contador en el tópico")
return errores, avisos
for t in ("casa/camara07/tel/temperatura", "/Casa/Cámara 07/Temperatura", "casa//estado", "casa/camara07/#",
"casa/camara07/lectura/2026-11-07T14:32", "casa/camara07/tel/1794061920"):
e, a = revisar(t)
partes = (["ERROR: " + "; ".join(e)] if e else []) + (["aviso: " + "; ".join(a)] if a else [])
estado = " | ".join(partes) if partes else "bien"
print(f"{t:<42} -> {estado}")
# ---------- Parte 2: un tópico por magnitud o uno por dispositivo ----------
IP_TCP = 40
MAGNITUDES = ["temp", "hum", "pres", "bat", "luz", "co2", "pm25", "rssi", "vib", "cor"]
VALORES = [43, 612, 1013, 87, 340, 415, 12, 61, 5, 120]
TS = 1794061920
def largo_publish(topico, carga):
cuerpo = 2 + len(topico) + len(carga)
resto = 1 if cuerpo < 128 else 2
return 1 + resto + cuerpo + IP_TCP
def mensajes(diseno, n):
"""Lista de (tópico, carga) que publica un dispositivo en cada ciclo con n magnitudes."""
if diseno == "una por magnitud":
return [(f"casa/camara07/tel/{MAGNITUDES[i]}", json.dumps({"v": VALORES[i], "t": TS}, separators=(",", ":"))) for i in range(n)]
if diseno == "valor solo":
return [(f"casa/camara07/tel/{MAGNITUDES[i]}", str(VALORES[i])) for i in range(n)]
carga = {"t": TS, **{MAGNITUDES[i]: VALORES[i] for i in range(n)}} # un solo mensaje con todo
return [("casa/camara07/tel", json.dumps(carga, separators=(",", ":")))]
def flujo(diseno, n, dispositivos, intervalo_s):
msgs = mensajes(diseno, n)
por_ciclo = len(msgs)
bytes_ciclo = sum(largo_publish(t, c) for t, c in msgs)
temp = msgs[0] # lo que recibe un suscriptor que solo quiere temperatura
return (dispositivos * por_ciclo / intervalo_s, # mensajes por segundo en el broker
dispositivos * bytes_ciclo / intervalo_s / 1000, # KB/s hacia el broker (y hacia un suscriptor que quiere todo)
dispositivos * largo_publish(*temp) / intervalo_s / 1000) # KB/s hacia un suscriptor de solo temperatura
print()
print("magnitudes diseño mensajes/s KB/s al broker KB/s al que quiere solo temperatura")
for n in (1, 4, 10):
for diseno in ("una por magnitud", "valor solo", "un mensaje por dispositivo"):
m, kb, kb_t = flujo(diseno, n, 10_000, 60)
print(f"{n:>9} {diseno:<26} {m:>8,.0f} {kb:>14.1f} {kb_t:>24.1f}")
print()
for n in (4, 10):
print(f"Con {n} magnitudes, ejemplo del mensaje único:", mensajes("un mensaje por dispositivo", n)[0][1])
Resultado con los valores iniciales. El verificador deja pasar casa/camara07/tel/temperatura; marca error y avisos en /Casa/Cámara 07/Temperatura (nivel vacío inicial, mayúsculas, espacios y tilde); error en casa//estado (nivel vacío) y en casa/camara07/# (comodín al publicar); y avisos en los tópicos con una fecha (y una mayúscula) o un contador. Para 10.000 dispositivos cada 60 s: con una magnitud, los tres diseños mueven 167 mensajes por segundo (14,8; 11,3 y 14,5 KB/s). Con 4 magnitudes, un tópico por magnitud pasa a 667 mensajes por segundo y 59,5 KB/s (45,5 si solo se envía el valor), mientras que el mensaje único se queda en 167 y 19,7 KB/s; el suscriptor que solo quiere temperatura recibe 14,8 KB/s con el primer diseño y 19,7 con el único. Con 10 magnitudes: 1667 mensajes por segundo y 148,2 KB/s (113,2 con solo el valor) contra 167 mensajes y 29,5 KB/s del mensaje único; el suscriptor de temperatura recibe 14,8 KB/s con un tópico por magnitud y 29,5 con el único.
Tres conclusiones. Una: un mensaje por dispositivo reduce el tráfico hacia el broker 5 veces con 10 magnitudes (29,5 contra 148,2 KB/s) y los mensajes 10 veces. Otra: un tópico por magnitud entrega justo lo pedido: el suscriptor selectivo recibe 14,8 KB/s en cualquier caso, mientras que con el mensaje único el costo para él crece con las magnitudes. Y la tercera: enviar solo el valor ahorra 24 % de bytes pero se pierde la hora, el dato que más cuesta recuperar después.
09 · Exploración interactiva
¿Cuántos tópicos, cuántos mensajes?, de extremo a extremo
Este laboratorio arma los mismos mensajes del código anterior y cuenta sus bytes. Elegí la cantidad de dispositivos, las magnitudes que mide cada uno, cada cuánto publican y el diseño. Las barras comparan los tres diseños en mensajes por segundo, en kilobytes por segundo hacia el broker y en kilobytes por segundo hacia un suscriptor interesado solo en la temperatura; el diseño elegido va resaltado. Abajo se muestra un ejemplo del mensaje que se publica.
Granularidad de los tópicos
Elegí los parámetros y presioná «Calcular».
Recorrido guiado
- Con los valores iniciales (10.000 dispositivos, 10 magnitudes, cada 60 s, un mensaje por dispositivo), calculá. 167 mensajes por segundo, 29,5 KB/s al broker, 10.000 tópicos y 29,5 KB/s para quien solo quiere la temperatura: «Manda datos de más a quien quiere uno».
- Cambiá a Un tópico por magnitud, con JSON: 1667 mensajes por segundo (10 veces más), 148,2 KB/s (5 veces más) y 100.000 tópicos; en cambio, el suscriptor de temperatura recibe 14,8 KB/s, la mitad. «Muchos mensajes para el broker».
- Probá solo el valor: 113,2 KB/s, 24 % menos que con JSON. El ahorro es real, pero el mensaje
43no dice cuándo se midió; si llega tarde por un corte de red, nadie lo puede saber. - Bajá a 4 magnitudes con el mensaje único: 167 mensajes y 19,7 KB/s; con tópicos por magnitud, 667 mensajes y 59,5 KB/s. La diferencia se achica a 4 veces en mensajes.
- Con 1 magnitud los tres diseños son prácticamente iguales (14,8; 11,3 y 14,5 KB/s, 167 mensajes). La granularidad solo importa cuando hay varios datos por dispositivo.
- Subí a 10 segundos con 10.000 dispositivos y 10 magnitudes: el diseño por magnitud llega a 10.000 mensajes por segundo (una carga que ya exige un broker dimensionado para ello), mientras que el mensaje único se queda en 1000. En flotas grandes con ritmo alto, la granularidad decide si el broker aguanta.
Desafío: el costo de los tópicos de más
Un diseño publica en casa/camara07/tel/temperatura (29 caracteres) un valor de 2 caracteres. El paquete MQTT mide 1 + 1 + 2 + 29 + 2 = 35 bytes, más 40 de encabezados de red: 75 bytes, de los cuales 2 son el dato y 29 el nombre del tópico. Es decir, el 39 % del paquete es el nombre del tópico y el 3 % el dato. Acortar el esquema (por ejemplo, c/c07/t/temp, 12 caracteres) ahorra 17 bytes por mensaje: con 10.000 dispositivos y 4 magnitudes cada minuto, 667 mensajes por segundo × 17 bytes = 11,3 KB/s, casi un quinto de los 59,5 KB/s. Pero se pierde legibilidad, y los nombres crípticos se pagan en depuración. MQTT 5 ofrece una salida mejor: los alias de tópico, que reemplazan el nombre por un número de 2 bytes después de usarlo una vez en la conexión. Un esquema legible y un tráfico chico no son incompatibles si el protocolo ayuda; si no, hay que elegir con números en la mano.
10 · Método de trabajo
Lista de verificación del esquema
- Listá los actores (dispositivos, paneles, servicios) y qué publica y qué lee cada uno.
- Definí los canales (
tel,estado,evt,cmd,ack,cfg) con su QoS y su retención. - Armá el árbol de general a particular, con un significado por nivel, pocos niveles y nombres en minúsculas, ASCII y cortos.
- Verificá cada nombre con un verificador automático: nada de niveles vacíos, comodines al publicar, fechas o contadores.
- Elegí la granularidad midiendo mensajes por segundo, tráfico y tópicos con tu flota y tu ritmo reales.
- Escribí las listas de acceso con patrones por usuario y comprobá que un dispositivo no puede salir de su rama.
- Definí un formato único de carga, con hora de la medición, versión, identificadores y unidades documentadas.
- Diseñá los comandos con identificador, vencimiento, respuesta y emparejamiento.
- Escribí el registro del esquema y mantenelo versionado junto al firmware.
- Planificá la evolución: versión en la carga, campos opcionales, transición con doble publicación.
Una prueba de oro: pedile a alguien que no participó del diseño que, mirando solo el árbol de tópicos, adivine quién publica cada uno y qué contiene. Si acierta, el esquema es claro; si duda, hay niveles ambiguos que corregir antes de fabricar los dispositivos.
11 · Comprensión
Confusiones frecuentes
«El esquema de tópicos se puede mejorar después, cuando los dispositivos ya estén en campo»
Cambiar un tópico exige actualizar el firmware de toda la flota y las suscripciones y permisos de todos los servicios. Es una de las decisiones más caras de cambiar. Se diseña antes de fabricar.
«Cuantos más niveles, más ordenado»
Más niveles complican los filtros, alargan cada mensaje y suelen ocultar ambigüedades. Entre tres y cinco alcanzan casi siempre.
«Poner el identificador del dispositivo en la carga es suficiente»
El broker no lee las cargas: sin el identificador en el tópico, no se puede filtrar, enrutar ni autorizar por dispositivo. En la carga puede repetirse, pero en el tópico es imprescindible.
«Un solo tópico para todo y un campo "tipo" en el JSON es más flexible»
Todos los suscriptores reciben todo y tienen que abrir cada mensaje para descartar el que no les sirve, y no hay forma de dar permisos por tipo. La flexibilidad que da el tópico es precisamente la de filtrar sin abrir.
«Enviar solo el valor, sin hora, es una buena optimización»
Ahorra unos bytes y pierde el dato más difícil de reconstruir. Con cortes de red, mensajes reenviados o procesos lentos, la hora de recepción no es la de la medición.
«Los comandos deben ir al mismo tópico que la telemetría para simplificar»
Mezcla direcciones opuestas: ya no se puede dar permiso de escritura a un servicio sin dárselo al dispositivo, ni al revés. Separar por canal es lo que permite que cada actor tenga justo los permisos que necesita.
12 · Práctica guiada
Predecí antes de comprobar
1. Arreglar un tópico
Corregí /Casa/Cámara 07/Temperatura/ y proponé el tópico definitivo de la temperatura de la cámara 07.
Ver solución
Problemas: barra inicial y final (niveles vacíos), mayúsculas, espacio y tilde. Versión corregida: casa/camara07/tel/temperatura, con el canal tel que indica que es telemetría del dispositivo.
2. Contar mensajes
Diez mil dispositivos con 10 magnitudes publican cada 60 s. ¿Cuántos mensajes por segundo entran con un tópico por magnitud y con un mensaje por dispositivo? ¿Cuántos tópicos hay en cada caso?
Ver solución
Por magnitud: 10.000 × 10 / 60 ≈ 1667 mensajes por segundo y 100.000 tópicos. Mensaje único: 10.000 / 60 ≈ 167 por segundo y 10.000 tópicos. Diez veces menos de ambos.
3. Lista de acceso
Escribí las reglas que dejan al usuario camara07 publicar telemetría y estado y leer solo comandos y configuración, usando patrones.
Ver solución
pattern write casa/%u/tel/#, pattern write casa/%u/estado, pattern read casa/%u/cmd y pattern read casa/%u/cfg (y, para las respuestas, pattern write casa/%u/ack). El %u se reemplaza por el nombre de usuario: una regla para toda la flota.
4. Retención de la configuración
El servicio publica la configuración vigente en casa/camara07/cfg. Un dispositivo nuevo se conecta una hora después. ¿Qué debe tener el mensaje para que la reciba?
Ver solución
Haberse publicado retenido y con QoS 1. Al suscribirse a casa/camara07/cfg, el broker entrega de inmediato el último retenido, la configuración vigente, aunque se haya publicado una hora antes. El mensaje lleva su versión para saber si cambió.
5. Comando con respuesta
El servicio envía {"id":401,"a":"abrir","min":10} y no recibe respuesta en 30 s. ¿Qué puede haber pasado y qué hace?
Ver solución
Posibilidades: el dispositivo está desconectado (la orden espera en su sesión), la orden se perdió, el dispositivo la ejecutó pero se perdió la respuesta. El servicio reenvía con el mismo identificador: como la orden es idempotente y el dispositivo reconoce el 401 ya ejecutado, responde de nuevo sin repetir la acción.
6. Elegir la granularidad
Un panel de un solo usuario muestra toda la telemetría de 50 dispositivos que miden 6 magnitudes cada minuto. ¿Qué diseño elegirías?
Ver solución
El mensaje único por dispositivo: un solo consumidor usa todos los datos, la flota es chica (300 mensajes por minuto si fuera por magnitud, contra 50), y el mensaje único ahorra batería y mantiene las magnitudes de un mismo instante juntas con una sola hora. La separación por tópico solo agregaría mensajes sin beneficiar a nadie.
13 · Síntesis
Ideas para recordar
- El esquema de tópicos es una API: cambiarlo en campo es tan costoso como cambiar una interfaz pública, así que se diseña antes y con más cuidado que el código.
- Un buen esquema va de lo general a lo particular, da un significado a cada nivel, mantiene el tópico como dirección estable (sin horas ni contadores), pone el identificador del dispositivo en el tópico y usa nombres cortos, en minúsculas y ASCII.
- Los seis canales de un dispositivo son telemetría (
tel), estado, eventos (evt), comandos (cmd), respuestas (ack) y configuración (cfg), cada uno con su QoS y su retención. - Separar los canales permite expresar los permisos con pocas reglas de patrón por usuario y confinar a cada dispositivo a su rama.
- La granularidad es un compromiso: un tópico por magnitud entrega justo lo pedido pero multiplica mensajes y tópicos en el broker; un mensaje por dispositivo reduce la carga y la batería pero manda datos de más al suscriptor selectivo.
- Las cargas usan un formato único con hora de la medición, versión, identificadores de mensaje y unidades fijas; enviar solo el valor ahorra bytes y pierde la hora.
- Los comandos se emparejan con sus respuestas por un identificador, son idempotentes y vencen; MQTT 5 ofrece tópico de respuesta y datos de correlación.
- El esquema evoluciona versionando la carga, agregando campos opcionales y publicando en ambos nombres durante las transiciones; se documenta en un registro versionado.
- Para industria y domótica existen convenciones (Sparkplug B, descubrimiento de Home Assistant) que conviene adoptar si el sistema debe convivir con esos ecosistemas.
¿Listo para el tema 30?
Antes de avanzar, escribí el registro de tópicos de tu proyecto en una tabla: tópico, quién publica, quién se suscribe, QoS, retención y ejemplo de carga. Pasalo por el verificador y calculá los mensajes por segundo y los tópicos distintos con tu flota prevista. Después escribí las reglas de acceso de un dispositivo y del servicio de control.
En el próximo tema cerramos el bloque de MQTT con MQTT o HTTP: cuándo usar cada uno, la comparación final con todo lo visto en los temas 19 a 29, para elegir con criterio el protocolo de cada parte de un sistema.