Manual

do

Maker

.

com

IoT - Configurando um MQTT broker

IoT - Configurando um MQTT broker

Representando uma nova era, a Internet das Coisas tem se apresentado nos mais diversos meios digitais, com novos hardwares menores e mais poderosos a cada dia. Claro que isso tudo necessita de gerenciamento e controle. Para tal, veremos como configurar um servidor MQTT - protocolo da Internet das Coisas.

O que é MQTT

O acrônimo MQTT significa Message Queuing Telemetry Transport; um protocolo criado pela IBM em 1999. Esse protocolo muito leve permite a comunicação bi-direcional (não como o protocolo HTTP, mas a seu modo específico) para coleta de dados e gerenciamento de dispositivos da Internet das Coisas. De modo similar, o gerenciamento de dispositivos complexos é feito com TR-069 e fico meditando a respeito; poderiam esses dispositivos (roteadores, switches, outros equipamentos de telecom) fazer parte do IoT? - Eu responderei de forma simples - uma empresa alemã já tem amplamente implementado e divulgado seu produto IoT junto aos produtos que utilizam TR-069. Ela faz parte da Broadband Forum e acredite, se eles estão apostando em IoT, podemos tomar como uma decisão acertiva introduzir-se nesse fantástico novo mundo.

Como o serviço funciona?

O protocolo utiliza uma arquitetura publish/subscribe, em contraste ao request/response do protocolo web HTTP. Desse modo é possível empurrar mensagens ao client e com uma boa implementação de lógica, fazer um belo gerenciamento dos dispositivos da sua nuvem. Uma outra característica que chama a atenção é a capacidade de buffering que, ainda que haja uma desconexão com o broker por qualquer razão, ao retormar a conexão os clients recebem as informações do tempo de indisponibilidade.

O centralizador, serviço ou server, é chamado MQTT broker - exatamente isso, um intermediário. Ele que recebe e envia mensagens para todos os clients que estabelecerem conexão e todos os dispositivos devidamente permitidos a receber interação.

mqtt-broker-1-300x43.webp

É bastante simples como você pode reparar. O dispositivo publica a informação no MQTT broker. Os clientes se subscrevem no tópico que desejam receber informação e essa consulta pode ser feita através de qualquer tipo de dispositivo que comporte o protocolo de comunicação.

Conexão através de NAT

E essa é uma vantagem da utilização do MQTT, uma vez que o client inicia a conexão, portanto não há problema algum em estar por trás de uma rede com NAT.

Inicio da conexão: CONNECT

Um pacote de conexão MQTT tem vários parâmetros opcionais. Você não precisa se preocupar com esses detalhes para efetuar a configuração, ainda mais que sequer é obrigatório usuário e senha (se assim for permitido pelo broker). Vamos focar nos parâmetros utilizados no post sobre a configuração do client.

ClientID

Trata-se do identificador. Esse identificador não é o que o tema do tópico, isto é, você pode chamá-lo de "ESP_001" e se subscrever no tópico "casa/sala/temperatura". Até um clientID vazio é permitido, mas sugiro a utilização do MAC como identificador.

Username/Password

O protocolo em si não tem criptografia e trafega em texto plano tal qual uma mensagem SIP, por exemplo. Esse humilde exemplo de configuração de broker contempla a configuração do TLS para disponibilizar um canal seguro. De qualquer modo, o caminho mais curto é mesmo sua utilização sem outras implementações e pode ser aceitável desde que utilizado em ambientes não públicos, acesso interno na sua casa ou um laboratório de testes.

O Broker responde com CONNACK

Ao receber a mensagem de CONNECT a resposta obrigatória do Broker é a mensagem de CONNACK, contendo apenas duas entradas de dados; a Session Present Flag e o código de retorno. Esta primeira indica que o Broker já tem uma sessão persistente do cliente com interação prévia. Saber o formato dos pacotes lhe permitirá depurar qualquer problema na comunicação através da camada de rede, utilizando um sniffing sobre um conexão não criptografada. Os códigos de retorno de CONNACK são:

0 - Conexão aceita
1 - Conexão recusada, versão do protocolo inaceitável
2 - Conexão recusada, identificador rejeitado
3 - Conexão recusada, servidor indisponível
4 - Conexão recusada, usuário e/ou senha inválidos
5 - Conexão recusada, não autorizado

Pacote PUBLISH

O formato desse pacote contempla os seguintes campos:

CampoExemplo
topicName"topico/x"
payload"temperature:28.3"
qos1
retain0

topicName

Essa parte me lembrou o roteamento da comunicação com PBX Asterisk (só um comentário, não considere). Ele é a rota da informação com o broker, o caminho ou estrutura a qual está relacionado. Cada client que quiser receber mensagens se subscreve em um determinado tópico e o broker entrega todas as mensagens relacionadas ao tópico solicitado pelo client, desde que ele tenha permissões. Você pode criar um tópico público, onde qualquer dispositivo não autenticado pode estabelecer uma comunicação. E você pode ter os tópicos privados, diretamente relacionados a um usuário, com senha e criptografia no canal de comunicação. Esse post trata de exemplificar todos esses recursos, veremos mais sobre tópicos adiante.

qos

Como qualquer QoS, Quality of Service, com 3 níveis (0, 1 ou 2) afim de garantir a entrega da mensagem ao ponto extremo. Vale lembrar que os tempos de entrega associados ao QoS e outros validadores podem agregar um payload alto. De imediato não posso avaliar pois não mensurei pacotes e processamento, mas certamente em um hardware bem modesto (modesto digo, uma board ARM) pode influenciar, dependendo do número de clients conectados à estrutura.

retainFlag

Determina se a a mensagem deve ser armazenada pelo Broker. Novos clients subescritos receberão instantaneamente a última mensagem retida do tópico ao qual se subescreveu.

CampoExemplo
topic"topico/x"
qos1

Como anteriormente citado, mas dessa vez para o efeito de consulta. Os parâmetros citados aqui não são baseados baseados nem no protocolo nem no Broker, estou focando na comunicação com o ESP8266, cujo post relacionado à comunicação utilizando MQTT pode ser visto aqui.

Clientes não fazem conexão entre sí. Tenha firme em mente que o Broker tem um conceito diferente de um server e é o que mais lembra um serviço em nuvem. Ele é apenas o intermediário entre o dispositivo e o aplicativo de consulta, para que não haja conexão direta entre as pontas e também para que não haja conexão entrante na rede dos dispositivos.

Apesar de deixar explícita sua utilização em nuvem (uma vez que trata-se de gerenciamento remoto), você pode ter um broker configurado em uma rede local dentro de uma empresa, ou até mesmo dentro de sua casa ou comércio. Para isso, sem a necessidade de sair da arquitetura IoT, pois um Raspberry Pi já seria muito mais que o suficiente para ser utilizado como broker.

Isolamento

Um ponto muito interessante é que os clients não precisam tomar ciência da existência de outros dispositivos, de forma que isso implementa um nivel extra de segurança através dessa nuvem, eles somente se comunicam através do tópico relacionado. Essa arquitetura é altamente escalável e independente dos produtores de dados e consumidores de dados.

Formato do tópico

Os tópicos são multi-nivel. Suponhamos que esteja medindo a temperatura da sala. Você pode ter o nivel mestre casa, seguido por sala e então temperatura. O client pode se subescrever para o tópico exato ao qual se deseja registrar dados ou usar um coringa para outro nível. Subescrever-se para casa/+/temperatura enviará a temperatura para todos os tópicos do segundo nível como por exemplo, casa/cozinha/temperatura. Por fim, um coringa multi-nível é a cerquilha (#). Isso permite subescrever-se para todos os níveis hierárquicos; casa/# servirá para todos os níveis contidos após casa.

Por fim, a configuração inclui autenticação e criptografia dos dados e pode ser compilado tanto para seu notebook/desktop como para qualquer board ARM rodando Linux. Iniciemos o processo!

Pacotes iniciais

Primeiramente será necessário instalar algumas ferramentas. Pode variar de caso a caso, dependendo do que você tem (ou não tem) instalado. O broker é leve e pode ser instalado em qualquer placa ARM que rode Linux, ou em qualquer arquitetura tradicional desktop rodando Linux. Se estiver usando Windows, o WSL é uma opção para ter um bash e seguir com o mesmo procedimento descrito aqui.

sudo apt-get install pkg-config cmake openssl libc-ares-dev libssl-dev python-mosquitto

Compilando e instalando

Então os fontes devem ser baixados e a partir daí começa nossa diversão:

wget http://mosquitto.org/files/source/mosquitto-1.3.5.tar.gz
tar xzf mosquitto-1.3.5.tar.gz
cd mosquitto-1.3.5
cmake .
make install

Fácil, hum? Mas calma, tem mais.

mosquitto.conf

Eu havia editado o arquivo original e descomentado linha a linha do que eu queria. Na versão do mosquitto baixada por apt-get você não terá alguns dos novos recursos da versão disponível na publicação desse post, por isso dispense a preguiça e ponha a mão-na-massa. Mas no que se refere ao arquivo, fui preguiçoso e invés de remover apenas as linhas comentadas, copiei um arquivo pronto sem comentários, fazendo apenas ajustes de níveis de diretórios.

Nos comandos a seguir uso vi como editor de texto, mas você pode usar o que quiser, desde que tenha permissões para escrever no destino (Kate no KDE, nano na linha de comando, mcedit, gedit, etc).

ln -s /usr/local/etc/mosquitto /etc/mosquitto
mkdir /etc/mosquitto/certs
vi /etc/mosquitto/mosquitto.conf

E o conteúdo deixei assim:

#nao permitir acesso anonimo
allow_anonymous false       
#...                                                              
autosave_interval 1800                                                                    
#...
connection_messages true                                                                  
#destino das msgs de log. Pode apontar pra quantas quiser, uma por linha
log_dest stderr                                                                           
log_dest topic   
#tipos de erro. Tem mais alguns nessa ultima versao, mas aqui ja me basta                                                                         
log_type error                                                                            
log_type warning                                                                          
log_type notice                                                                           
log_type information                                                                      
log_type debug
#...                                                                            
log_timestamp true
#arquivo de passwd, criado mais adiante                                                                        
password_file /etc/mosquitto/jp.pw     
#arquivo de acl, descrito e criado mais adiante                                                   
acl_file /etc/mosquitto/jp.acl                 
#para gravar os dados em disco                                         
persistence true
#destino da base de dados.                                                                        
persistence_location /opt/mosquitto/mosquitto_db
#nome para o arquivo de persistencia de dados                                                              
persistence_file mosquitto.db                
#tempo para descarregar da memoria para o disco                                             
persistent_client_expiration 1m  
#um sinonimo de persistence, nao precisa dessa repeticao                                                         
retained_persistence true                                                                 
#abre 1883 em localhost, apenas IPv4
listener 1883 127.0.0.1
#abre em todas as interfaces na 8883, IPv4 e IPv6 (e pode ter mais)
listener 8883
#certificados criados adiante
#tls_version tlsv1
#cafile /etc/mosquitto/certs/ca.crt
#certfile /etc/mosquitto/certs/server.crt
#keyfile /etc/mosquitto/certs/server.key
require_certificate false

Esses são apenas alguns dos muitos parâmetros disponíveis, você pode contemplá-los (e incluí-los se desejar) chamando a página de manual:

man mosquitto.conf

Gerar certificados

Agora é hora de gerar certificados. Continua sendo tão simples quanto os procedimentos anteriores. PORÉM, não consegui utilizá-lo ainda. Como no primeiro momento é fundamental que não se utilize a criptografia no canal de dados para que o sniffing seja possível e assim possa ser depurado qualquer problema na camada de rede, não fiz questão de configurar o certificado agora, mas vou fazer, prometo. Só estou ansioso em publicar esse post!

mkdir -p /etc/mosquitto/certs
cd /etc/mosquitto/certs
openssl req -new -x509 -days 1000 -extensions v3_ca -keyout ca.key -out ca.crt

Coloque a senha que quiser. Um exemplo do processo:

openssl req -new -x509 -days 1000 -extensions v3_ca -keyout ca.key -out ca.crtGenerating a 2048 bit RSA private key
.................+++
.....................+++
writing new private key to 'ca.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:BR
State or Province Name (full name) [Some-State]:Sao Paulo
Locality Name (eg, city) []:Sao Paulo
Organization Name (eg, company) [Internet Widgits Pty Ltd]:KGB
Organizational Unit Name (eg, section) []:Matriz
Common Name (e.g. server FQDN or YOUR name) []:dobitaobyte
Email Address []:djames.suhanko@gmail.com

...e mais

openssl genrsa -des3 -out server.key 2048
openssl genrsa -out server.key 2048
openssl req -out server.csr -key server.key -new
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 1000

Crie o usuário mosquitto (que será o proprietário do processo) apontando /bin/false como shell padrão.

adduser mosquitto --shell /bin/false

Siga todos os ritos e em seguida crie o usuário client:

touch /etc/mosquitto/jp.pw
mosquitto_passwd /etc/mosquitto/jp.pw dobitaobyte

Solicitará senha. Pra tudo eu utilizei a mesma.

Se desejar deletar o usuário, use

mosquitto_passwd -D /etc/mosquitto/jp.pw dobitaobyte

A senha criada é semelhante ao conteúdo do shadow (se você não sabe o que é, não se importe. Foi apenas um comentário).

Minha primeira ACL

Vamos começar água com açucar; estou ancioso para ver o serviço em execução. Crie um arquivo em /etc/mosquitto/jp.acl para as ACLs e digite o seguinte:

# Acesso anonimo (bloqueado no mosquitto.conf, soh exemplo aqui)
topic read $SYS/#
topic test/#

user dobitaobyte
topic write casa/#
topic read  casa/#
topic write /mcu/#
topic read  /mcu/#


MQTT Client - MyMQTT

myMQTT-1-300x156.webp

Se você vai iniciar uma configuração do zero, acredite, fazer os dois pontos de uma vez pode representar o caos. Inicie pelo Broker sem SSL associado ao uso de um aplicativo para testes. Eu recomendo o MyMQTT que funcionou de primeira sem nenhum problema. Baixe-o no google Play, podendo ser acessado através desse link (instalando pelo notebook/desktop o aplicativo será enviado para seu smartphone).

Mensagens no stdout

Devido ao nível de verbosidade, se tiver algum erro em sua configuração será possível vê-lo em stdout. Nesse momento já podemos iniciar o serviço e em seguida ver a comunicação com o dispositivo (nesse teste, o NodeMCU):

KGB mosquitto # mosquitto -v -c /etc/mosquitto/mosquitto.conf
1449517780: mosquitto version 1.4.5 (build date 2015-12-05 12:29:10-0200) starting
1449517780: Config loaded from /etc/mosquitto/mosquitto.conf.
1449517780: Opening ipv4 listen socket on port 1883.
1449517780: Opening ipv4 listen socket on port 8883.
1449517780: Opening ipv6 listen socket on port 8883.
1449517815: New connection from 192.168.1.234 on port 8883.
1449550319: New client connected from 192.168.1.232 as root.1449550319072 (c1, k60, u'dobitaobyte').
1449550319: Sending CONNACK to root.1449550319072 (0, 0)
1449550319: Received SUBSCRIBE from root.1449550319072
1449550319:     casa/# (QoS 1)
1449550319: root.1449550319072 1 casa/#
1449550319: Sending SUBACK to root.1449550319072
1449550335: Received PUBLISH from root.1449550319072 (d0, q0, r0, m0, 'casa/cozinha', ... (4 bytes))
1449550335: Sending PUBLISH to root.1449550319072 (d0, q0, r0, m0, 'casa/cozinha', ... (4 bytes))
...

O broker cria uma base de dados descarregada em determinada periodicidade para o disco (veja lá em cima, na seção mosquitto.conf). Não se preocupe com o conteúdo, porque o gerenciamento é feito pelo broker, mas se desejar fazer backup, creio que essa seja a espinha dorsal. Se quiser fazer a persistência de outro modo como Redis ou uma base de dados MySQL etc, você pode configurar esse plugin de autenticação para Mosquitto.

Nos exemplos contidos dentro do diretório de fontes você encontra um mysql_log e um temperature_conversion. Se desejar compilar, não se esqueça de instalar o pacote libmysqld-dev; edite o arquivo mysql_log.c e configure adequadamente os parâmetros para uma base de dados, mudando os defines. Talvez eu faça outro post mostrando a configuração de alguns tipos de persistência, caso eu perceba que esse post foi bem recebido pela comunidade.

Inscreva-se no nosso canal Manual do Maker Brasil no YouTube.

Próximo post a caminho!

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.