MQTT - Protocolos para IoT

mqtt

Febre. Moda. Hype. Qualquer uma das três palavras descreve bem o cenário do conjunto de tecnologias conhecida como Internet das Coisas (IoT, do inglês, Internet of Things). Uma profusão de plataformas em núvem, sensores, hardware diversos e módulos vêm aparecendo, gerados pelos mais diversos fabricantes. Intel, Microsoft, Samsung, ARM, Google, IBM, Apple, só para citar algumas gigantes, têm hoje setores devotados a criar soluções para IoT. Com este panorama, é ainda difícil dizer quais serão os líderes de mercado dos próximos anos em IoT, se é que teremos algum.

 

Na área de protocolos não é diferente: inúmeras propostas e implementações já existem. Leves mudanças de escopo, algumas pequenas diferenças de casos de uso já são suficientes para que a companhia proponha o seu novo protocolo para IoT.

 

Um dos protocolos de troca de mensagens para IoT em uso recente é o MQTT (Message Queue Telemetry Transport). Criado pela IBM no final da década de 90, obviamente o protocolo carrega muito do cenário de uso original, mais voltado e adaptado para sistemas de supervisão e coleta de dados do tipo SCADA (Supervisory Control and Data Acquisition ou Sistemas de Supervisão e Aquisição de Dados, em português). Mas, mesmo assim, o MQTT encontrou seu espaço nesse amplo mercado de IoT.

 

O MQTT não é tão sofisticado quanto o AMQP (Advanced Message Queuing Protocol), que possui mais funcionalidades e cenários de uso, mas é simples o suficiente sem deixar de contemplar características como segurança, qualidade de serviço e facilidade de implementação. Essas características fazem do MQTT um bom candidato para implementações e usos em sistemas embarcados, embora a competição seja acirrada.

 

Neste artigo discutiremos um pouco sobre o MQTT, explicando o seu funcionamento e aplicações.

 

 

Publish/Subscriber do MQTT e tópicos

 

O padrão de troca de mensagens no MQTT é o publish/subscriber (publicador/subscritor). Neste padrão, quando um elemento da rede deseja receber uma determinada informação, ele a subscreve, fazendo uma requisição para um outro elemento da rede capaz de gerir as publicações e subscrições. Na rede MQTT este elemento é conhecido como broker, o intermediário no processo de comunicação. Elementos que desejam publicar informações o fazem também através do broker, enviando-lhe as informações que possuem. Esse padrão não é novo e existe em outros protocolos. Por exemplo, a troca de informação de controle (links) em redes Foundation Fieldbus segue o paradigma publish/subscriber.

 

Apesar de o broker representar um elo de fragilidade na rede ao centralizar as comunicações, ele permite um desacoplamento entre as partes comunicantes, algo não possível em modelos de comunicação do tipo cliente/servidor. Vale lembrar que existem soluções de brokers redundantes ou operando em clusters, na tentativa de mitigar esta fragilidade.

 

MQTT verview - Publish/subscriber
Figura 1 - MQTT overview

  

A identificação das mensagens no MQTT se dá através de tópicos (topics). O tópico lembra o conceito de URI, com níveis separados por barras (“/”). Elementos da rede podem enviar diversos tópicos para o broker e subscritores podem escolher os tópicos que desejam subscrever.

 

Por exemplo, imagine que, em uma rede de sensores, existam vários sensores diferentes de temperatura e umidade, publicando o valor do sensor como o dado útil (payload) e identificando as mensagens com tópicos nos seguintes formatos:

 

 

Neste esquema, possíveis publicações seriam: 

 

 

Ou seja, temos informações provenientes de duas áreas diferentes (10 e 20) sendo geradas por quatro sensores (5000, 5001, 4000, 4001), onde cada sensor publica temperatura e umidade. O valor da temperatura ou umidade faz parte dos dados da mensagem, sendo o formato algo dependente da aplicação, uma vez que o MQTT não impõe restrições sobre isso. Seria possível codificar a mensagem em json, ou mesmo enviar um valor binário de 16 bits para cada variável, entre outras formas.

 

Um subscritor pode assinar estas mensagens, especificando exatamente o tópico que deseja. No entanto, é muito mais interessante receber informações agrupadas. Por exemplo, para assinar todas as informações de sensores de temperatura da área 10, o seguinte tópico poderia ser usado:

 

 

O “+” tem função de curinga, aceitando qualquer valor naquele nível do tópico. Existe também uma outra notação utilizando o símbolo “#”, que significa “qualquer coisa abaixo de determinado nível do tópico”. Assim, para ter acesso a qualquer valor de sensoriamento dentro da área 20, o tópico seria:

 

 

Independente do sensor e da variável sensoriada, tudo seria recebido.

 

Tópicos que começam com “$” são considerados especiais, sendo geralmente reservados para uso interno do broker. Para o broker Mosquitto, a quantidade de clientes ativos é dada pelo seguinte tópico:

 

 

 

Conexão, segurança e qualidade de serviço

 

A conexão do cliente ao broker, seja ele subscritor ou publicador, é originalmente feita via TCP, com opções de login (usuário e senha) e uso de criptografia (SSL/TLS). É possível encontrar também outros meios físicos, com MQTT rodando em links seriais, por exemplo.

 

Todo processo de conexão estabelece também um nível de qualidade de serviço (QoS, de Quality of Service) desejado, indicando como deve ser a relação entre os elementos comunicantes. São previstos três níveis de qualidade de serviço:

  • QoS 0 (at most once): É o que conhecemos como “best effort”, ou melhor esforço. Assemelha-se ao protocolo de transporte UDP, onde não se tem confirmações de entrega de mensagem. Quem envia também não tem a obrigação de manter a mensagem armazenada para futuras retransmissões;
  • QoS 1 (at least once): Neste nível existe a confirmação de entrega de uma mensagem. Atende situações onde quem envia acaba gerando várias mensagens iguais possivelmente por um atraso na chegada de confirmação de recebimento. Neste caso, é garantido que uma delas terá o reconhecimento realizado. Note que existe um armazenamento da mensagem por parte de quem envia até a posterior confirmação;
  • QoS 2 (exactly once): Garante que a mensagem seja entregue exatamente uma vez, com envio de confirmações de recebimento e confirmações de recebimento de confirmações de recebimento (!). Parece confuso, mas não é, apenas existem confirmações nos dois sentidos, para tudo que é trafegado. Enquanto uma mensagem não é confirmada, ela é mantida. É um caso mais próximo do protocolo de transporte TCP.

 

Não existe um QoS melhor ou pior, isto irá depender de cada cenário de aplicação do MQTT, da qualidade do link de comunicação, dos recursos disponíveis no seu sensor, etc. E, é importante ressaltar, cada nível de QoS é negociado entre o cliente e o broker, não entre o publicador e o subscritor. Assim, é possível ter uma publicação em QoS 0 e uma subscrição em QoS 2, para um mesmo tópico.

 

 

Implementações e exemplos de uso

 

Existem diversas implementações para clientes e brokers MQTT, open source ou não, e para diversas linguagens como Java, C, C#, Javascript e Python. Como exemplo, será usado o broker open source Mosquitto, que pode ser facilmente baixado e instalado para diversos sistemas operacionais e plataformas (Windows, MAC, Linux, Raspberry Pi, OpenWRT, etc). Adicionalmente, para a parte de criptografia do Mosquitto, existe a necessidade de instalação do pacote openssl.

 

No Windows, uma vez que o broker esteja instalado, para um caso simples de uso sem senhas, bastaria executá-lo. O broker usa a porta 1883 e TCP (isto pode ser alterado via arquivo de configuração).

 

Escrever um cliente em python talvez seja a forma mais fácil de testar o MQTT. Para um sistema com python já instalado, o módulo MQTT proveniente do projeto paho pode ser adicionado via pip com o seguinte comando:

 

 

Obs: Para instalar o pip num host Ubuntu ou Windows, execute os seguintes comandos:

 

 

Utilizando os tópicos de temperatura e umidade mencionado antes, podemos criar um pequeno script capaz de se comportar como um sensor dentro da área 10, enviando valores de temperatura e umidade a cada 5 segundos e com um QoS de nível 0.

 

 

Neste publicador, preferiu-se o QoS 0 e os possíveis erros de conexão não foram tratados para que o exemplo não ficasse mais complexo. Nos outros níveis de qualidade de serviço é necessário a chamada de outras funções que avaliam o recebimento de confirmações e gerenciam retransmissões.

 

Note que os dados foram organizados como inteiros de 16 bits no formato big endian, ou seja, o valor mais significativo vem no payload. A função pack e seu argumento “>H” faz esta codificação (“>” para big endian e “H” para inteiro sem sinal de 16 bits). Posteriormente, este valor será decodificado com a função unpack. Para maiores informações, consultar o módulo struct da linguagem.

 

Criar um subscritor capaz de receber todas as mensagens da área 10, por sua vez, pode ser implementado como a seguir:

 

 

Todas as mensagens que chegam e casam com o tópico assinado acabam sendo tratadas pelo método on_message. É possível criar funções diferentes de recepção, separando a recepção dos tópicos. A subscrição dos tópicos deve ser feita após a conexão, algo tratado pela função on_connect. Por fim, via uma chamada loop_forever() do módulo MQTT do paho, o subscritor fica indefinidamente recebendo as mensagens do tópico assinado. Os dois scripts devem rodar sem modificações tanto num PC quanto numa Beaglebone ou Raspberry Pi. Recomenda-se um estudo no módulo MQTT do paho, explorando as demais funcionalidades providas por ele.

 

Existe muito mais a ser explorado do MQTT, como mensagens de testamento, manutenção da conexão com keep alives, sessões persistentes e outros níveis de QoS. Voltaremos nesses tópicos em um artigo posterior. Até lá!

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Marcelo Barros de almeida
Sou engenheiro eletricista com graduação em engenharia elétrica pela Universidade Federal de Itajubá, com ênfase em eletrônica (1996). Mestre (1998) e doutor (2002) em engenharia elétrica pela Universidade Federal de Minas Gerais. Atualmente, sou professor na Universidade Federal de Uberlândia/MG. Também já dei aulas para cursos de informática/computação no Centro Universitário Barão de Mauá e trabalhei por diversos anos como engenheiro de desenvolvimento e também um tempo como gerente de produto.