Matriz de capacidades por transporte
Esta página muestra qué hace hoy cada transporte, en cada dirección, y nombra las carencias.
Esta página se mantiene a mano contra la implementación, no se genera, así que puede quedarse atrás. Cuando ella y tu instancia discrepen, tu instancia tiene razón. Cada afirmación de más abajo se leyó del servicio que la implementa, no de un documento de diseño; todo lo que no pudo establecerse así aparece marcado como tal en lugar de rellenado. Una celda que exagera lo que hace la plataforma es un fallo de esta página; por favor, comunícalo.
Cómo leer esta página
Cada capacidad está en uno de tres estados, y no hay un cuarto:
| ● | Completo | Implementado, sin ninguna limitación específica de esta dirección. Las salvedades ordinarias que afectan al transporte entero están en sus notas. |
| ◐ | Parcial | Implementado, y falta algo concreto. La nota dice qué; léela antes de diseñar apoyándote en esa fila. |
| ○ | Ninguno | No implementado. Cuando se trata de una decisión deliberada y no de trabajo pendiente, la nota lo dice: son dos cosas muy distintas frente a las que planificar. En Escritura, la nota dice además qué le ocurre a un comando que emitas de todos modos, porque no es lo mismo en todas las filas. |
| — | No aplica | La dirección no tiene sentido para esa fila. No es un sinónimo de «ninguno», y nunca sustituye a «desconocido» ni a «planeado». |
Una sola regla separa ● de ◐, y se aplica a todas las filas de esta página. Una dirección es ◐
siempre que la plataforma pueda perder, truncar o rechazar algo sin decírselo a nadie, incluso
cuando el transporte en conjunto sea el más completo de la página. ● se reserva para una dirección sin
ese agujero. Esa es la única razón por la que la ingesta HTTP es ● en Suscripción y el bróker de la
plataforma no lo es: al superar el límite de ingesta del inquilino, HTTP responde 429 al publicador,
mientras que la vía del bróker descarta el mensaje después de que el dispositivo ya haya recibido su
PUBACK, y al publicador no le llega nada.
Las direcciones se nombran desde el punto de vista de la plataforma:
- Lectura: la plataforma pide un valor a un dispositivo y obtiene la respuesta en ese intercambio.
- Escritura: la plataforma fija un valor en un dispositivo, o le dice que actúe.
- Suscripción: el dispositivo envía lecturas sin que se le pidan cada vez.
— nunca aparece en la tabla de transportes de dispositivo. Las tres direcciones tienen sentido para
todos los transportes de dispositivo, así que Ninguno ahí es siempre una respuesta real a una
pregunta real.
Transportes de dispositivo
Cómo llegan los dispositivos a la plataforma, y cómo llega la plataforma de vuelta.
| Transporte | Lectura | Escritura | Suscripción |
|---|---|---|---|
| MQTT (bróker de la plataforma) | ○ | ◐ | ◐ |
| HTTP | ○ | ○ | ● |
| MQTT (bróker externo) | ○ | ○ | ◐ |
| Sparkplug B | ○ | ○ | ◐ |
| LwM2M | ◐ | ◐ | ◐ |
MQTT — el bróker de la plataforma
La vía por defecto, y la más completa. El bróker es el servidor MQTT integrado en NATS, así que no hay ningún bróker aparte que operar.
-
Suscripción ◐: el dispositivo publica en su propio topic de eventos, y el bróker captura el mensaje de forma duradera antes de que ningún código de la plataforma lo vea. La autenticación tiene dos capas independientes: la conexión se autentica en el bróker y queda ligada a los subjects de ese único dispositivo, y el evento lleva una credencial que se comprueba de nuevo en el pipeline.
Hay un agujero, y es la razón de que esto no sea
●. Un mensaje que llega mientras el inquilino supera su techo de ingesta, contado en lecturas, se confirma al bróker y se descarta. El dispositivo ya recibió su PUBACK cuando el bróker lo capturó, así que nada informa al publicador; en este transporte no hay un429que enviar. Si tu flota puede superar su límite a ráfagas, dimensiónala contra ese límite en lugar de confiar en que se avise al dispositivo para que frene, porque no se le avisa.Tampoco se avisa al dispositivo cuando la propia plataforma rechaza eventos nuevos (consulta contrapresión en la ruta de ingesta). El bróker ya confirmó el mensaje al dispositivo, así que no se rechaza: espera en el stream de captura hasta que la canalización vuelva a aceptar eventos. Si el rechazo dura lo suficiente para llenar el stream de captura, se descartan sus mensajes más antiguos.
JetStreamDurableStalledBehindStreamlo informa mientras la canalización no lee el stream de captura, yJetStreamDurableLostUnreadcuando vuelve a leerlo.Un tercer agujero es la propia elección de líder del stream de captura. El broker entrega cada publicación QoS 1 al stream de captura sin respuesta, después de que el dispositivo ya tiene su PUBACK. Si el stream cambia de líder bajo carga, las publicaciones que llegan mientras no tiene ninguno, varios segundos, no se guardan en ningún sitio y ningún contador las registra. En una prueba de 12 000 eventos por segundo, un cambio así perdió unos cinco segundos de eventos.
JetStreamCaptureLeaderChangedavisa de que hubo un cambio mientras llegaban eventos; los eventos perdidos no se pueden recuperar, y la hora del cambio acota la ventana que revisar en los registros de sus propios dispositivos.El ajuste de instancia
infrastructure.nats.mqttFailClosed(desactivado por defecto) cierra el segundo y el tercer agujero para QoS 1. Con él activado, un PUBACK de QoS 1 significa que la plataforma guarda el mensaje: la plataforma lee los eventos, las respuestas a comandos y los informes de dispositivo QoS 1 del propio almacén de mensajes del bróker. Un almacén lleno rechaza la publicación, y uno cuyo líder está cambiando no la confirma, así que el dispositivo no recibe PUBACK y la vuelve a enviar. Las publicaciones QoS 0 mantienen el comportamiento anterior, y un mensaje por encima del techo del inquilino se sigue descartando después de su PUBACK. Consulte calidad de servicio y MQTT a prueba de fallos. -
Escritura ◐: los comandos se entregan, pero la entrega es solo en vivo y sin confirmación. Una publicación alcanza a un dispositivo que esté conectado y suscrito en ese instante. El bróker no la retiene para uno que no lo esté, y nada informa a la plataforma de si el dispositivo la recibió. Deliberadamente no existe un estado
DELIVERED: confirmar la entrega por separado de la respuesta exigiría un acuse de recibo que este transporte no proporciona. Un comando se completa cuando el dispositivo lo responde; consulta respuesta a un comando. -
Lectura ○: no hay ninguna primitiva de petición/respuesta iniciada por la plataforma. Puedes expresar una lectura como un comando cuya respuesta lleve el valor, pero eso es un vocabulario que tú defines en el perfil del dispositivo, no algo que aporte el transporte.
HTTP
Un endpoint POST para el mismo cuerpo de evento JSON. Sencillo, y de un solo sentido.
-
Suscripción ●:
POST /{instanceId}/{tenant}/eventsdevuelve:202una vez almacenado el evento en el stream de entrada de la plataforma;400ante un cuerpo que no puede decodificar o un inquilino sintácticamente inválido;404cuando el id de instancia de la ruta es incorrecto;429cuando el inquilino supera su techo de ingesta, contado en lecturas. Se comprueba antes de la contrapresión, así que un inquilino por encima de su propio techo recibe429, nunca el503de contrapresión;503con una cabeceraRetry-Aftercuando la plataforma aplica contrapresión: rechaza eventos nuevos para que no desplacen eventos que un consumidor aún no ha procesado (consulta contrapresión en la ruta de ingesta);503sinRetry-Aftercuando el evento no pudo entregarse al stream.
Reintenta ante un
503: es la plataforma diciéndote, en el único transporte que puede hacerlo, que tus datos quizá no llegaron. Un503conRetry-Aftersignifica que el evento no se almacenó con toda seguridad, así que espera ese tiempo y vuelve a enviarlo. Un503sin él significa que la publicación falló, y si falló después de que el stream almacenara el evento, un reintento lo almacena dos veces, salvo que el evento llevealtIdyoccurredTime(consulta calidad de servicio). Un429también significa que el evento no se aceptó; lleva una cabeceraRetry-After, así que espera y reintenta.202,400y404son terminales para esa petición. -
Escritura ○ / Lectura ○: no hay ningún canal descendente en absoluto. Un dispositivo que llega a la plataforma solo por HTTP no puede recibir comandos. Más que una carencia a la espera de arreglo, es la forma de la integración: da también una conexión MQTT a un dispositivo que deba recibir comandos.
Un comando emitido a un dispositivo solo HTTP no se rechaza: caduca. La plataforma no acuña ningún nombre de transporte para un dispositivo que llegó por HTTP (el origen registrado del dispositivo es el id que el operador dio a la fuente de eventos), así que la compuerta que reconoce un transporte no entregable no puede reconocer este. El comando se acepta, se publica donde ningún dispositivo está suscrito para recibirlo, se marca
SENTy acaba enTIMEOUT. Sparkplug es la única fila de esta página en la que un○en esta columna produce unFAILEDinmediato. -
El listener de ingesta termina HTTP en claro y no tiene autenticación de transporte propia; las credenciales del dispositivo viajan en el cuerpo del evento. Donde necesites TLS, lo aporta lo que pongas por delante del servicio.
MQTT — un bróker externo, propiedad del operador
La plataforma también puede actuar como cliente en un bróker que ya operes, para ingerir de él.
-
Suscripción ◐: funciona, pero faltan cuatro cosas, y todas importan más allá de un laboratorio:
- la conexión es en claro (sin TLS);
- no presenta ninguna credencial de bróker;
- en la práctica es como mucho una vez;
- un mensaje rechazado por exceder un límite, o mientras la plataforma aplica contrapresión, se descarta, sin devolver nada al publicador.
Prefiere el bróker de la plataforma salvo que necesites específicamente leer de uno ya existente.
Lo de como mucho una vez importa si vas a elegir un QoS en tu propio bróker. La plataforma se suscribe con QoS 1, así que la pérdida no está en la suscripción. La sesión no es persistente y el traspaso a la decodificación vive en memoria, de modo que un mensaje que la plataforma ya tomó de tu bróker y aún no ha publicado se pierde si el proceso se reinicia. Subir el QoS en tu lado no cambia eso, y la plataforma no reclama durabilidad sobre un bróker que no le pertenece.
Cuánto puede perderse tiene un límite: los mensajes en cola para decodificar o en decodificación (hasta 105), más los eventos que esperan la confirmación del bróker de la plataforma, que son como máximo
externalMqtt.publishWindow(128 por defecto). Una parada que deja terminar a la plataforma, como una actualización progresiva o ceder la fuente a otro pod, espera a que se almacenen primero. Una publicación que falla se cuenta entotal_msg_publish_failedy se registra; no se reintenta.Si tu bróker se reinicia o la conexión se cae, la plataforma se reconecta y vuelve a suscribirse por sí sola. Un bróker que rechaza la suscripción, ya sea al arrancar o tras una reconexión (por ejemplo, porque un cambio de ACL deniega el topic), detiene todo el servicio event-sources con un error en lugar de dejarlo conectado sin ingerir nada. Eso incluye la ingesta desde el bróker de la plataforma y por HTTP, no solo esta fuente: el servicio se reinicia y sigue fallando hasta que el bróker vuelva a conceder la suscripción.
Un solo pod lee cada fuente, con un identificador de cliente propio. La plataforma se conecta a tu bróker como
devicechain:<instancia>:<fuente>:<pod>, así que dos instancias, dos fuentes o dos pods deevent-sourcesnunca comparten una sesión. Un bróker mantiene una sesión por identificador de cliente y corta la conexión más antigua cuando llega una segunda, y el identificador único compartido que usaban las versiones anteriores perdía mensajes por esa vía. Corran los pods deevent-sourcesque corran, solo uno lee una fuente dada a la vez, porque nada en esta vía distingue un mensaje entregado a dos pods de dos mensajes. Los demás no conectan nada para esa fuente, quedan a la espera y siguen atendiendo todo lo demás. Si la ACL, la lista de permitidos o la regla de identificadores de tu bróker se basa en el identificador de cliente, permite los que empiezan pordevicechain:. El identificador supera los 23 caracteres, el límite más corto que MQTT exige aceptar a un bróker, así que un bróker que aplica ese límite lo rechaza.- Relevo. Un pod que se detiene libera la fuente al salir, y otro pod se conecta en unos dos
segundos. Tras una pérdida abrupta (un fallo de nodo, un
SIGKILL, una terminación por falta de memoria), la fuente queda sin leer unos 30 segundos más lo que tarde en reconectarse. Tu bróker no conserva lo que entrega en ninguno de esos huecos, porque la sesión no es persistente. - Un pod que toma una fuente y no puede conectarse registra el motivo, libera la fuente y vuelve a intentarlo cada 15 segundos. No detiene el servicio. Si tu bróker rechaza su suscripción, el servicio se detiene, como se describe arriba. El pod que lee una fuente cuando el servicio arranca sigue haciendo fallar ese arranque en ambos casos, como antes.
- Escalar no reparte la carga. Añadir pods de
event-sourcesañade pods en espera, no lectores de una fuente externa. - Vigílalo.
devicechain_eventsources_external_mqtt_owner{source}vale 1 en el pod que lee la fuente y 0 en los demás. La alertaExternalMqttSourceNotReadByOnePodsalta cuando una fuente lleva dos minutos sin que la lea ningún pod, o leída por más de uno. - Solapamiento. Un pod que pierde la fuente mientras sigue conectado descarta lo que todavía
le llega, y lo cuenta en
devicechain_eventsources_total_msg_not_owner{source}, en lugar de almacenarlo. La ventana en la que dos pods pueden almacenar el mismo mensaje es de una fracción de segundo, no el arrendamiento de 30 segundos.
-
Escritura ○ / Lectura ○: esta integración es solo de ingesta. Un comando emitido a un dispositivo que llega por esta vía se comporta exactamente igual que en HTTP, más arriba: publicado,
SENTy luegoTIMEOUT.
Sparkplug B
Para flotas ya existentes que hablan Sparkplug con su propio bróker.
-
Suscripción ◐: se decodifican NBIRTH/NDATA/DBIRTH/DDATA, incluidas las tablas de alias y el seguimiento de secuencia, y BIRTH/DEATH dirigen una presencia autoritativa en lugar de una presencia inferida por temporizador. Lo que impide que sea
●: solo las métricas numéricas se convierten en mediciones. Una métrica booleana, de cadena, de bytes, DataSet o Template se omite al decodificar el payload, sin registrar nada y sin decir nada. Si las señales interesantes de tu flota son booleanas (un indicador de marcha, un bit de fallo), verás un dispositivo autoritativamente en línea que no reporta nada.Mientras la plataforma aplica contrapresión (consulta contrapresión en la ruta de ingesta), las lecturas se descartan sin reintento y se cuentan. BIRTH y DEATH se siguen aceptando, así que la presencia sigue siendo correcta.
-
Escritura ○: deliberadamente fuera de alcance, no inacabado. No hay salida de comandos Sparkplug (
DCMD), y ninguna espera trabajo pendiente: una flota Sparkplug reside en la infraestructura MQTT del cliente, así que nada tiende un puente entre el flujo de comandos de la plataforma y ella. Un comando emitido a un dispositivo Sparkplug acaba enFAILED, no entregable, con dos matices:- El veredicto suele ser rápido, pero no es sincrónico con el encolado. Encolar un comando desencadena un intento de despacho inmediato para ese dispositivo. Cuando es el único comando encolado del dispositivo, la compuerta de presencia lo marca como fallido en el acto. Si el dispositivo ya tiene otros comandos encolados, ese intento se retira y el veredicto llega en el siguiente barrido de entrega, que corre cada 30 segundos por defecto (configurable entre 5 y 300).
- Exige que la compuerta de presencia esté configurada. La compuerta de presencia es la
comprobación que retiene o marca como fallido un comando según lo que el transporte del
dispositivo informa sobre él. Necesita el secreto entre servicios y un endpoint de
device-state. Sin cualquiera de los dos está apagada (lo registra al arrancar), y el comando se despacha como cualquier otro y acaba enTIMEOUT.
-
Lectura ○: por la misma razón.
Lo que la plataforma sí publica en Sparkplug: ningún DCMD, nunca, y ningún NCMD alcanzable
desde la API de comandos. El único NCMD que la plataforma emite es un Node Control/Rebirth
interno, emitido por el seguimiento de sesión de la propia Host Application para reparar un hueco de
secuencia, con QoS 0 y sin retener.
La Host Application sí publica su propio mensaje STATE en spBv1.0/STATE/{host_id}, retenido y
con QoS 1: al conectarse, al detenerse limpiamente y como su Last-Will si muere. Ese es el contrato
de nacimiento/muerte de la Host Application de Sparkplug, y los nodos de borde lo leen.
STATE de la plataformaSi escribes ACL de bróker, concede al cliente de la plataforma permiso de publicación en
spBv1.0/STATE/{host_id}. Si lo deniegas, la sesión de la Host Application queda rota desde la
primera conexión.
La identidad de un dispositivo Sparkplug proviene del topic en el que publicó, así que el modo de autenticación de dispositivo por evento no impide que un publicador de tu bróker envíe bajo la identidad de otro dispositivo dentro del mismo inquilino. Entre inquilinos esto no puede ocurrir: la pertenencia a inquilino la fija la conexión de bróker por la que llegó un mensaje, nunca nada del mensaje. La separación dentro de un inquilino se aplica en tu bróker, con credenciales por cliente y permisos de topic. Dimensiona eso antes de apuntar un bróker compartido a un inquilino.
LwM2M
Para dispositivos con recursos limitados sobre CoAP/UDP con DTLS.
-
Lectura ◐: implementada como un comando de dispositivo, y el cuerpo de la respuesta vuelve. La limitación es que un cuerpo de más de 8 KiB se trunca y la respuesta se sigue reportando como un éxito. «Limitado» es el modelo mental equivocado: no se rechaza nada y nada marca el resultado como parcial, así que la lectura de un recurso grande vuelve con aspecto de estar completa.
-
Escritura ◐: un único recurso escalar cada vez. No se admite escribir una instancia de objeto, escribir varios recursos en una sola operación ni la actualización parcial. Los valores se limitan a 8 KiB.
-
Suscripción ◐: Observe funciona, pero solo se decodifican notificaciones SenML-JSON y, de ellas, solo los recursos numéricos se convierten en mediciones. Un objeto de naturaleza booleana no produce telemetría alguna, la misma limitación que tiene Sparkplug.
Dimensiona esto de antemano: un cliente conforme solo LwM2M 1.0 no puede producir SenML, así que rechaza correctamente el Observe. Ese dispositivo sigue registrándose, dirige la presencia y acepta comandos, pero no reporta ninguna telemetría. Decodificar el formato TLV más antiguo es la tarea pendiente que cierra esto.
Los objetos observados se restringen a una lista de permitidos incorporada que no es configurable, con un tope de 32 observaciones por registro. Las observaciones no sobreviven a un relevo de líder: la presencia se reconstruye, y la telemetría se restablece solo a medida que se renueva el registro de cada dispositivo.
Mientras la plataforma aplica contrapresión (consulta contrapresión en la ruta de ingesta), una notificación se descarta y se cuenta, y la siguiente la sustituye. El registro y la desconexión se siguen aceptando, así que la presencia sigue siendo correcta.
-
Los comandos a un dispositivo dormido se retienen de forma duradera y se drenan cuando vuelve a aparecer, registrados como
PARKED. Es el único lugar donde un comando que el transporte ya intentó entregar se conserva para el dispositivo en vez de perderse. No es la única retención de la plataforma: para todos los transportes (MQTT incluido, cuando es el propio bróker quien informa la presencia del dispositivo), un comando cuyo dispositivo el transporte afirma ausente se retiene comoHELDantes de publicarse, y se libera cuando vuelve la presencia. Consulta comandos para un dispositivo ausente.
Operaciones LwM2M en detalle
| Operación | Notas | |
|---|---|---|
| Read | ◐ | GET de CoAP; una respuesta de más de 8 KiB se trunca en silencio y se sigue reportando como correcta |
| Write | ◐ | Un único recurso escalar, solo reemplazo |
| Execute | ● | Con o sin argumentos. Un Execute sin procesar del recurso Factory Reset del objeto Device (/3/0/5) se rechaza con COMMAND_DESTRUCTIVE_REFUSED; está prevista una operación con nombre y confirmación |
Reboot (lwm2m.reboot) | ● | Un comando con nombre que ejecuta (Execute) el recurso Reboot del objeto Device; no recibe parámetros |
Lectura de información del dispositivo (lwm2m.readDeviceInfo) | ● | Un comando con nombre que lee el fabricante, el modelo, el número de serie, la versión de firmware y el nivel de batería del objeto Device, y lista los recursos que el dispositivo no tenía |
| Recolección de información del dispositivo | ● | Al registrarse se leen una vez los mismos recursos y se guardan como atributos de cliente; como máximo una vez por hora por dispositivo, y nunca retrasa el registro ni la telemetría |
| Observe | ◐ | Solo SenML-JSON; solo recursos numéricos; lista de objetos fija; 32 por registro |
| Discover | ○ | No implementado |
| Create | ○ | No implementado |
| Delete | ○ | No implementado |
| Write-Attributes | ○ | No implementado: las bandas de notificación no se pueden fijar desde la plataforma |
| Bootstrap | ○ | No implementado; un servidor Bootstrap está planeado |
La autenticación de dispositivo es por dispositivo, en el handshake DTLS, con claves precompartidas. Las credenciales X.509 y de clave pública en bruto están planeadas.
Conectores de salida
A dónde envía datos la plataforma cuando dispara una regla. Un conector es un sumidero de un solo
sentido sin direcciones de dispositivo, así que Lectura y Suscripción son — y no
Ninguno.
| Conector | Lectura | Escritura | Suscripción | Notas |
|---|---|---|---|---|
Webhook httpCall | — | ● | — | Solo POST; se rechaza cualquier otro método |
publish → MQTT | — | ● | — | QoS 0/1/2; usuario + secreto; URL tcp, mqtt, ssl, tls, mqtts, ws, wss; sin ajustes de TLS (consulta más abajo) |
publish → Kafka | — | ● | — | TLS; SASL PLAIN, SCRAM-SHA-256, SCRAM-SHA-512 |
publish → AWS SNS | — | ● | — | Solo credenciales estáticas por inquilino |
publish → AWS SQS | — | ● | — | Solo credenciales estáticas por inquilino |
publish → Google Pub/Sub | — | ○ | — | No disponible: se rechaza al escribir (consulta más abajo) |
A diferencia de Kafka, que tiene un conmutador tls real, la configuración del conector MQTT no
tiene campos de TLS de ningún tipo, y rechaza claves desconocidas, así que no hay nada que
configurar. El TLS solo ocurre de forma implícita, cuando das al bróker una URL ssl://, tls://,
mqtts:// o wss://. La conexión se verifica entonces contra el almacén de confianza público y el
host que nombra la URL, sin ninguna manera de aportar una CA, un certificado de cliente o un ajuste
de verificación.
Los dos conectores de AWS exigen deliberadamente una clave de acceso estática y no recurren a la identidad IAM ambiental del pod en el que se ejecutan. Esa separación existe para que la identidad de nube de la propia plataforma nunca se tome prestada para hacer la llamada de un inquilino.
Cada destino de un conector se comprueba al establecer la conexión, y uno que resuelve a una dirección privada o de metadatos de nube se rechaza salvo que un operador haya permitido explícitamente esa dirección; consulta a dónde puede enviar un conector.
gcp_pubsub es un tipo de conector reconocido, pero no tiene implementación de entrega en esta
versión. Crear un conector de ese tipo, actualizar uno a ese tipo o publicarlo se rechaza con el
código de error UNSUPPORTED. Un conector de ese tipo guardado por una versión anterior sigue
acabando en la cola de mensajes muertos como no soportado si un publish lo apunta: reconocido
pero no ejecutable, nunca descartado en silencio. Cuando se publique, se autenticará con una credencial
guardada en el conector, como hacen los conectores de AWS, nunca con la identidad del pod.
Aparte de los conectores, los canales de notificación llegan a personas y no a sistemas, por SMTP y webhook.
No disponible
Se nombran explícitamente porque, desde fuera de la plataforma, «ausente de la lista de arriba» y «se pidió y la respuesta fue no» son indistinguibles, y solo uno de los dos merece la espera.
| Ingesta de dispositivo por WebSocket | No disponible. Figura como planeada en la introducción. |
| CoAP fuera de LwM2M | No disponible. CoAP llega a la plataforma a través de LwM2M y no de otro modo. |
| NATS en bruto como transporte de dispositivo | No disponible. Una credencial de dispositivo autoriza una conexión MQTT, y no existe un cliente de dispositivo nativo de NATS. |
Salida de comandos Sparkplug (DCMD) | No disponible, y deliberadamente fuera de alcance en lugar de pendiente; consulta más arriba. |
| Protocolos de bus de campo industrial: OPC-UA, Modbus, BACnet | No disponibles como transportes de plataforma, y nada de lo que publica el proyecto los habla. La forma admitida es una pasarela local que hable el bus de campo en la red de planta y reenvíe por MQTT o HTTP; la traducción de protocolo la aportas tú. El proyecto sí publica dc-edge-agent, que hace la otra mitad de ese trabajo: termina localmente la vía MQTT del dispositivo, almacena de forma duradera durante un corte de WAN y reenvía solo por MQTT. No habla ningún bus de campo. |