MQTT

De Wiki Cursos IFPR Foz
Ir para navegaçãoIr para pesquisar

MQTT - Message Queue Telemetry Transport

MQTT (Message Queue Telemetry Transport) é um protocolo de mensagens para sensores e pequenos dispositivos móveis, baseado no modelo publicador/subscritor, ideal para aplicações de Internet das Coisas, em particular para a comunicação máquina a máquina (M2M - Machine to Machine).

Referências:

As aplicações de Internet das Coisas podem envolver abordagens avançadas de telemetria, de forma a poder conectar diferentes dispositivos inteligentes em atividades de sensoreamento, monitoramento e controle, além da conexão dos mesmos a Internet ou a sistemas de controle central [1].

MQTT - Conceitos básicos

Conceitos básicos do MQTT [1]
  • Publicador/Subscritor: O protocolo MQTT é baseado no modelo publisher/subscriber, isto é, o princípio de publicar mensagens (publisher) e subscrever tópicos (subscriber) para receber mensagens.
    Um cliente pode subscrever tópicos e receber mensagens de atualizações quando algo for publicado sobre este tópico. Alternativamente, um cliente pode publicar mensagens relativas a um dado tópico e deixá-la disponível para os assinantes.
  • Tópicos e subscrições: As mensagens MQTT são publicadas em tópicos (topic), que são áreas de interesse.
    Os clientes, por sua vez, assinam para receber mensagens de uma dada subscrição. As subscrições podem ser explicitas, ou organizadas hierarquicamente, com o cliente usando wildcards (# ou +) para receber mensagens de uma variedade de tópicos.
    Exemplos:
    • topic: /casa/terreo/temperatura
    • topic: /casa/terreo/umidade
    • topic: /casa/superior/temperatura
    • topic: /casa/superior/umidade
    • wildcard multilevel: /casa/# -> todos os sensores da casa (# multinível)
    • wildcard sigle level: /casa/+/temperatura -> todos os sensores de temperatura (+ somente um nível)

  • Qualidade de Serviço: O MQTT define três níveis de Qualidade de Serviço (QoS):
    • (0) best effort, envia a mensagem uma vez;
    • (1) envia a mensagem uma ou mais vezes, podendo haver mensagens duplicadas;
    • (2) assegura o recebimento de apenas uma mensagem.
  • Retem as mensagens: O servidor MQTT retem as mensagens publicadas no brocker mesmo depois de enviada a todos os subscritores.
  • Conexões duráveis e sessões limpas: Quando um cliente se conecta a um servidor com a flag clean session = true após ele se desconectar todas as subscrições serão removidas. Se a flag clean session = false (opcional) a conexão é tratada como durável e as subscrições do cliente continuam mesmo após uma desconexão.
  • Will: Característica também chamada LWT (Last Will and Testament) do MQTT. Quando um cliente se conecta a um servidor e pode informar que possui uma will, isto é, mensagens importantes que deveriam ser publicadas, mesmo em caso de desconexão involuntária. É necessária uma atribuição prévia das mensagens que deveriam ser enviadas, chamado testamento. Isto é importante para sensores de alerta, que informam o sistema caso percam o contato com a rede.

O modelo publisher/subscriber oferece uma alternativa ao modelo cliente/servidor. No modelo cliente/servidor o cliente se comunica diretamente o servidor num serviço fim a fim. No modelo publisher/subscriber o publicador e o subscritor não se comunicam diretamente. A comunicação é realizada por um terceiro componente, o brocker [2].

Mensagens do protocolo MQTT [2]

O protocolo MQTT trabalha no topo da pilha de protocolos TCP/IP.

O modelo publisher/subscriber do MQTT desacopla a mensagem enviada pelo cliente publicador (publisher) do cliente subscritor (subscriber).

O MQTT usa tópicos para determinar quais mensagens vão ser encaminhadas a cada subscriber.

Cliente MQTT
Tanto o publisher quanto o subscriber são clientes MQTT.
Um cliente MQTT é qualquer dispositivo que rode a biblioteca MQTT, desde um microcontrolador até um servidor de grande porte.
brocker MQTT
O brocker MQTT intermedeia a comunicação entre os clientes publicadores e subscritores.
O brocker é o responsável de receber todas as mensagens, determinar quais são os subscritores de cada mensagem, e, em seguida, encaminhar as estas mensagens aos subscritores.
Blibliotecas MQTT
Bibliotecas cliente MQTT estão disponíveis em diferentes linguagens de programação, como Android, Arduino, C, C++, Ct#, Go, iOS, Java, JavaScript, and .NET. Veja lista completa em MQTT wiki.


Mensagens de Conexão

Uma conexão MQTT é sempre entre um cliente e um brocker. O cliente inicia a conexão enviando uma mensagem CONNECT ao brocker, que responde com a mensagem CONNACK. A conexão é mantida até que o cliente envie uma mensagem DISCONNECT.

Cliente              Brocker
   |    ---------->     |
   |      CONNECT       |
   |    <----------     |
   |      CONNACK       |
Detalhe das mensagens
CONNECT
clientId        "cliente1"  
cleanSession    true
username        "user1"           (opcional)
passwd          "1234"            (opcional)
lastWillTopic   "topic1/will"     (opcional)
lastWillQoS     2                 (opcional)
lastWillMessage "unexpected exit" (opcional)
lastWillRetain  false             (opcional)
keepAlive       60

O clientId é um identificador único do cliente para o brocker com o qual vai se comunicar.

A flag cleanSession informa se a sessão é persistente ou não.

O username e passwd são enviados em modo texto, portanto, é aconselhável utilizá-las juntamente com transporte seguro através de autenticação de clientes com SSL.

Os parâmetros lastWill são utilizados pelo brocker para notificar clientes subscritores sobre uma desconexão involuntária deste publicador. Quando um cliente de conecta e informa ao brocker, pela mensasgem CONNECT, o tópico, a QoS e a mensagem lastWill. No caso de uma desconexão involuntária deste cliente o brocker envia a mensagem lastWill aos clientes subscritores.

O parâmetro keepAlive informa o tempo em segundos que o cliente pode ficar sem se comunicar com o brocker depois de iniciada a conexão. Para manter a conexão ativa, caso não haja comunicação, o cliente deve enviar regularmente a mensagem PING Request ao brocker, que responde com PING Replay.

CONNACT
sessionPresent  false
returnCode      0

O parâmetro sessionPresent informa ao cliente se o brocker já tem uma conexão persistente anterior com este cliente.

O parâmetro returnCode é o retorno com o estado da conexão, que pode ser:

  • 0 Conexão aceita
  • 1 Conexão recusada: versão inválida
  • 2 Conexão recusada: userId rejeitada
  • 3 Conexão recusada: servidor não disponível
  • 4 Conexão recusada: username ou passwd inválida
  • 5 Conexão recusada: não autorizado

Keep Alive

Para manter a conexão ativa entre um cliente e o brocker, caso não haja publicação, o cliente deve enviar regularmente a mensagem PING Request ao brocker, que responde com PING Response.

PINGREQ
PINGRESP

Se o brocker não recebe um PINGREQ ou algum outro pacote do cliente, o brocker fecha a conexão e envia a última mensagem will e testamento (caso o cliente especificou um LWT).

Mensagem para Publicação

O cliente publica mensagens assim que estabelece a conexão com o brocker. Cada mensagem contem um tópico, que é utilizado para encaminhar a mensagem aos clientes subscritores.

A mensagem de publicação é utilizada também pelo brocker para encaminhar as mensagens publicadas aos subscritores.

PUBLISH
packetId    0
topicName   "sensor/temperatura"
qos         0
retainFlag  true
payload     "25,0"
dupFlag     false
O parâmetro packetId é um identificador único para a mensagem e é utilizado para retransmitir mensagens com QoS diferente de 0. A biblioteca do cliente e/ou brocker é responsável por gerenciar os identificadores.
O parâmetro retainFlag define quando a mensagem deve ser salva no brocker como último valor bom para este tópico.
O dupFlag indica que a mensagem é uma duplicata sendo retransmitida para um cliente que não enviou um reconhecimento da anterior. É utilizado para retransmitir mensagens com QoS diferente de 0.

Publicação com Qualidade de Serviço (QoS)

O protocolo MQTT define três níveis de Qualidade de Serviço (QoS):

  • (0) best effort, envia a mensagem uma vez;
  • (1) envia a mensagem pelo menos uma vez, mas podem haver mensagens duplicadas, e aguarda confirmação de recebimento;
  • (2) assegura o recebimento uma única mensagem e da confirmação do recebimento.

No MQTT a QoS deve considerar os dois lados da entrega da mensagem:

  • A comunicação entre o cliente publicador e o brocker;
  • A comunicação entre o brocker e os clientes subscritores.

A QoS é considerada separadamente. O cliente publicador define a QoS quando publica no brocker. O brocker, por sua vez, encaminha a mensagem ao cliente subscritor de acordo com a QoS definida no momento da subscrição. Caso a subscrição tenha QoS maior que o que foi publicado, utiliza-se a menor QoS.

QoS = 0
Serviço best-effort, sem garantia de entrega da mensagem.
Emissor                  Receptor   Ação
   |    -------------->     |       -Publica a mensagem aos subscritores
   |     PUBLISH QoS=0      |
QoS = 1
A mensagem é enviada pelo menos uma vez ao receptor. O emissor armazena a mensagem até receber um reconhecimento do receptor com a mensagem PUBACK. O PUBACK utiliza o packetId da mensagem publicada para reconhecer a mensagem. Caso o emissor não receba reconhecimento num tempo apropriado a mensagem é reenviada com dupFlag = true. Se o receptor recebe uma mensagem duplicada ele responde com PUBACK e reencaminha a mensagem aos subscritores. Note que os subscritores também podem receber mensagens duplicadas.
Cenário 1: Uma mensagem enviada:
Emissor                  Receptor   Ação
   |    -------------->     |       -Armazena a mensagem na base de dados
   |     PUBLISH QoS=1      |       -Publica a mensagem aos subscritores
   |    <--------------     |
   |        PUBACK          |
Cenário 2: Mais de uma mensagem enviada:
Emissor                  Receptor   Ação
   |    -------------->     |       -Armazena a mensagem na base de dados
   |     PUBLISH QoS=1      |       -Publica a mensagem aos subscritores
   |          X--------     |
   |        PUBACK          |
   |    -------------->     |       -Atualiza base de dados
   |     PUBLISH QoS=1      |       -Publica a mensagem aos subscritores
   |    <--------------     |
   |        PUBACK          |


QoS = 2
É a maior QoS do MQTT. Garante a entrega de apenas uma mensagem aos subscritores . O protocolo utiliza um acordo em quatro vias entre o emissor e o receptor.
O QoS=2 deve ser utilizado somente se não forem desejadas mensagens duplicadas.
Emissor                  Receptor   Ação
   |    -------------->     |       -Armazena e bloqueia a mensagem na base de dados
   |     PUBLISH QoS=2      |       (se houver mensagens duplicadas atualiza base de dados)
   |    <--------------     |       
   |        PUBREC          |
   |    -------------->     |       -Publica a mensagem aos subscritores
   |        PUBREL          |       
   |    <--------------     |
   |        PUBCOMP         |
A mensagem é enviada pelo emissor com PUBLISH. Caso o receptor receba a mensagem ele reconhece com PUBREC e deixa a mensagem bloqueada no servidor. Se o emissor não recebe o PUBREC num tempo apropriado ele envia novamente a mensagem com dupFlag = true. Caso o emissor receba o PUBREC ele tem a garantia que o receptor recebeu a mensagem e envia o PUBREL. Quando o receptor recebe o PUBREL ele responde com PUBCOMP e então encaminha a mensagem aos subscritores. As mensagens trocadas utilizam o packetId da mensagem publicada para reconhecimento.

Mensagens para e Subscrição

Para receber mensagens um cliente deve subscrever um dado tópico em um brocker MQTT.

SUBSCRIBE
packetId      4343 (exemplo)
List of Subscritions:
topic         "sensores_ambiente/#"
qos           0
topic         "sensor/alerta"
qos           1
O packetId é um identificador único para a mensagem entre o cliente e o brocker. A biblioteca do cliente e/ou brocker é responsável por gerenciar os identificadores.
A List of Subscritions contém a lista de subscrições do cliente, cada qual contendo um tópico e a QoS. O tópico pode ser expresso de forma explícita ou de maneira hierárquica, separados por com /, e também pode utilizar wildcards (# ou +).

Cada subscrição é confirmada com SUBACK.

SUBACK
packetId    4343 (exemplo)    
returnCode  0
returnCode  1
...
O packetId é o mesmo identificador da mensagem SUBSCRIBE correspondente.
O returnCode informa o código para cada par tópico/QoS como segue:
  • 0 Sucesso: máximo QoS 0
  • 1 Sucesso: máximo QoS 1
  • 2 Sucesso: máximo QoS 2
  • 128 Falha
Cliente A               Brocker            Cliente B
   |      ----------->     |                     |
   |        SUBSCRITE      |                     |
   |      <-----------     |                     |
   |         SUBACK        |                     |
   |                       |    <----------      |
   |      <-----------     |      PUBLISH        |
   |        PUBLISH        |                     |

Um cliente pode cancelar uma subscrição com UNSUBSCRIBE.

UNSUBSCRIBE
packetId    4344 (exemplo)   
topic1      "/sensor/temp"
topic2      "/sensor/umid"
...
O packetId é um identificador único para a mensagem entre o cliente e o brocker. A biblioteca do cliente e/ou brocker é responsável por gerenciar os identificadores.

Reconhecimento

UNSUBACK
packetId
O packetId é o mesmo identificador da mensagem UNSUBSCRIBE correspondente.

MQTT - sensores e atuadores

O MQTT tem aplicabilidade especial para dispositivos para sensoriamento remoto [1].

Sensores
Sensores medem ou monitoram parâmetros do ambiente ou de um sistema e reportam a informação para humanos ou outros dispositivos ou sistemas. Com a ajuda do protocolo MQTT a informação obtida pelos sensores pode ser realizada via rede.
Múltiplos sensores podem ser posicionados para reportar vários parâmetros e medições em diferentes localizações, dando uma visão completa das condições de operação de um dispositivo ou sistema.
Atuadores
Atuadores são dispositivos que atuam sobre variáveis de um sistema visando alterar seu comportamento.

O controle de um sistema normalmente envolve sensores monitorando parâmetros do sistema e atuadores visando corrigir sua operação. A ação de controle é realizada a partir de um algoritmo de controle, que pode ser executado por controlador central, ou diretamente pelos sensores/atuadores, que, neste caso, devem ter processamento no próprio sensor/atuador.

O modelo publisher/subscriber do MQTT pode ser bastante útil para interligar sensores, atuadores e sistemas de controle em diferentes tipos de aplicações, em particular àquelas que envolvem as chamadas tecnologias de Internet das Coisas.

MQTT e Arduino

O suporte para MQTT para Arduíno é provido por uma biblioteca que pode ser obtida em: https://github.com/knolleary/pubsubclient .

Para interagir com a rede é necessário um shild Ethernet colocado sobre a placa Arduíno.

Limitações do MQTT para Arduíno
  • Suporta somente publicações com QoS=0 e subscrições com QoS=0 ou QoS=1.
  • Tamanho máximo de mensagem com 128 bytes por default.
  • Intervalo de keep alive de 15 s por default.
Hardware compatível
  • Shield Ethernet
  • Arduíno Ethernet
  • Arduíno Yun
  • Arduíno Wifi
  • ESP8266
  • ESP32

Mosquitto

Mosquitto é um Brocker MQTT open source, que pode ser utilizado desde computadores de placa única até servidores.

O Mosquitto implementa o modelo publilsher/subscriber e pode ser utilizado em aplicações de Internet das Coisas, as quais fazem uso de sensores de baixa potência, atuadores, dispositivos móveis, microcontroladores e outros dispositivos programáveis.

O Mosquitto oferece comandos de linha como mosquitto_pub e mosquitto_sub para publicar e subscrever no brocker, respectivamente, além de bibliotecas em C para implementação de cliente MQTT.

Instalação e inicialização do Mosquitto no Ubuntu

sudo apt-get update
sudo apt-get mosquitto
sudo apt-get install mosquitto-clients

Depois de instalado no Ubuntu o Mosquito é automaticamente iniciado, assim como é iniciado a cada reboot. Para verificar se está rodando, pode utilizar o comando:

ps -aux|grep mosquitto

Parar, iniciar ou reiniciar Mosquitto:

service mosquitto stop
service mosquitto start
service mosquitto restart

Iniciar o Mosquitto com verbose dos logs de operação:

mosquitto -v 

Páginas man:

man mosquitto

Porta TCP de escuta do Mosquitto

O Mosquitto de escuta por padrão na porta TCP 1883.

A porta pode ser alterada com um parâmetro na inicialização:

mosquitto -p 1888
ou especificando no arquivo de configuração:
/etc/mosquitto/mosquitto.conf

Teste do Mosquitto

Use um terminal para subscrever um tópico:

mosquitto_sub -t "teste"

Use outro terminal para publicar uma mensagem em um tópico:

mosquitto_pub -m "Mensagem" -t "teste"

Usuários e senhas podem ser configurados para uso no Mosquito, ver [3] [4].

Ver detalhes e exemplos destes comandos em:

man mosquitto_pub
man mosquitto_sub

Analise do protocolo MQTT e Mosquitto com Wireshark

Realização do experimento
Realizado em computador com sistema operacional Ubuntu.
  • Iniciar o Mosquitto (escutando na porta TCP padrão 1883).
  • Iniciar o analisador de pacotes Wireshark:
    • configurar captura para o endereço IP do localhost (127.0.0.1);
    • configurar filtro para o protocolo mqtt.
  • Abrir dois terminais: (1) para executar o mosquitto_sub e (2) para executar o mosquitto_pub.
  • No terminal (1) executar o comando:
mosquitto_sub -t "teste"
  • Observar no Wireshark os pacotes capturados.
  • Aguardar tempo e verificar captura de pacotes de PINGREC e PINGRESP que visam manter a conexão ativa (keep alive).
  • No terminal (2) executar o comando:
mosquitto_pub -m "Mensagem" -t "teste"
  • Observar no Wireshark os pacotes capturados.
  • Aguardar tempo e verificar captura de pacotes outros PINGREC e PINGRESP.
  • No terminal (1) realizar CTRL-C para cancelar a subscrição do tópico.
  • Observar no Wireshark os pacotes capturados.

Análise das mensagens do protocolo MQTT capturadas

Saída do Wireshark
Salvas em formado ASCII com o comando Statistics/Flow Graph.
|Time         |Port Or     127.0.0.1         Port Dst|                   
| 35.042444068|         Connect Command              |MQTT: Connect Command
|             |(56826)  ------------------>  (1883)  |
| 35.044310152|         Connect Ack                  |MQTT: Connect Ack
|             |(1883)   ------------------>  (56826) |
| 35.044457320|         Subscribe Request            |MQTT: Subscribe Request (id=1) [teste]
|             |(56826)  ------------------>  (1883)  |
| 35.044674094|         Subscribe Ack                |MQTT: Subscribe Ack (id=1)
|             |(1883)   ------------------>  (56826) |
| 95.108438935|         Ping Request                 |MQTT: Ping Request 
|             |(56826)  ------------------>  (1883)  |
| 95.108667264|         Ping Response                |MQTT: Ping Response
|             |(1883)   ------------------>  (56826) |
|143.557210682|         Connect Command              |MQTT: Connect Command
|             |(56838)  ------------------>  (1883)  |
|143.557367867|         Connect Ack                  |MQTT: Connect Ack
|             |(1883)   ------------------>  (56838) |
|143.557412443|         Publish Message              |MQTT: Publish Message [teste]
|             |(56838)  ------------------>  (1883)  |
|143.557464819|         Disconnect Req               |MQTT: Disconnect Req
|             |(56838)  ------------------>  (1883)  |
|143.557548521|         Publish Message              |MQTT: Publish Message [teste]
|             |(1883)   ------------------>  (56826) |
|155.568781503|         Ping Request                 |MQTT: Ping Request
|             |(56826)  ------------------>  (1883)  |
|155.569040363|         Ping Response                |MQTT: Ping Response
|             |(1883)   ------------------>  (56826) |
|193.756460789|         Disconnect Req               |MQTT: Disconnect Req
|             |(56826)  ------------------>  (1883)  |
Análise dos pacotes capturados
Em cada coluna são mostrados a marca de tempo, porta origem, mensagem, porta destino, resumo.
  • Após a execução do comando:
mosquitto_sub -t "teste"
  • Foram capturadas as mensagens MQTT:
Connect Command
Connect Ack
Subscribe Request
Subscribe Ack
Sequência de mensagens de conexão, reconhecimento, subscrição e reconhecimento do cliente subscritor.
Note que as mensagens estão todas na marca de tempo 35.0...
Note que a porta origem do cliente subscritor é 56826 e a porta destino do brocker é 1883.
  • Depois de uma espera de 60s, foram capturadas as mensagens:
Ping Request
Ping Response
Estas mensagens correspondem ao keep alive da conexão MQTT.
Note que as portas origem e destino são as mesmas do cliente subscritor.
  • Após a execução do comando:
mosquitto_pub -m "Mensagem" -t "teste"
  • Foram capturadas as mensagens MQTT:
Connect Command
Connect Ack
Publish Message
Publish Req
Disconnect Req
Publish Message
Sequência de 5 mensagens do cliente publicador com conexão, reconhecimento, publicação, reconhecimento e desconexão.
Note que a porta origem do cliente publicador é 56838 e a porta destino do brocker é 1883.
A segunda publicação refere-se a publicação do brocker ao subscritor (porta 56826).
  • Após mais um tempo de 60s no subscritor tivemos outra sequência de keep alive.
Ping Request
Ping Response
  • Por fim, após o CTRL-C no subscritor tivemos a conexão encerrada.
Disconnect Req

Referências

  1. 1,0 1,1 1,2 1,3 Valerie Lampkin; Weng Tat Leong; Leonardo Olivera; Sweta Rawat; Nagesh Subrahmanyam; Rong Xiang. Building Smarter Planet Solutions with MQTT and IBM WebSphere MQ Telemetry, ibm.com/redbooks, 2012.
  2. 2,0 2,1 2,2 MQTT Essentials: The Ultimate Kickstart For MQTT Beginners, https://www.hivemq.com/mqtt-essentials/.
  3. Fernando Veiga. Instalar MQTT-Broker no Linux, Things Hackers Team, 2018.
  4. Faz-B. Instalando, testando e conhecendo o MQTT no Ubuntu, 2017.

Evandro.cantu (discussão) 11h27min de 25 de março de 2020 (-03)