Guía técnica · MQTT · firmware 2.7 y 2.8

El puente MQTT de Meshtastic

Cómo conectar una malla a MQTT sin inundar a tus vecinos, el ajuste que silenciosamente frena tus paquetes, y las dos cosas que el firmware 2.8 rompió sin avisar.

Cada afirmación de abajo se verificó contra una malla real y el código fuente del firmware.

1. Qué es MQTT en realidad

MQTT es una oficina de correos para mensajes. Hay un servidor en el medio llamado broker. Cualquiera puede publicar un mensaje en una casilla con nombre —un tópico (topic)— y cualquier otro puede suscribirse a ese tópico y recibir todo lo que se deje en él.

Nada se conecta directamente con nada más. Ese es todo el modelo, y es la razón por la que MQTT le queda bien a Meshtastic: dos mallas separadas por cientos de kilómetros pueden intercambiar paquetes por internet en lugar de por radio, con un broker como punto de encuentro.

2. Proxy de cliente vs. gateway

Ambos aparecen bajo «MQTT» en la app. No son lo mismo, y aquí empieza casi toda la confusión.

MODO PROXY DE CLIENTE MODO GATEWAY Nodo BLE Teléfono datos del teléfono Nodo WiFi / ethernet propio broker MQTT El nodo no necesita red propia. Se detiene al cerrar la app. El nodo funciona solo, 24/7. Se vuelve una puerta a tu malla.
El proxy toma prestado el internet de tu teléfono. El gateway tiene el suyo propio.

Configurar el modo proxy de cliente

Esto es lo que quieres si tu objetivo es ver tus propios nodos en un mapa o alimentar un tablero. Es la configuración segura.

mqtt.enabled = true
mqtt.proxy_to_client_enabled = true
mqtt.address = tu.broker.ejemplo
# deja uplink_enabled / downlink_enabled APAGADOS en cada canal

Tu nodo igual se reporta al broker. No empieza a empujar el tráfico de todos los demás hacia internet.

Configurar el modo gateway

network.wifi_enabled = true
mqtt.enabled = true
mqtt.proxy_to_client_enabled = false
mqtt.tls_enabled = true
mqtt.root = msh/TU_REGION

Apagar proxy_to_client_enabled es el interruptor que dice «yo manejo mi propia conexión». El nodo ahora habla con el broker haya o no un teléfono presente.

Ser gateway todavía no significa que estés puenteando nada. Por defecto el nodo publica solo sus propios paquetes y nada más. Retransmitir el tráfico de otros nodos es un ajuste aparte.

3. Uplink, downlink y por qué vienen apagados

Estas dos banderas se configuran por canal, en el gateway. Son las que de verdad unen dos mallas.

Tu malla local nodos en LoRa Malla lejana otro pueblo broker uplink downlink Ambas apagadas — el gateway publica solo sus propios paquetes. Nada cruza. Ambas encendidas — las dos mallas son, para todo efecto práctico, una sola malla.
Uplink y downlink son banderas por canal en el nodo gateway.

Por favor, no las enciendas por defecto

El downlink le cuesta tiempo en el aire a tus vecinos. Cada mensaje de la malla lejana se retransmite por tu RF local. En un preset lento, eso es tiempo de canal real que le quitas a todos a tu alrededor.

Tu lista de nodos se inunda de nodos distantes que nunca alcanzarás por radio —y publicas el tráfico de otras personas en un servidor que ellas nunca aceptaron.

Hay una buena razón para encenderlas: tienes dos mallas lejanas y quieres enlazarlas deliberadamente en un canal compartido. Si ese no es tu objetivo, deja ambas apagadas. Vienen apagadas por algo.

Si sí vas a puentear, activa uplink y downlink solo en el canal específico que estás compartiendo —no en tu canal primario, y no en todos.

4. «OK to MQTT» — el asesino silencioso de paquetes

Cada nodo lleva un ajuste llamado lora.config_ok_to_mqtt. Por defecto es false.

Cuando está en false, el nodo marca una bandera dentro de cada paquete que origina que significa «no me pongas en MQTT», y los gateways la respetan. Puedes tener el uplink activado, un broker sano y un gateway que te escucha perfectamente —y tus mensajes aún así nunca se publicarán.

Nodo A ok_to_mqtt = false Nodo B ok_to_mqtt = true se escucha bien se escucha bien Gateway uplink ACTIVADO descartado, sin error broker El nodo que envía decide si puede ser puenteado —no el operador del gateway.
Misma señal, mismo gateway, mismo broker. Solo cambia la bandera.
meshtastic --port COM11 --set lora.config_ok_to_mqtt true

# luego confirma que quedó
meshtastic --port COM11 --info | grep configOkToMqtt

En la app está bajo LoRa → Avanzado; el texto cambia entre versiones, así que busca «OK to MQTT» o «MQTT OK». Vuelve a leerlo después de configurarlo, y revísalo otra vez tras una actualización de firmware —a mí se me revirtió a mitad de sesión y perdí veinte minutos echándole la culpa al gateway.

Si recuerdas una sola cosa

«Veo sus mensajes pero ellos no ven los míos» es casi siempre esta bandera —no un desajuste de firmware, no un problema del broker. Revísala primero.

5. Tópicos protobuf y JSON

Bajo tu tópico raíz hay dos ramas, y saber cuál estás mirando explica la mayoría de los reportes de «mi tablero no muestra nada».

msh/PA/2 /e/ — protobuf /json/ — texto plano Sigue cifrado con la llave de tu canal El broker solo ve texto cifrado El gateway debe descifrarlo para armar el JSON El broker ve tus mensajes msh/PA/2/e/MESHPTY/!cce742aa raíz / versión / codificación / nombre del canal / gateway que publica
Dos codificaciones del mismo paquete —una mantiene tu llave fuera, la otra no.

Protobuf es el valor por defecto y casi siempre la opción correcta: compacto, cifrado de extremo a extremo, y legible por toda herramienta de Meshtastic. JSON es cómodo para Node-RED o Home Assistant porque no hay que decodificar nada —pero producirlo obliga al gateway a descifrar primero, así que tu texto plano termina en el broker.

En un canal privado

Deja json_enabled apagado. Encenderlo publica exactamente lo que tu PSK de canal estaba protegiendo. Si quieres datos legibles, suscríbete al tópico protobuf y descífralo localmente —tú tienes la llave, el broker no la necesita.

6. El firmware 2.8 rompe los DM a través de un gateway

Los mensajes directos van cifrados de extremo a extremo entre dos nodos. Un gateway que transporta el DM de otra persona genuinamente no puede leerlo —el mensaje no está dirigido al gateway.

En 2.7 esto no importaba. El gateway reenviaba el bloque cifrado a MQTT sin leerlo, y el otro extremo lo descifraba. Así cruzaban los DM un puente.

En 2.8 un paquete que el gateway no puede descifrar se clasifica como opaco (opaque), y el tráfico opaco se excluye deliberadamente de MQTT.

Tu nodo DM → un amigo LoRa Gateway en 2.8 no puede descifrar — no es para él OPAQUE_RELAY_ONLY Retransmisión LoRa ✓ la malla local igual lo recibe MQTT ✕ nunca se publica, sin error Los DM hacia o desde el propio gateway no se ven afectados —esos sí los puede descifrar.
Router.cpp:1613 retorna temprano ante el tráfico opaco, antes de llegar siquiera a la publicación MQTT.

El firmware declara la intención sin rodeos, en NextHopRouter.cpp:

// Opaque traffic is never admitted to PacketHistory, NodeDB,
// modules, phone, MQTT, or ACK handling.

Introducido por el PR #10967, «feat(security): enforce packet authenticity policies». Ningún ajuste de configuración lo sortea —la opción packet_signature_policy gobierna cómo se reciben los paquetes y solo aplica al tráfico que el nodo ya puede descifrar. Compatible, Balanced y Strict toman todos el mismo camino opaco.

Efecto práctico

En 2.8 no puedes mandar un DM a alguien a través de un puente MQTT. Los mensajes de canal siguen funcionando. Los DM al propio gateway siguen funcionando. Un DM que pasa a través, dirigido a un tercer nodo, muere en el gateway sin ningún error en ninguna parte.

Si los DM puenteados te importan, v2.7.26 es el último lanzamiento sin este comportamiento.

7. El firmware 2.8 casi duplica tu tiempo en el aire

El mismo PR agregó una firma XEdDSA a cada transmisión (broadcast): 64 bytes, más dos bytes de sobrecarga de protobuf, en cada paquete sin importar el largo del mensaje.

Firmware 2.7 — «Prueba meshpty», 14 caracteres puerto carga útil bf 20 bytes Firmware 2.8 — «test», 4 caracteres puerto msg bf firma XEdDSA — 66 bytes 76 bytes Tiempo en el aire en LONG_FAST (SF11 / BW250 / CR4-5), mensaje de cuatro caracteres: 477 ms → 928 ms (1.94×)
Un mensaje de cuatro caracteres en 2.8 pesa más en el aire que uno de catorce en 2.7.

La firma solo está condicionada por !pki_encrypted && isBroadcast(to) —no hay ajuste en tiempo de ejecución. Desactivarla significa una compilación personalizada con MESHTASTIC_EXCLUDE_XEDDSA. En un canal concurrido, esto conviene saberlo antes de actualizar una flota.

8. Qué se rompe de verdad entre versiones

Circula la afirmación de que los nodos 2.7 no pueden recibir de nodos 2.8. Yo me la creí, luego revisé el código fuente —no es cierto. Protobuf está hecho para esto: nanopb llega al campo de firma desconocido, lo salta y sigue (pb_decode.c, «No match found, skip data»).

Escenario¿Funciona?Por qué
Nodo 2.8 recibe de 2.7Nada raro en el paquete
Nodo 2.7 recibe de 2.8El campo de firma desconocido se salta
2.8 recibe de < 2.5.0NoDescarte pre-hop; esos paquetes no llevan datos de saltos
DM a través de un gateway 2.8NoEl tráfico opaco se excluye de MQTT
Paquete sin firmar de un firmante conocido, bajo Balanced/StrictNoSe trata como intento de downgrade
Cualquier nodo sin ok_to_mqttNoEl gateway respeta la bandera y lo descarta

Si tu síntoma es «ellos me ven pero yo no los veo», o al revés, la causa abrumadoramente probable es la bandera ok_to_mqtt o un canal con el uplink desactivado —no un desajuste de versión.

9. Lista de verificación

  1. ¿Estás en modo proxy o gateway? Confirma que proxy_to_client_enabled coincide con tu intención.
  2. ¿Está uplink_enabled activado para el canal específico que estás probando —no solo el primario?
  3. ¿Está lora.config_ok_to_mqtt en true en el nodo que envía? Vuelve a leerlo.
  4. ¿Acabas de cambiar downlink? Reinicia el gateway. Las suscripciones se construyen solo cuando la sesión MQTT se conecta, así que publicar funcionará mientras que recibir, en silencio, nunca lo hará.
  5. ¿Estás mirando el tópico correcto? El protobuf cae bajo /2/e/; la rama /2/json/ está vacía a menos que json_enabled esté encendido.
  6. ¿Esperas que un DM cruce el puente? En 2.8 no lo hará. Usa un mensaje de canal, o corre 2.7.26.
  7. ¿Sigues atascado? Suscríbete tú mismo a msh/# y observa. Si aparecen los paquetes de tu propio gateway pero no los retransmitidos, es la bandera del paso 3.

Sobre esta guía

Se agradecen correcciones. Las referencias de firmware son a b68de08 (2.8.0) y v2.7.26.54e0d8d; las cifras de tiempo en el aire están calculadas para SF11 / BW250 / CR4-5 y variarán en otros presets.