# ULEAM - T.4.2 Protocolo MQTT

El protocolo MQTT es un protocolo de conectividad de máquina a máquina (M2M)/"Internet de las cosas". Diseñado como un transporte de mensajería de publicación/suscripción extremadamente liviano, es útil para conexiones con ubicaciones remotas donde se requiere poco código y/o el ancho de banda de la red es un bien escaso.
El protocolo generalmente se ejecuta sobre TCP / IP; sin embargo, cualquier protocolo de red que proporcione conexiones bidireccionales ordenadas y sin pérdidas puede admitir MQTT. RabbbitMQ ofrece MQTT y entre las caracteristicas soportadas se describen a continuación:
* Publicación y consumo de QoS0 y QoS1
* Publicación de QoS2
* TLS
* Mensajes retenidos con backends
Para habilitar el protocolo MQTT sobre RabbitMQ lo primero que se debe realizar es habilitar el Plugin. En este taller se describe los pasos para habilitar RabbitMQ sobre windows. Adicionalmente, se describe un ejemplo de código publish-subscribe en Python y usando el módulo Paho.
## Habilitar Plugin MQTT en RabbitMQ
El complemento MQTT está incluido en la distribución RabbitMQ. Antes de que los clientes puedan conectarse correctamente, debe habilitarse mediante rabbitmq-plugins.
```
rabbitmq-plugins enable rabbitmq_mqtt
```
1. Antes de digitar la instrucción anterior, compruebe si el servicio del protocolo MQTT está ejecutándose en su servidor broker local. Para realizar dicha acción inicie sesión con el usuario guest y contraseña guest y compruebe los servicios y puertos activos. En la figura se muestra los puertos y servicios que se están ejecutando en el servidor broker local.

2. Ubiquese en la raiz de la instalación en la figura siguiente se muestra la ruta donde se encuentran los binarios de ejecución para RabbitMQ.

3. Habilite el protocolo MQTT para RabbitMQ mediante el siguiente comando.
```
rabbitmq-plugins enable rabbitmq_mqtt
```
4. En la figura siguiente se muestra la respuesta luego de haber digitado dicho comando

6. Seguidamente, crearemos un nuevo usuario con su respectivo permisos. Para dicho propósito nos posicionaremos en la ruta del paso 2. Seguidamente digitaremos las siguientes sentencias:
```
rabbitmqctl add_user mqtt-test mqtt-test
rabbitmqctl set_permissions -p / mqtt-test ".*" ".*" ".*"
rabbitmqctl set_user_tags mqtt-test management
```

7. Esta acción permite crear el usuario mqtt-test con la contraseña mqtt-test.
8. Si su servidor se encuentra en un computador remoto configure los accesos del firewall de windows para que pueda permitir el puerto 1883.
9. Finalmente, comprueba el servidor y verifique que se encuentre activo el protocolo mqtt y el puerto en el cual se encuentra escuchando. Inicie sesión con el usuario guest contraseña guest.

:::info
:bulb: **TimeoutError: [WinError 10060]**: Se produjo un error durante el intento de conexión ya que la parte conectada no respondió adecuadamente tras un periodo de tiempo, o bien se produjo un error en la conexión establecida ya que el host conectado no ha podido responder.
:::
## Instalación del paquete PAHO
El paquete Paho proporciona una clase cliente que permite que las aplicaciones se conecten a un agente MQTT para publicar mensajes, suscribirse a temas y recibir mensajes publicados. También proporciona algunas funciones auxiliares para que la publicación de mensajes únicos en un servidor MQTT sea muy sencilla.
Es compatible con Python 2.7.9+ o 3.6+.
Para instalar dicha librería lo puede realizar mediante el comando pip para instalaciones en donde no se usa anaconda. O con el comando conda. A continuación se indica las das opciones:
```
pip install paho-mqtt
```
```
conda install -c conda-forge paho-mqtt
```
Está ultima opción se la realiza mediante la consola de anaconda. En las figuras siguientes se muestra la instalación del paquete paho-mqtt mediante la consola de anaconda.


## Código del consumidor - subscribe
Copie el siguiente código en un nuevo archivo denominado `mqtt-subscribe1.py` y guarde en una carpeta de su preferencia ejemplo: "uleam-iot" o "mqtt".
```Python=
import random
import paho.mqtt.client as mqtt #import the client1
mClientId = f'python-mqtt-{random.randint(0, 1000)}'
mBroker = '127.0.0.1'
mPort = 1883 #mosquito
mTopic = "uleam/fcvt/ti/#"
mUsername = 'mqtt-test'
mPassword = 'mqtt-test'
def connect_mqtt() -> mqtt:
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt.Client(mClientId)
client.username_pw_set(mUsername, mPassword)
client.on_connect = on_connect
client.connect(mBroker, mPort)
return client
def subscribe(client: mqtt):
def on_message(client, userdata, msg):
print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
#mData=json.loads(msg.payload)#Decode the JSON string
#print(mData)
client.subscribe(mTopic)
client.on_message = on_message
def run():
client = connect_mqtt()
subscribe(client)
client.loop_forever()
if __name__ == '__main__':
run()
```
En general, independiente de la librería utilizada, el código anterior difiere del intercambiador APMQP-Topic por su tema (tópico), que ha diferencia del rounting-key que usa el signo ".", en MQTT se usa el signo "/". En particular, todo código suscriptor (consumidor) proporciona los métodos conectar, y suscriptor. El método suscriptor, define un método que muestra el mensaje y es el que se registra a un tópico específico.
## Configuración del publicador - publisher
El ejemplo siguiente sigue el mismo contexto de los casos anteriores. Copie el código en un nuevo archivo denominado `mqtt-publisher1.py` y guarde en la carpeta que definió anteriormente .
```Python=
import random
import paho.mqtt.client as mqtt #import the client1
mClientId = f'pythonpc-{random.randint(0, 1000)}'
mBroker = '127.0.0.1'
mPort = 1883
mTopic = "uleam/fcvt/ti/sensor01"
mUsername = 'mqtt-test'
mPassword = 'mqtt-test'
def connect_mqtt() -> mqtt:
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt.Client(mClientId)
client.username_pw_set(mUsername, mPassword)
client.on_connect = on_connect
client.connect(mBroker, mPort)
return client
client = connect_mqtt()
client.loop_start()
try:
while True:
mensaje = input("Ingrese un mensaje: ")
client.publish(mTopic, mensaje) # Publicar el mensaje en un tema específico
except KeyboardInterrupt:
pass
# Desconexión del cliente MQTT
client.loop_stop()
client.disconnect()
```
Siguiendo el contexto anterior, en el código `mqtt-publisher1.py` adicional al método conectar, se define el método publish, este permite enviar (dado un tópico o tema) el mensaje al broker MQTT. También, se observa la función que se ha estado usando en programas anteriores que permite obtener el mensaje.
## Ejecución del programa
Para validar la ejecución de los códigos publish/subscribe se sigue el mismo procedimiento como el taller de sockets. Ejecute el consumidor y luego ejecute el publicador. Verifique los resultados. Recuerde que debe usar dos consolas para validar lo anterior.
:::info
:bulb: **Tarea**: Se le solicita que realice lo siguiente:
1. Cree una cuenta [CloudAMQP]. Seguidamente, haga los cambios respectivos y verifique el envío y recepción del mensaje usando MQTT.
:::