# ¿MQTT o HTTP? En una red LoRaWAN * **Estudiante**: Bibiana Mollinedo Rivadeneira * **Cátedra**: Tráfico * **Año**: 2019 ## Resumen Se realiza el diseño y puesta en marcha y análisis de dos redes LoRaWAN, la primera de ellas en un entorno de *simulación* y la restante en un escenario real. Para ambas se generan y capturan paquetes LoRa, se analizan los parámetros del tráfico de la red simulada versus la red física relacionados a **delay** y **overhead** para dos diferentes **protocolos de aplicación**: `MQTT` y `HTTP`, *(Ver diagrama general de red LoRaWAN)*. Se analizan los resultados y se establecen conclusiones respecto al protocolo más adecuado para una aplicación de *IoT*. ### Palabras clave LoRa, LoRaWAN, Arm Mbed OS simulator, ESP32, Arduino, MQTT, HTTP, thethingsnetwork. ## Sobre este documento **“¿MQTT o HTTP? En una red LoRaWAN”** se produce en el contexto del trabajo final de la cátedra de Tráfico en la carrera de Ing. en Telecomunicaciones, en la Universidad Nacional de Río Cuarto. Este documento es de libre acceso, permite modificación y redistribución, apostando al cumplimiento de la [Ley 26899: Repositorios digitales institucionales de acceso abierto.](https://www.argentina.gob.ar/normativa/nacional/ley-26899-223459) <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licencia Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />Esta obra está bajo una <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional</a>. Este es un resumen legible por humanos (y no un sustituto) de la licencia. Advertencia. Usted es libre de: * **Compartir** — copiar y redistribuir el material en cualquier medio o formato * **Adaptar** — remezclar, transformar y construir a partir del material para cualquier propósito, incluso comercialmente. * La licenciante no puede revocar estas libertades en tanto usted siga los términos de la licencia Bajo los siguientes términos: * **Atribución** — Usted debe dar crédito de manera adecuada, brindar un enlace a la licencia, e indicar si se han realizado cambios. Puede hacerlo en cualquier forma razonable, pero no de forma tal que sugiera que usted o su uso tienen el apoyo de la licenciante. * No hay restricciones adicionales — No puede aplicar términos legales ni medidas tecnológicas que restrinjan legalmente a otras a hacer cualquier uso permitido por la licencia. *** ## Índice de contenidos [TOC] ## Motivación La medición y análisis de parámetros de desempeño de tráfico en una red LoRaWAN surge de la inquietud de llevar adelante la mayor cantidad de experiencias empíricas sobre redes de internet de las cosas que permitan a la toma de decisiones desde un rol ingenieril para la proyección y procesos de escalar el prototipo/prueba de concepto de una red diseñada, simulada e implementada en el contexto de una práctica profesional supervisada. Cabe destacar que los conceptos y procolos aquí abordados se encuentran en auge en la industria así como implementan fundamentos que atraviesan a la carrera de Ingeniería en Telecomunicaciones. ## Introducción Los elementos de la cotidianeidad se transformaron en pocos años, en dispositivos a conectar a la red, enviando y recibiendo dimensiones gigantezcas de datos. Sin embargo existen aún áreas sin acceso a internet, pero con no menos importantes, ni en menor cantidad, datos a aportar. Las redes LoRaWAN, en su arquitectura híbrida de comunicación, ofrece alcances significativos, bajos requerimientos de potencia, versatilidad en la implementación con bajos costos. Ante la tarea de diseñar una red de este tipo, y más específicamente prepararse para la toma de decisiones desde una perspectiva técnica, ingenieril y lo más agnóstica posible ante diferentes escenarios y por ende variables a contemplar, se opta por experiencias empíricas de recopilación de datos, análisis y conclusiones sobre parámetros de interés. ## Objetivos ### Generales Montar redes LoRaWAN en entornos de simulación así como físicos, generar y capturar paquetes LoRa para ambas y realizar un análisis comparativo con enfoque en parámetros del tráfico para dos diferentes protocolos de aplicación y establecer conclusiones fundadas sobre una elección adecuada del mismo. ### Específicos * Realizar una búsqueda bibliográfica para confección de un marco teórico. * Buscar y elegir herramientas y metodologías de simulación de una red LoRaWAN, así como de una red física. * Generar y capturar paquetes LoRa para cada una de las redes en escenarios que se asemejen. * Analizar los datos empíricos con un enfoque comparativo del rendimiento del tráfico para cada uno de los protocolos de aplicación (MQTT y HTTP) respecto a `delay` y `overhead. * Establecer conclusiones con base en ventajas y desventajas de los protocolos de aplicación para diferentes aspectos y una elección adecuada para aplicaciones de internet de las cosas. ## Metodología Se realiza la búsqueda bibliográfica haciendo hincapié en protocolos de comunicación de tecnologías LoRaWAN, formato de frame LoRa, payload, parámetros de tráfico de la red y protocolos de aplicación. Se buscan, analizan y seleccionan herramientas de simulación y de puesta en marcha de redes LoRaWAN, priorizando el uso de software libre y opensource, así como apuntando a un proyecto reproducible. Se generan paquetes LoRa para cada una de las redes, en escenarios que se asemejen. Se capturan los paquetes en cuestión con wireshark. Se buscan y seleccionan herramientas para el procesamiento, análisis y muestra de datos de interés de la captura antes mencionada, capaces de exponer características como **latencia** y **overhead**. Se confeccionan tablas comparativas así como gráficos amenos para su análisis. Se confeccionan conclusiones fundadas sobre el rendimiento de las redes empleando MQTT versus HTTP como protocolo de aplicación de una red LoRaWAN. Desde una mirada ingenieril, se selecciona uno de ellos como el "más adecuado" para una aplicación de internet de las cosas. ## Marco teórico ### Sobre LoRaWAN *Tecnología LPWAN (Low Power Wide Area Network - Redes de baja potencia y área amplia)* es un protocolo de comunicación y arquitectura de sistema, orientado a **[IoT](#IoT-gIoT)** *(Internet of Things - Internet de las cosas)* que implementa **[LoRa](#LoRa-dLoRa)**. Dichas especificaciones adquirieron gran *"popularidad"* en el campo de **[IoT](#IoT-gIoT)**, algunos de los factores de lo anterior son: * **Largo alcance**, un [gateway](#Gateway-dGateway) puede dar cobertura a dispositivos de toda una ciudad, esto es, alcance a distancias en kilómetros. > El 13 de Julio de 2019, se logró un nuevo récord mundial de alcance con [LoRaWAN](#LoRaWAN-dLoRaWAN, con **766 km** de distancia y `25mW` de potencia de transmisión. > [Más información.](https://www.thethingsnetwork.org/article/lorawan-distance-world-record) * **Bajo consumo**, el protocolo de comunicación de datos permite bajos requerimientos de energía (potencia) para la transmisión de datos. * **Alta capacidad de la red**, la técnica de modulación empleada permite la comunicación entre un [gateway](#Gateway-dGateway) y múltiples nodos a diferentes distancias y tasas de transferencia. * **Adaptabilidad**, la red soporta diferentes clases de nodos según los requerimientos, permitiendo adaptar la red a diferentes aplicaciones. * **Bajo costo**, una red funcional puede ser implementada con dispositivos de bajo costo. * **Seguridad**, implementa algoritmos robustos de encriptación. * **Gran comunidad activa alrededor del mundo**. * **Compatible con componentes open source**. #### Arquitectura La arquitectura general de una red [LoRaWAN](#LoRaWAN-dLoRaWAN) es como sigue: [![](https://upload.wikimedia.org/wikipedia/commons/c/cc/ArquitecturaLoRa.png)](https://commons.wikimedia.org/wiki/File:ArquitecturaLoRa.png) *Arquitectura general de una red [LoRaWAN](#LoRaWAN-dLoRaWAN)* de brivadeneira / [CC BY SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) * **End-points**: Se comunican con uno o más gateways según el protocolo LoRa. * **Sensor**: *(→)* Registra medición de una magnitud física y la transmite a los gateways. *Ej: sensor de temperatura, de presión, de nivel.* * **Actuador**: *(↔)* Según dato recibido desde la red *modifica* uno o más parámetros del entorno. *Ej: LED, relé.* * **Gateways**: *(↔)* Se comunican con end-points según protocolo LoRa, así como con *-uno o más-* servidores de red por *Ethernet, WiFi o 3G/4G*. * **Servidor de red**: *(↔)* Se comunica con gateways y servidor de aplicación a través de red de datos. * **Servidor de aplicación**: *(↔)* Se comunica con dispositivos del usuario, así como servidor de red. Provee servicios al usuario, autentica dispositivos, etc. #### Especificaciones técnicas A continuación se exponen las especificaciones técnicas de interés de [LoRaWAN](#LoRaWAN-dLoRaWAN). #### Cifrado [LoRaWAN](#LoRaWAN-dLoRaWAN) implementa **[AES](#AES-gAES)-CTR** en el payload del tráfico de la red, así como **[AES](#AES-gAES)-CMAC** en el campo de *MIC, Código de Integridad del Mensaje* #### Frecuencia de trabajo En Argentina, la banda de frecuencias de trabajo para una red LoRaWAN es **`902 - 928 MHz`**, (915-928 MHz usable). *Ver pag. 8, "Table 1: Channel Plan per Country" en Anexo 1: LoRaWAN Regional Parameters (v1.1)*. ##### Normativa Argentina El rango de frecuencias de trabajo corresponde a la lista de [Bandas no licenciadas](https://www.enacom.gob.ar/bandas-no-licenciadas_p680): > Conviene destacar que el Reglamento de Radiocomunicaciones de UIT ha destinado a nivel mundial (y en algún caso, regional) bandas para uso primario para las aplicaciones Industriales, Científicas y Médicas (ICM). La Nota de Pie 5.150 dice: > "Las bandas *(...)* **`902-928MHz` en la Región 2 (frecuencia central 915MHz)**, *(...)*, están designadas para aplicaciones industriales, científicas y médicas (ICM). Los servicios de radiocomunicación que funcionan en estas bandas deben aceptar la interferencia perjudicial resultante de estas aplicaciones." Según la [Cuadro de atribución de bandas de frecuencias de la República Argentina](https://www.enacom.gob.ar/multimedia/noticias/archivos/201904/archivo_20190416044315_5617.pdf), la banda comprendida entre los **`915 MHz y 928 MHz`** *(ver pag 188, nótese que no comienza en `902 MHz`)*, corresponde a * **"Servicio TIC para banda de frecuencia de uso compartido"**. * Tipo de servicio FIJO/MOVIL de *Uso Privado – Prestador*. * Bajo **[resolución 581MM18](https://www.enacom.gob.ar/multimedia/normativas/2018/res581MM.pdf)**, la que establece los siguientes niveles de trabajo: * Potencia Máxima del Transmisor (Conducida) `30dBm`. * Potencia Máxima del Transmisor (P.I.R.E.) `36dBm`. #### Ocupación espectral La distribución espectral es según la norma **AU915-928 US902-928**, como sigue: [![](https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/EspectroAU915-928LoRa.png/800px-EspectroAU915-928LoRa.png)](https://commons.wikimedia.org/wiki/File:EspectroAU915-928LoRa.png) *"AU915-928 LoRa v1.1"* de brivadeneira / [CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/) * **Upstream** * 64 canales numerados de 0 a 63 de **`125kHz`** de ancho de banda, y **`200kHz`** entre ellos. El primero en **`915.2MHz`** y el último en **`927.1MHz`**. *(Verde)*. * 8 canales numerados de 64 a 71 de **`500kHz`** de ancho de banda, y **`1.6MHz`** entre ellos. El primero en **`915.9MHz`** y el último en **`927.1MHz`**. *(Azul)*. * **Downstream** * 8 canales numerados de 0 a 7 de **`500kHz`** de ancho de banda, y **`600kHz`** entre ellos. El primero en **`923.3MHz`** y el último en **`927.5MHz`**. *(Amarillo)*. > NOTA: En Argentina existe un consenso de usar los canales 8 a 15 de la especificación AU915 p **AU915 sub-band 2**, Para implementación de la red de código abierto TTN. #### Formato de las tramas Las tramas *(frames)* del protocolo LoRa posee una estructura formada por las capas **física**, **MAC** y superiores *(aplicación)*: [![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/LoRaFrameFormat.png/800px-LoRaFrameFormat.png)](https://commons.wikimedia.org/wiki/File:LoRaFrameFormat.png) *"LoRa Frame Format"* de brivadeneira / [CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/) * **Capa física** *-azul-* (*Physical Layer Frame*): La trama LoRa comienza con un * **Preámbulo**: Además de cumplir la función de *sincronismo*, define el *esquema de modulación de paquetes*. Duración típica del preámbulo: `12.25 Ts.` * **Encabezado + CRC** *(Header)*: Contiene información sobre el *tamaño* del [payload](#Payload-gPayload), si el *[CRC](#CRC-gCRC)* del [payload](#Payload-gPayload) de `16-bit` está o no presente en la trama. *Sólo los frames del enlace de subida contienen el campo [CRC](#CRC-gCRC)*. Tamaño de `20 bits`. * **Payload**: *-anaranjado-* *(PHY Payload)* - `0-96 bits` * **Capa MAC**. * **MAC Header**: Define la versión del protocolo así como el tipo de mensaje. * **MAC Payload**: *-verde-* Contiene *join-request* o *join-access*, empleados en el proceso de activación de un end-point. El MAC Payload es gestionado por la *capa de aplicación*, está conformado por: * **Frame Header**: *-violeta-* * **Dirección de dispositivo**: los primeros`8 bits` identifican la red, los demás se asignan deforma dinámica durante el inicio de sesión e identifican al dispositivo en la red. * **Frame Control**: `1 byte`, contiene información de control de la red como ser implementar o no velocidad de *subida* especificada por el [gateway](#Gateway-dGateway), [ACK](#ACK-gACK) del mensaje anterior, si el [gateway](#Gateway-dGateway) tiene más datos para transmitir. * **Frame counter** para el número de secuencia. * **Frame options**: datos para cambiar configuración como velocidad de transmisión, potencia de transmisión y validación de conexión. * **Frame Port**: Valor determinado según el tipo de aplicación. * **Frame Payload**: Datos a enviar a la red. Se cifra con la AppSKey mediante el algoritmo [AES](#AES-gAES) 128. * **MIC** *(Message Integrity Code)*: Resultado de computar el header y payload MAC con una NwkSKey. #### Formato de Payload (*Frame Payload*) A continuación se describen los formatos de [payload](#Payload-gPayload) bien conocidos: ##### CBOR *Concise Binary Object* ([RFC 7049](https://cbor.io)) Formato diseñado para un tamaño de código extremadamente pequeño, por ende un tamaño de mensaje pequeño y extensibilidad sin la necesidad de negociar la versión. * **Estructura de datos [JSON](#JSON-gJSON)**: Soporta objetos de tipo `number`, `string`, `array`, `map`, `bool`. No requiere un esquema en particular. Pero requiere codificar objetos como claves, gráficos o valores sensados, usualmente se realiza en `base64`, también es posible la codificación binaria *(procesamiento más veloz, impelmentación simple)*. * **"tags"**: Definidos como mecanismo de identificación de **información adicional** al modelo básico. Tanto futuras versiones del estándar como *terceros* pueden definir tags. Se puede implementar con numerosos lenguajes de programación incluyendo *Python*, *C* y hasta *Scratch*. Ejemplo simple: ```jsonld {"Fun": true, "Amt": -2} ``` ##### Cayenne LPP *[Cayenne Low Power Payload](https://github.com/myDevicesIoT/CayenneLPP)* El formato de payload para redes [LoRaWAN](#LoRaWAN-dLoRaWAN). Es compatible con reglas de **restricción de tamaño** por debajo de `11bytes`, lo que permite a un dispositivo enviar múltiples datos a la vez. Además, permite enviar diferentes datos sensados en *diferentes frames*. Para ello, cada dato debe acompañarse de un prefijo de `2bytes`: * **Data Channel:** Identifica unívocamente a un sensor en los frames. Por ejemplo: *“indoor sensor”* - **Data Type:** Identifica el *tipo de dato* en el frame, por ejemplo *“temperature”.* * **Estructura del payload**: | 1 Byte | 1 Byte | N Bytes | 1 Byte | 1 Byte | M Bytes | ... | |-----------|------------|---------|-----------|------------|---------|-----| | Data1 Ch. | Data1 Type | Data1 | Data2 Ch. | Data2 Type | Data2 | ... | * **Tipos de datos** *(Data type)* Corresponde a los lineamientos de la *IPSO Alliance Smart Objects*, identificando los tipos con un ID de objeto. * **LPP Data Type**: Identificador de `1byte` que se corresponde con el identivicador IPSO y puede convertirse de manera sencilla. Por ejemplo: ```python LPP_DATA_TYPE = IPSO_OBJECT_ID - 3200 ``` Donde `3200` es el ID IPSO, mientras que el ID LPP es `0` y se corresponde con una entrada digital. Ejemplo de payload enviando *dos datos sensados a la vez* : | Payload (Hex) | 03 67 01 10 05 67 00 FF | | |---------------|-------------------------|---------------------| | Data Channel | Type | Value | | 03 ⇒ 3 | 67 ⇒ Temperature | 0110 = 272 ⇒ 27.2°C | | 05 ⇒ 5 | 67 ⇒ Temperature | 00FF = 255 ⇒ 25.5°C | Compatible con `Arduino`. ##### Endpoints El módulo de adquisición de datos tiene como funcionalidad el sensado de magnitudes físicas de interés, *(según aplicación, temperatura, presión, humedad, nivel, etc)*. Se conecta directamente con el de transmisión según tecnología [LoRaWAN](#LoRaWAN-dLoRaWAN). En el diagrama general de la arquitectura de la red [LoRa](#LoRa-dLoRa) se denominan *[end-point](#Endpoints-Endpoints)s*. ##### Factor de ensanchado vs tasa de bits El factor de ensanchado de las señales enviadas en una red [LoRa](#LoRa-dLoRa), defindo como: $SF = \frac{chip\_rate}{symbol\_rate}$, el cociente entre la cantidad de pulsos por segundo y la cantidad de símbolos por segundo, varía entre 7 y 12 según normativa regional e impacta directamente en la tasa de bits como sigue: $bit rate = SF·\frac{Bw}{2^{SF}}$ A continuación se muestran las tasas de bits, según configuración física correspondiente a normativa `AU915-928` | DataRate | Configuration | Bit rate [bit/sec] | |----------|----------------------|--------------------| | 0 | LoRa: SF12 / 125 kHz | 250 | | 1 | LoRa: SF11 / 125 kHz | 440 | | 2 | LoRa: SF10 / 125 kHz | 980 | | 3 | LoRa: SF9 / 125 kHz | 1760 | | 4 | LoRa: SF8 / 125 kHz | 3125 | | 5 | LoRa: SF7 / 125 kHz | 5470 | | 6 | LoRa: SF8 / 500 kHz | 12500 | | 7 | RFU | | | 8 | LoRa: SF12 / 500 kHz | 980 | | 9 | LoRa: SF11 / 500 kHz | 1760 | | 10 | LoRa: SF10 / 500 kHz | 3900 | | 11 | LoRa: SF9 / 500 kHz | 7000 | | 12 | LoRa: SF8 / 500 kHz | 12500 | | 13 | LoRa: SF7 / 500 kHz | 21900 | | 14 | RFU | | | 15 | Defined in LoRaWAN | | *Ver tabla 35, pag. 38 de Anexo 1: LoRaWAN Regional Parameters (v1.1)* publica el mensaje en el tópico correspondiente, con la calidad de servicio especificada. El servidor responde con un paquete **CONNACK** con los siguientes campos: * **SessionPresent**: (Según *CleanSession*, `1`/`True` → `0`/`False` (no requiere almacenar sesión), `0`/`False` → `1`/`True` (sesión persistente)) * **ReturnCode**: Indica resultado de la autenticación según: | ReturnCode | Descripción | |------------|----------------------------------------------------------------------| | 0 | Conexión aceptada. | | 1 | Conexión rechazada por no soportar versión de MQTT solicitado. | | 2 | Conexión rechazada por haber sido denegado el `ClientId` solicitado. | | 3 | Conexión rechazada, si bien la red está disponible, no lo está MQTT. | | 4 | Conexión rechazada por usuario o contraseña incorrectos. | | 5 | Conexión rechazada por haber fallado la autenticación. | ##### Suscripción El cliente envía un paquete **SUSCRIBE** para *suscribirse* a uno o más tópicos con un `PacketId` en el header y uno o más pares `Topic`, `QoS` → `"topic/1"`, `0`. [![](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8f/MQTT_suscribe.png/800px-MQTT_suscribe.png)](https://commons.wikimedia.org/wiki/File:MQTT_autenticacion.png) "MQTT suscribe" de brivadeneira / [CC BY SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) El broker responde con un paquete **SUBACK** con el mismo `PacketId` y un `ReturnCode` según: | ReturnCode | Descripción | |------------|--------------------------------------------| | 0 | Suscripción exitosa con un máximo QoS de 0 | | 1 | Suscripción exitosa con un máximo QoS de 1 | | 2 | Suscripción exitosa con un máximo QoS de 2 | | 128 | Falló suscripción | ##### Publicación Una vez que el cliente se conectó exitosamente con el broker, puede comenzar a **publicar** mensajes, enviando paquetes **PUBLISH**. [![](https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/MQTT_publish.png/800px-MQTT_publish.png)](https://commons.wikimedia.org/wiki/File:MQTT_publish.png) "MQTT publish" de brivadeneira / [CC BY SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en) * **PacketId**: Según `QoS`, `0` → `0`/`null`, `1/2` → `!=0` * **Dup**: Según `QoS`, `0` → `0`/`null`, `1/2` → `!=0`, en este último caso el servidor reenvía el mensaje publicado si no se recibió ACK de los clientes suscriptos. * **QoS**: Nivel de QoS para el mensaje. De ser `0`, ante un mensaje de publicación, el broker no responde, lo envía a los clientes suscriptos. Para valores distintos de `0`, se realiza interacción extra entre cliente que publica y broker. * **0**: Máximo una entrega, ofrece la misma garantía que TCP, el servidor envía el paquete una vez, el cliente no devuelve ACK, el servidor no almacena el paquete para reenvío ni planifica ninguna otra comunicación luego de la entrega. *Baja sobrecarga*, *no hay garantía*. * **1**: Mínimo de una entrega, el servidor envía el paquete, pero lo almacena a la espera un `ACK` del cliente, hasta entonces, reenvía el paquete. *Garantiza entrega*, *paquetes duplicados*. * **2**: Exactamente una entrega, el servidor envía un paquete, recibe un paquete `PUBREC`, al que responde con un `PUBREL` y espera un `PUBCOMP` considerado como ACK, y garantía de exactamente una entrega del paquete. *Garantía de entrega*, *no hay sobrecarga*, *datos críticos*. * **Retain**: `1/True`, `0/False`, retiene o no el mensaje, si se retiene, es enviado a los clientes que se suscriban al tópico en el futuro. * **TopicName**: `string` que indica el nombre del tópico, responden a una jerarquía y usan "/" como delimitador, por ejemplo: `"sensors/drone01/altitude"`. > Los datos del payload son agnósticos al formato, es decir que puede contener un `JSON`, un `XML` o un `binario`. El cliente puede enviar un paquete **UNSUSCRIBE** para *desuscribirse* a uno o más tópicos con un `PacketId` en el header y uno o más pares `Topic`, `QoS` → `"topic/1"`, `0`. > Recomendaciones para nombres de tópicos: > Crear directorios jerárquicos separados por "/", por ejemplo: `sensors/drone01/altitude`. > NO usar: "+", "#" ni "$". #### Seguridad Se pueden implementar técnicas de seguridad para la comunicación bajo MQTT en tres diferentes capas: * **Red (3)**: VPN (Virtual Private Network). * **Transporte (4)**: TLS (Transport Layer Security), las comunicaciones MQTT viajan por TCP, por defecto no están cifradas, se puede usar TLS para asegurar cifrado e integridad, se denomina **MQTTS**. * **Aplicación (5)**: Se pueden implementar funcionalidad de autenticación y autorización empleando el `ClientId`. ##### Mosquitto Borker o Server Open source compatible con MQTT. ## Procedimiento ### Servidor de red/aplicación **1.** Se requiere registro en [thethingsnetwork](https://www.thethingsnetwork.org/) **2.** Click en avatar de usuario y luego en `consola`. A continuación seleccionar `Aplicaciones`: ![](https://i.imgur.com/ptdWS4E.png) **3.** Click en `add aplication`: ![](https://i.imgur.com/ZiiYfbV.png) **4.** Una vez creada la aplicación, click en `devices` y `register device` ![](https://i.imgur.com/XR09sao.png) **4.1.** Elegir un ID para el dispositivo, y click en `generate` para el campo `Device EUI`: ![](https://i.imgur.com/YJI3zuN.png) **4.2.** En el *overview* del dispositivo, visualizar las claves en sistema hexadecimal *(presionando los símbolos `<>`)*. ![](https://i.imgur.com/aTrRETH.png) > Se repiten los pasos **2**, **3** y **4** para crear aplicación y registrar embebidos reales (*físicos*). ### Simulación paquetes LoRa Se emplea el simulador online [Mbed OS Simulator](https://labs.mbed.com/simulator), escrito en js y con ejemplos LoRa disponibles. **5.** Elegir el ejemplo **LoRaWAN**: ![](https://i.imgur.com/XzoKLyr.png) **5.1** Copiar y pegar las claves desde la aplicación *(paso 4.2)* y reemplazar en el código: ```javascript // Device credentials, register device as OTAA in The Things Network and copy credentials here static uint8_t DEV_EUI[] = { 0x00, 0x37, 0xD5, 0x78, 0x63, 0x16, 0xE6, 0x64 }; static uint8_t APP_EUI[] = { 0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x02, 0x38, 0x0C }; static uint8_t APP_KEY[] = { 0xB3, 0x9B, 0x30, 0x5F, 0xF1, 0xDF, 0xB4, 0x5B, 0xFA, 0xB5, 0x61, 0x3E, 0x4B, 0x30, 0xF7, 0x75 }; ``` **5.2** Modificar el puerto a 1 ```javascript // The port we're sending and receiving on #define MBED_CONF_LORA_APP_PORT 1 ``` **6.** Click en `run` **6.1** En `devices` -> `sim-1` -> `data` se pueden observar los paquetes generados: ![](https://i.imgur.com/z7A5vIJ.png) **7.** Repetir los pasos 4 a 6 tantas veces como dispositivos se deseen simular. Se simulan 5 dispositivos: ![](https://i.imgur.com/XbbyhQb.png) En la pestaña `data`se pueden observar los paquetes simulados: ![](https://i.imgur.com/qzQKCZ8.png) ### Red LoRa física ![](https://i.imgur.com/ai9t8Wv.png) *Red LoRa: ESP32-oled, arduino-uno.* Para más información sobre la red LoRa, código de los sistemas embebidos, etc, visitar el siguiente [repositorio](https://github.com/brivadeneira/LoRaWANprototype). ### Integración #### MQTT Se usa el broker MQTT provisto por el servicio *thethingsnetwork*. **Instalar Mosquitto** ```shell=sh wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key sudo apt-key add mosquitto-repo.gpg.key cd /etc/apt/sources.list.d/ sudo wget http://repo.mosquitto.org/debian/mosquitto-stretch.list sudo apt update sudo apt install mosquitto sudo apt install mosquitto-clients ``` **Iniciar el cliente** *Sintáxis* ```shell=sh mosquitto_sub -h <Region>.thethings.network -t "+/devices/+/events/activations" -u "<AppID>" -P "<AppKey>" -v ``` ### Análisis MQTT #### Datos simulados A continuación se muestra el diagrama de red de análisis de MQTT para la red LoRa simulada: ![](https://i.imgur.com/XcjI6SE.png) > Los servidores de red y aplicación así como el broker MQTT son servicios provistos por thethingsnetwork. > Los íconos de lupa indican en equé punto de la red se capturan los paquetes de análisis. El comando para iniciar el cliente MQTT es como sigue: ```shell=sh mosquitto_sub -h eu.thethings.network -t '+/devices/+/events/activations' -u 'simulacion-lora' -P 'ttn-account-v2.Ry5fpvakBfsaUGz7FRjFh1YFJl3s18D9W4jW7ynlWz8' -v ``` #### Datos reales A continuación se muestra el diagrama de red de análisis de MQTT para la red LoRa real: ![](https://i.imgur.com/1Hc63zI.png) El comando para iniciar el cliente MQTT es como sigue: ```shell=sh mosquitto_sub -h eu.thethings.network -t "+/devices/+" -u "fonexa" -P "ttn-account-v2.MNg0XZlghGLZmAUh2eOSDECfoZsyFyG2NjX5V5hhWy8" -v ``` *Enviar un mensaje desde el gateway simulado*. Se puede observar en la consola de `mosquitto`: ```shell=sh simulacion-lora/devices/sim-1/events/activations {"app_eui":"70B3D57ED002380C", "dev_eui":"0037D5786316E664", "dev_addr":"2601210B", "metadata":{"time":"2019-10-09T23:30:59.946537221Z", "frequency":868.3, "modulation":"LORA", "data_rate":"SF8BW125", "airtime":53760000,"coding_rate":"4/6", "gateways":[{"gtw_id":"eui-0242ee000084ee70", "timestamp":1322089000,"time":"2019-10-09T23:30:59.939Z","channel":2, "rssi":-35, "snr":5, "rf_chain":0}]}} ``` Datos reales ```shell=sh { "time": "2019-11-28T13:30:58.715386532Z", "frequency": 902.3, "modulation": "LORA", "data_rate": "SF7BW125", "coding_rate": "4/5", "gateways": [ { "gtw_id": "eui-240ac4ffff308f78", "timestamp": 577252293, "time": "", "channel": 0, "rssi": -60, "snr": 9, "latitude": -33.11341, "longitude": -64.32847, "altitude": 440 } ] } ``` **Instalar e iniciar wireshark** ```shell=sh sudo apt install wireshark sudo wireshark ``` **Escribir MQTT en filtros** ![](https://i.imgur.com/pbeLN0O.png) *Captura MQTT* #### Sobre los fundamentos de MQTT ##### Jerarquía de protocolos `Statistics` -> `Protocol hierarchy` ![](https://i.imgur.com/uCa5ovi.png) *Protocol Hierarchy Statistics, Wireshark* ##### Conversación entre Broker y cliente `Statistics` -> `Conversation` ```YAML --- - - Address A - Port A - Address B - Port B - Packets - Bytes - Packets A → B - Bytes A → B - Packets B → A - Bytes B → A - Rel Start - Duration - Bits/s A → B - Bits/s B → A - - 192.168.0.20 - 55794 - 52.169.76.255 - 1883 - 5 - 918 - 2 - 283 - 3 - 635 - 1.800446844 - 11.158864002 - 202.8880358784034 - 455.2434727306931 ``` `Statistics` -> `Flow Diagram` ![](https://i.imgur.com/V2ZrBbL.png) *Flow Diagram, Wireshark* #### Latencia ##### Filtrar paquetes PUBLISH MQTT En el host cliente MQTT, se filtran los paquetes de publish MQTT. El **filtro en wireshark** es `mqtt.msgtype == 3`. Se exporta la captura con el filtro aplicado en un `json`, *(File -> Export packet dissections -> as JSON)*. El delay, dado por **el tiempo entre el momento en el que se genera el mensaje LoRa en el nodo de la red, hasta que arriva al host del cliente**, se determina calculando el `delta` de tiempo entre el tiempo de arrivo que se extrae desde la captura de paquetes, y el tiempo dentro del payload LoRa, *(habiendo hecho la correspondiente conversión por diferentes timezones)*. El script de análisis es como sigue: ```shell==python import datetime as dt import requests import json import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as ticker from bs4 import BeautifulSoup def parse_date_time(date_time_str, option): """ Returns a datetime object, if option is 0, expects a string like: '2019-12-01T14:19:17.285087186Z' If option is 1, expects a string like 'Dec 1, 2019 11:19:17.639483558 -03' but uses just 17.639483 information of seconds """ if option: split_s = date_time_str.split() #split_s looks like ['Dec', '1,', '2019', '11:19:17.639483558', '-03'] split_s[-1] += '00' if len(split_s[1]) == 2: # if day is equal to one digit and a comma split_s[1] = '0' + split_s[1] # next line solves problem with too much digits for microseconds split_s[-2] = split_s[-2][:-3] date_time_s = ' '.join(split_s) return dt.datetime.strptime(date_time_s, '%b %d, %Y %H:%M:%S.%f %z') else: return dt.datetime.strptime(date_time_str[:-4] + date_time_str[-1], '%Y-%m-%dT%H:%M:%S.%f%z') #----------------------------------------------# #-------------------- MQTT --------------------# #----------------------------------------------# def mqtt_delay_from_json_capture(json_capture_path): """ Returns 4 lists: 'gen_times', 'publish_times', 'deltas' and 'deltas_milisec' according to publish mqtt packets """ with open(json_capture_path) as f: json_capture = json.load(f) gen_times = [] publish_times = [] deltas = [] for packet in json_capture: try: gen_time_str = json.loads(packet['_source']['layers']['mqtt']['mqtt.msg'])['metadata']['time'] publish_time_str = packet['_source']['layers']['frame']['frame.time'] gen_time = parse_date_time(gen_time_str, 0).astimezone() publish_time = parse_date_time(publish_time_str, 1).astimezone() delta = publish_time - gen_time except KeyError: pass gen_times.append(gen_time) publish_times.append(publish_time) deltas.append(delta) deltas_milisec = [delta.total_seconds()*1000 for delta in deltas] return gen_times, publish_times, deltas, deltas_milisec ``` #### Sobrecarga (overhead) Para analizar el **overhead** se aplican como columnas `Frame length` *(primer capa, física)* y `Msg length`, *(MQTT)* ##### Simulación ![](https://i.imgur.com/WrXYp5A.png) Se puede observar una sobre carga *(dada por la diferencia entre la longitud del mensaje y la longirud de frame)* que varía entre `66` y `69` bytes. ##### Datos reales ![](https://i.imgur.com/gsfdGVV.png) Se puede observar una sobre carga *(dada por la diferencia entre la longitud del mensaje y la longirud de frame)* de `66` bytes. ##### Seguridad Para un paquete MQTT con un mensaje lora, es posible mirar el contenido del mensaje: ![](https://i.imgur.com/Fpp4L7m.png) ```JSON {"app_eui":"70B3D57ED002380C", "dev_eui":"0037D5786316E664", "dev_addr":"26012979", "metadata":{"time":"2019-10-10T01:22:38.970294643Z", "frequency":868.5, "modulation":"LORA", "data_rate":"SF7BW125", "airtime":26880000, "coding_rate":"4/6", "gateways":[{"gtw_id":"eui-0242ee000084ee70","timestamp":1623747000, "time":"2019-10-10T01:22:38.962Z", "channel":2,"rssi":-35, "snr":5,"rf_chain":0}]}} ``` Dado que MQTT, por defecto, no implementa cifrado. ### Análisis HTTP En la aplicación creada en *thethingsnetwork*, click en `Integrations` -> `Add integrations`, seleccionar `HTTP Integration`: ![](https://i.imgur.com/3CwRjFR.png) *HTTP integration* Crear URL de API, ingresar en [requestbin](https://requestbin.com), `Create a Request bin`. *Editar la URL del endpoint en configuración de aplicación*. ### HTTP **Escribir HTTP en filtros** ![](https://i.imgur.com/235eqCx.png) *Captura HTTP* Con vista en un *POST* lora *(columna Info)*, en la pestaña HTTP, y método POST seleccionar el post lora como filtro: ![](https://i.imgur.com/B5sFfR7.png) *Captura POST lora api* #### Análisis HTTP ##### Jerarquía de protocolos `Statistics` -> `Protocol hierarchy` ![](https://i.imgur.com/o6IgB4z.png) *Protocol Hierarchy Statistics, Wireshark* ##### Handshake `Statistics` -> `Conversation` ```YAML --- - - Address A - Address B - Packets - Bytes - Packets A → B - Bytes A → B - Packets B → A - Bytes B → A - Rel Start - Duration - Bits/s A → B - Bits/s B → A - - 52.211.146.247 - 192.168.0.20 - 9 - 7000 - 0 - 0 - 9 - 7000 - 49.331159418 - 44.471642003 - 0 - 1259.2294207671107 ``` `Statistics` -> `Flow Diagram` ![](https://i.imgur.com/dwcbEcr.png) *Flow Diagram, Wireshark* #### Latencia El delay usando HTTP como protocolo de integración se realiza mediante un script que hace *scraping* sobre la página en HTML de la API hosteada en requestbin.net. ```shell==python import datetime as dt import requests import json import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as ticker from bs4 import BeautifulSoup def parse_date_time(date_time_str, option): """ Returns a datetime object, if option is 0, expects a string like: '2019-12-01T14:19:17.285087186Z' If option is 1, expects a string like 'Dec 1, 2019 11:19:17.639483558 -03' but uses just 17.639483 information of seconds """ if option: split_s = date_time_str.split() #split_s looks like ['Dec', '1,', '2019', '11:19:17.639483558', '-03'] split_s[-1] += '00' if len(split_s[1]) == 2: # if day is equal to one digit and a comma split_s[1] = '0' + split_s[1] # next line solves problem with too much digits for microseconds split_s[-2] = split_s[-2][:-3] date_time_s = ' '.join(split_s) return dt.datetime.strptime(date_time_s, '%b %d, %Y %H:%M:%S.%f %z') else: return dt.datetime.strptime(date_time_str[:-4] + date_time_str[-1], '%Y-%m-%dT%H:%M:%S.%f%z') #-----------------------------------------------# #-------------------- HTTP ---------------------# #-----------------------------------------------# def http_delay_from_api_url(url): #url = 'http://requestbin.net/r/10ojyvy1?inspect' #url = 'http://requestbin.net/r/11a0l9y1?inspect' response = requests.get(url) html_doc = response.text gen_times = [] publish_times = [] deltas = [] soup = BeautifulSoup(html_doc, 'html.parser') timestamp_divs = soup.findAll("div", {"class": "timestamp"}) for div in timestamp_divs: publish_time_str = div.find("span")['title'] publish_time_s = 'T'.join(publish_time_str.split()) + 'Z' publish_time = parse_date_time(publish_time_s, 0) publish_times.append(publish_time) requestbody_divs = soup.findAll("div", {"class": "request-body"}) for div in requestbody_divs: payload_str = div.find("pre").find(text=True) payload_json = json.loads(payload_str) gen_time_str = payload_json['metadata']['time'] gen_time = parse_date_time(gen_time_str, 0) gen_times.append(gen_time) for i, gen_time in enumerate(gen_times): delta = publish_times[i] - gen_time deltas.append(delta) deltas_milisec = [delta.total_seconds()*1000 for delta in deltas] return gen_times, publish_times, deltas, deltas_milisec ``` #### Sobrecarga (overhead) ##### Datos Para analizar el **overhead** se aplican como columnas `Frame length` *(primer capa, física)* y `Content length`, *(HTTP)*. ![](https://i.imgur.com/0wvNKiU.png) Se puede observar una sobre carga *(dada por la diferencia entre la longitud del mensaje y la longirud de frame)* promedio es de`635` bytes. Dado que se usa un servicio en la nube *(gratuito)*, el método `POST` no se genera en la LAN, por lo que no es posible sniffear con wireshark. Se descarga el contenido HTML de la URL de *requests bin*, se "escrapean" los datos de fecha y hora con `Python` como sigue: ```shell=python def http_overhead(json_capture_path, url): #url = 'http://requestbin.net/r/10ojyvy1?inspect' #url = 'http://requestbin.net/r/11a0l9y1?inspect' response = requests.get(url) html_doc = response.text soup = BeautifulSoup(html_doc, 'html.parser') frame_lengths = [] msg_lengths = [] # Next code gets msg lenghts from json capture with open(json_capture_path) as f: json_capture = json.load(f) for packet in json_capture: try: msg_length_str = json.loads(packet['_source']['layers']['mqtt']['mqtt.len']) except KeyError: pass msg_length = int(msg_length_str) msg_lengths.append(msg_length) # Next code gets frane lenghts from url span6_divs = soup.findAll("div", {"class": "span6 content"}) for div in span6_divs: texto = div.text.strip() if '\n' in texto: bytes_str = texto.split('\n ')[1].split(' ')[0] else: bytes_str = texto.split(' ')[0] bytes = int(bytes_str) frame_lengths.append(bytes) mean_msg_length = sum(msg_lengths) / len(msg_lengths) mean_frame_length = sum(frame_lengths) / len(frame_lengths) return mean_frame_length - mean_msg_length ``` ###### Seguridad Para el caso de un POST de mensaje lora por HTTP (API), el contenido del mensaje **no es visible**, dado que está cifrado. ![](https://i.imgur.com/KdLRXOc.png) ## Resultados | Parámetro | MQTT (sim) | MQTT (real) | HTTP (sim) | HTTP (real) | |-----------|------------|-------------|------------|-------------------------| | **latencia** | 379.298500 [ms] | 305.594625 [ms] | 524.574300 [ms] | 1113.238350[ms] * | | **overhead** | 69 bytes | 69 bytes | 110.5 bytes | 168.924 bytes | | cifrado | no | no | si | si | `*` Dato no significativo para el análisis. ![](https://i.imgur.com/Z5bUWUh.png) **(tiempo en milisegundos)**. *Gráfico comparativo delay en protocolos MQTT y HTTP para una red LoRaWAN simulada y una real.* ## Análisis de los resultados Ambos protocolos de aplicación, pero en particular de *integración* en el contexto de una red LoRaWAN, cumplen con el objetivo de servir los datos de nodos LoRa. Para el relevamiento de los dos parámetros de interés, se observa una diferencia muy significativa que favorece a MQTT, sin embargo para este último protocolo las credenciales de autorización son transparentes. > Se puede implementar una capa de seguridad con MQTTS. Desde el enfoque comparativo de los resultados de la red LoRaWAN *simulada* versus la red *"real"*, se observa una cohesión del comportamiento. > Cabe aclarar que el resultado obtenido para delay empleando HTTP en la red real, no resulta comparable y su desproporción se debe al uso de un sevicio gratuito y en la nube. ## Conclusiones MQTT resulta un protocolo de aplicación/integración versátil, de muy baja latencia y sobrecarga para aplicaciones de internet de las cosas, donde se requieren enviar pequeños mensajes y en algún contexto, puedan requerir ser entregados con urgencia. HTTP sin embargo muestra robustez respecto a la seguridad del mensaje, implementando por defecto un cifrado del mismo y se integra fácilmente a soluciones comerciales. Los resultados obtenidos para redes simuladas, respecto a las reales, son congruentes y permiten confirmar lo anterior. ## Proyección Se proyecta un entorno de simulación con incremento de dispositivos y de mensajes enviados, para evaluar además las colisiones y retransmisiones, parámetros que impactan directamente en la latencia y en la confiabilidad de los datos. Como mejora de la metodología de análisis se propone implementar capturas de paquetes salientes además de los recibidos, establecer un algoritmo de correlación y comparar dichos tiempos. ## Bibliografía Technical Marketing Workgroup 1.0, [**"LoRaWAN. What is it?"**](https://lora-alliance.org/resource-hub/what-lorawanr), [*LoRa Alliance*](https://lora-alliance.org/), Noviembre 2015. [*LoRa Alliance*](https://lora-alliance.org/), [**"LoRaWAN Regional Parameters v1.0.3revA"**](https://lora-alliance.org/resource-hub/lorawanr-regional-parameters-v11rb), [LoRa Alliance](https://lora-alliance.org/resource-hub/lorawanr-regional-parameters-v103reva), Inc., 2017 [Cuadro de Atribución de Bandas de Frecuencias de la República Argentina](https://www.enacom.gob.ar/cuadro-de-atribucion-de-bandas-de-frecuencias-de-la-republica-argentina-cabfra-_p1588), CABFRA, Julio 2019. [Resolución 581MM18](https://www.enacom.gob.ar/multimedia/normativas/2018/res581MM.pdf), Poder Ejecutivo Nacional, Septiembre 2018. Admin (10 de Octubre de 2018). ["LoRa- (Long Range) Network and Protocol Architecture with Its Frame Structure"](http://www.techplayon.com/lora-long-range-network-architecture-protocol-architecture-and-frame-formats) [*Entrada en un blog*]. Recuperado de [Techplayon](http://www.techplayon.com). [Carsten Bormann](mailto:cabo@tzi.org?subject=cbor.io), [RFC 7049 - Concise Binary Object Representation (CBOR)](https://cbor.io/), Octubre de 2013. ["LoRaWAN - OTA or ABP?"](https://static1.squarespace.com/static/560cc2c2e4b01e842d9fac18/t/5a938d38ec212d9451fbecf8/1519619387035/OTAA_or_ABPv3.pdf), Newie Ventures. [Documentación oficial Semtech UDP](https://github.com/LoRa-net/packet_forwarder/blob/master/PROTOCOL.TXT), Semtech-Cycleo. [Documentación oficial Basic Station Forwarder](https://doc.sm.tc/station/), Semtech Corp. G. C. Hillar, [*MQTT Essentials - ALightweight IoT Protocol*](http://ebooks.blt4spd.com/ebooks/titles/2596/file/MQTT%20Essentials%20-%20a%20Lightweight%20-%20Gaston%20C.%20Hillar.pdf), Birmingham, UK: Packt Publishing Ltd, 2017.