IoT DevKit - 12. Envio de Dados por MQTT




Introdução

No tutorial anterior aprendemos os conceitos básicos de um rede Wi-Fi e tivemos o nosso primeiro contato com ela, requisitando informações simples do ESP32. Entretanto, não chegamos a nos conectar à nenhuma rede, portanto não chegamos a desenvolver um projeto IoT propriamente dito.

Neste tutorial vamos nos conectar à uma rede Wi-Fi e enviar as leituras de temperatura e umidade do sensor DHT11 para a PROIoT utilizando o protocolo MQTT.

Lista de Materiais

O Que é MQTT?

MQTT é uma sigla para "MQ Telemetry Transport" (Transporte de Telemetria MQ), que foi desenvolvida inicialmente para a série MQ ("Message Queue" - Fila/Lista de Mensagens) de aparelhos da IBM. Este protocolo é baseado na pilha TCP/IP e se tornou famoso por consumir uma baixíssima banda de rede e exigir pouco esforço do seu hardware de controle.

Este protocolo trabalha com tópicos, que são basicamente os diretórios por onde as informações serão enviadas ou recebidas. Esses tópicos são gerenciados por um Broker, que nada mais é do que o servidor de comunicação do protocolo. O Broker também é responsável por gerenciar as conexões com os Publishers e com os Subscribers. Os Publishers são os dispositivos que enviam informações para o Broker através de mensagens do tipo "PUBLISH". Já os Subscribers são os dispositivo que recebem informações de um determinado tópico, e eles se inscrevem neste determinado tópico através de mensagens do tipo "SUBSCRIBE".

A imagem a seguir ilustra um exemplo desta comunicação, onde um sensor de temperatura atua como um Publisher enviando as suas leituras para o Broker. O celular e o computador neste exemplo são os Subscribers da comunicação, pois eles se inscrevem ao tópico "temperature" para receber as leituras do sensor, publicadas no mesmo tópico.

exemplo-comunicacao-mqtt
Exemplo de Comunicação MQTT
Fonte: Medium

Configuração da Plataforma

Para este projeto não vamos mais utilizar o plano ATC LoRaWAN, porém continuaremos a utilizar o plano gratuito da própria PROIoT. Embora esse plano garanta uma quantidade consideravelmente grande de "Uplinks" e "Downlinks" para dispositivos MQTT, ainda é necessário tomar cuidado com a frequência de mensagens para não esgotar a quantidade disponível antes do final do mês.

Como vamos trabalhar com um protocolo diferente, temos que criar e configurar um dispositivo novo na PROIoT.

Criação do Dispositivo

Primeiramente, acesse a seção "Dispositivos" da plataforma e pressione o botão "+ Dispositivo". Ao pressionar esse botão, será exibida uma janela de configuração do novo dispositivo, pedindo para que você selecione a tecnologia usada. Como vamos trabalhar com o protocolo MQTT, selecione esta opção, como na imagem a seguir.

selecao-tecnologia-dispositivo
Seleção da Tecnologia do Dispositivo

Após a seleção da tecnologia, selecione a opção "Custom Device" na lista "Modelo" da plataforma, como na próxima imagem, já que o ESP32 não está nesta lista.

selecao-modelo-dispositivo
Seleção do Modelo do Dispositivo

A plataforma deve passar diretamente pela seleção "Conectividade", pois só há uma opção disponível para a tecnologia MQTT, portanto ela já está pré selecionada. Por fim, digite um nome para o seu dispositivo, que será o mesmo que o seu rótulo, como na imagem abaixo.

nome-rotulo-dispositivo
Nome e Rótulo do Dispositivo

Com este código gerado, pressione o botão de confirmação verde para que o dispositivo seja criado. Feito isso, será possível observar o dispositivo na lista de dispositivos, como na imagem a seguir.

dispositivo-criado
Dispositivo Criado

Criação do Token API

Agora vamos obter dois códigos que serão extremamente importantes para que nos conectemos ao servidor. O primeiro deles é o "ID Único" do dispositivo, que é gerado automaticamente pela plataforma na criação do mesmo. Para obter ele, temos que acessar o nosso dispositivo, pois ele se encontra na área "Chaves do dispositivo", como na imagem a seguir.

id-unico-dispositivo
ID Único do Dispositivo

Esta é uma das informações que vamos utilizar no código para que possamos nos conectar ao servidor, portanto anote-a e guarde-a.

Em seguida, temos que gerar um "Token API" para nossa aplicação, e para isso selecione o ícone de chave ao lado da "Loja" no canto superior direito da janela. Ao clicar sobre esse botão, será exibida uma janela informando os tokens do seu cadastro, como na imagem abaixo.

janela-resumo-tokens
Janela de Resumo dos Tokens

Com essa janela aberta, selecione a opção "Ir para Tokens" para que possamos criar um. Ao selecionar essa opção, você será direcionado para a seguinte página.

pagina-criacao-tokens
Página de Criação de Tokens

Nesta página, clique sobre o botão "+ Adicionar" na seção "Organização" (o segundo botão da página), e então digite um nome para o seu Token, como na imagem a seguir.

token-configurado
Token Configurado

Feito isso, pressione o botão de confirmação verde, assim a plataforma irá gerar automaticamente um código que será utilizado como o nosso Token API. Assim que o código estiver gerado, anote-o e guarde-o, pois iremos usá-lo posteriormente.

Criação de Variáveis

Agora que o dispositivo está criado, acesse a seção "Opções de Payload", como na primeira imagem abaixo, e certifique-se que a opção "Formato de Payload" está corretamente pré configurada como "JSON", como na segunda imagem abaixo. Caso contrário, selecione essa opção.

caminho-secao=opcoes-payload
Caminho para Seção "Opções de Payload"
payload-configurado-json
Payload Configurado como "JSON"

Feito isso, podemos criar e configurar as variáveis que vão receber as mensagens do nosso dispositivo. Para isso, acesse a seção "Variáveis" dentro do seu dispositivo e pressione o botão "+ Variável", para que a plataforma apresente uma janela de edição como a da próxima imagem.

criacao-variavel
Criação da Variável

Com essa janela aberta, dê um nome para a sua variável, digite "°C" no campo "Unidade", defina a quantidade de pontos decimais para "1", e garanta que o campo "Dividir valor por" está como "1", caso contrário o valor enviado será dividido pelo valor deste campo antes de ser exibido. Além disso, digite "Temperatura" no campo "Alias" (este é o nome que está pré configurado no código deste tutorial, porém você pode digitar outros nome de desejar, apenas lembre-se de alterar este parâmetro no código também) para que a sua variável fique configurada como a da imagem abaixo.

variavel-temperatura-configurada
Variável "Temperatura" Configurada

Feito isso, pressione o botão de confirmação verde e, como vamos enviar os valores temperatura e umidade relativa do ar lidos pelo DHT11, temos que criar outra variável para a umidade, portanto repita o processo feito anteriormente. Entretanto, digite "%" no campo "Unidade" e, no campo "Alias", digite o nome "Umidade" (o mesmo vale para esta variável, "Umidade" é o nome pré configurado no código, porém você pode escrever outro se desejar), para que sua variável fique configurada como a da imagem a seguir

variavel-umidade-configurada
Variável "Umidade" Configurada

Após a configuração desta variável, pressione o botão de confirmação verde para observar ambas as variáveis na lista do dispositivo.

Configuração do Painel

Para não invadirmos o ambiente criado anteriormente para o protocolo LoRaWAN, vamos criar um segundo painel. Para isso, expanda a lista de painéis da sua conta, clicando sobre símbolo de menu contido ao lado do nome do seu painel, demarcado na imagem abaixo.

simbolo-acesso-lista-paineis
Símbolo de Acesso à Lista de Painéis

Ao clicar sobre esse símbolo, será aberta uma janela listando todos os painéis da sua conta, como na imagem a seguir.

lista-paineis-disponiveis
Lista de Painéis Disponíveis

Com esta janela aberta, pressione o botão "+ Adicionar painel", assim será aberta uma aba para a configuração do novo painel, então basta digitar um nome para ele, como na próxima imagem.

novo-painel-configurado
Novo Painel Configurado

Feito isso, pressione o botão de confirmação verde para que o painel seja criado em branco, e então basta dar um clique duplo sobre este painel para acessá-lo. Clique sobre o botão "+ Widget" e selecione a opção gráfico de linhas, como na imagem abaixo.

widget-grafico-linhas-selecionado
"Widget" "Gráfico de Linhas" Selecionado

Após selecionar esta opção, será aberta a janela de configuração do "Widget". Neste momento selecione a sua a sua "Organização", a sua "Aplicação", o dispositivo e as duas variáveis criadas anteriormente. Feito isso, dê um nome para o seu "Widget" e altere as cores de exibição das variáveis se desejar, para que ele fique configurado como na imagem a seguir.

widget-configurado
"Widget" Configurado

Com a configuração completa, pressione o botão de confirmação verde para que o "Widget" seja adicionado ao painel recém criado, como na imagem a seguir.

wdiget-criado
"Widget" Criado

Software

Biblioteca

Agora que a plataforma está configurada, podemos prosseguir com o projeto. Porém, antes de carregarmos o código para a placa, precisamos instalar a biblioteca "PubSubClient" que nos ajudará a realizar as publicações MQTT. Para isso, acesse o "Gerenciador de Bibliotecas" seguindo o caminho que mostramos em tutoriais anteriores, então digite "pubsubclient" no campo de pesquisa e pressione "Enter". A biblioteca não deve ser apresentada na primeira posição da lista, porém basta rolar a lista um pouco para baixo para encontrar a biblioteca desenvolvida por "Nick O'Leary", como demarcado na imagem a seguir.

biblioteca-pubsubclient-encontrada
Biblioteca "PubSubClient" Encontrada

Com a biblioteca correta encontrada, pressione o botão "Instalar" e aguarde alguns instantes. Quando a biblioteca estiver instalada, será apresentada a etiqueta "Instalada" ao lado do nome dela, como na imagem abaixo.

biblioteca-instalada
Biblioteca Instalada

Código

Com a biblioteca instalada, copie o código a seguir para a sua Arduino IDE e carregue-o para a placa. Apenas lembre-se de alterar as variáveis que armazenam o nome e a senha da sua rede Wi-Fi (REDE e SENHA respectivamente), juntamente com o ID único do seu dispositivo (ID_DISPOSITIVO) e o Token API (TOKEN_API), que foram gerados pela plataforma.

Entendendo o Código

Começamos o código verificando se o modelo de placa está corretamente selecionado na IDE e incluindo as bibliotecas que nos ajudarão a conectar o ESP32 à rede Wi-Fi, a enviar mensagens por MQTT, a realizar a leitura do sensor DHT e a converter essas leituras em mensagens JSON. Em seguida declaramos as variáveis REDE e SENHA, que como os próprios nomes já dizem, armazenam o nome e a senha da sua rede Wi-Fi, respectivamente.

Após a declaração dos parâmetros da rede Wi-Fi, nós criamos o objeto cliente para a biblioteca "WiFiClient" do ESP32, que também é utilizado pelo objeto MQTT criado da biblioteca "PubSubClient". Feito isso, criamos as variáveis SERVIDOR e PORTA, que armazenam o endereço do servidor e sua respectiva porta. Além dos dois, definimos as variáveis que armazenam o ID único do dispositivo criado (ID_DISPOSITIVO), o Token API gerado pela plataforma (TOKEN_API) e a senha de conexão (SENHA_ID), que nos ajudarão a nos conectar ao servidor da PROIoT. Esta última variável é vazia, pois não é necessária uma senha para estabelecer a conexão, entretanto é necessária uma variável para a função que realiza a conexão.

O Token API é utilizado neste código como o nome do usuário na conexão do protocolo, pois este é um requisito da PROIoT. Mas vale lembrar que outras plataformas podem exigir outras informações para estabelecer essa conexão.

Ainda nas declarações globais do código, declaramos as variáveis que armazenam os Aliases das variáveis configuradas na plataforma (ALIAS1 e ALIAS2), juntamente com a variável TOPICO, que será concatenada posteriormente, para armazenar o tópico em que publicaremos as leituras do sensor. Aproveitando a menção do sensor, nós criamos para ele a variável PINO_DHT, que armazena o pino do ESP32 no qual ele está conectado, e então utilizamos esta variável para criar o objeto dht a partir da biblioteca "DHT", juntamente com o modelo do sensor utilizado (o sensor de fábrica do IoT DevKit é o DHT11). Em seguida, declaramos as variáveis temperatura, umidade e ESPERA, que serão responsáveis por armazenar a leitura de temperatura e umidade do sensor, e o intervalo de tempo entre mensagens do código, respectivamente. Por fim, temos a declaração das variáveis reconecta, que é responsável por executar o intervalo de espera entre tentativas de conexão com o servidor, e INTERVALO, que ajudará a variável espera a realizar o intervalo de espera de 20 minutos (1200000 milissegundos).

Já nas configurações do código, iniciamos o monitor serial com a velocidade de 115200 bps, o sensor DHT através da função dht.begin() e a conectividade Wi-Fi da placa de acordo com o nome e a senha da rede Wi-Fi configurados anteriormente, por meio do comando WiFi.begin(REDE,SENHA). Em seguida verificamos se a placa se conectou efetivamente à rede através da condição while(WiFi.status() != WL_CONNECTED) e, enquanto ela não estiver conectada, exibimos no monitor serial alguns pontos ("."). Assim que a conexão estiver estabelecida, exibimos no monitor serial o endereço IP da placa, que é obtido com a função WiFi.localIP(). Em seguida, configuramos o servidor da PROIoT para o objeto MQTT através do comando MQTT.setServer(SERVIDOR,PORTA).

Para finalizar as configurações do código, nós concatenamos a variável TOPICO com a variável ID_DISPOSITIVO utilizando o comando strcat(TOPICO,ID_DISPOSITIVO).

Mas afinal, o que é concatenação? Para que isso serve? Concatenação é a junção de strings. Ou seja, utilizando o nosso código como exemplo, a string "5f3ec0664315e000189749a9" (valor armazenado na variável ID_DISPOSITIVO) é somada à string "device/" (declarada na variável TOPICO), resultando em um única string composta pelos dois elementos, "device/5f3ec0664315e000189749a9". Assim não precisamos criar duas variáveis que contenham a mesma informação no código.

Finalmente na repetição do código, utilizamos o comando MQTT.loop() para manter a conexão ativa com o servidor. Em seguida, através da condição if(!MQTT.connected()), verificamos se a placa está efetivamente conectada ao servidor. Se a placa não estiver conectada ao servidor, comparamos se a variável reconecta é menor que a contagem de milissegundos da placa. Se for, nós requisitamos a conexão com o servidor de acordo com os parâmetros ID_DISPOSITIVO, TOKEN_API e SENHA_ID que foram declarados anteriormente, utilizando o comando if(!MQTT.connect(ID_DISPOSITIVO, TOKEN_API, SENHA_ID)), que também verifica se a conexão foi realizada com sucesso ou não. Deste modo, se a conexão não foi estabelecida, informamos isso no monitor serial e então tentamos nos reconectar após 5 segundos, graças ao comando reconecta = millis() + 5000, que atualiza a contagem de tempo da variável reconecta.

Entretanto, caso o ESP32 esteja conectado ao servidor, iniciamos a lógica de envio da mensagem, armazenando a leitura do sensor nas variáveis temperatura e umidade através dos comandos temperatura = dht.readTemperature() e umidade = dht.readHumidity(). Feito isso, verificamos se a leitura do sensor foi feita corretamente utilizando a condição if (isnan(umidade) || isnan(temperatura)), caso contrário exibimos uma informação de erro no monitor serial. Assim que a leitura for verificada corretamente, iniciamos o processo de conversão dos valores para mensagens JSON com a criação do objeto json, com o tamanho "2" (JSON_OBJECT_SIZE(2)) para a classe DynamicJsonDocument da biblioteca "ArduinoJson". Então criamos dois elementos, um com o nome ALIAS1 e outro com o nome ALIAS2, que recebem os valores das variáveis temperatura e umidade, respectivamente.

Depois nós criamos a variável tamanho_mensagem, que é atribuída à soma unitária do comprimento da mensagem JSON do objeto json. Essa adição é necessária para inserir o caractere de final de texto ('\0') na conversão a seguir. Logo após, criamos a string mensagem de acordo com o tamanho tamanho_mensagem, que será responsável por armazenar a mensagem JSON para o envio. Após esta criação, nós realizamos uma cópia do objeto json para a variável mensagem de acordo com o comprimento tamanho_mensagem, através da função serializeJson() da biblioteca "ArduinoJson". Por fim, finalmente publicamos a mensagem em formato de texto para o tópico armazenado na variável TOPICO utilizando o comando MQTT.publish(TOPICO, mensagem). Com a mensagem enviada, atualizamos a contagem de tempo da variável espera, igualando ela à soma da contagem de milissegundos da placa (millis()) com a variável INTERVALO.

O Que Deve Acontecer

Após carregar o código para a placa, abra o monitor serial com a velocidade de 115200 bps, assim você terá um resultado como o da imagem abaixo.

resultado-monitor-serial
Resultado do Monitor Serial

Juntamente com essa mensagem no monitor serial, será possível observar a atualização do "Widget" configurado anteriormente e, após algum tempo de funcionamento do projeto, ele ficará parecido com o da próxima imagem.

painel-atualizado
Painel Atualizado

Conclusão

Neste tutorial vimos como enviar mensagens para a PROIoT utilizando a conectividade Wi-Fi e o protocolo MQTT. Agora podemos prosseguir com nossos estudos e aprender a receber mensagens da plataforma através deste método.

Solução de Problemas

Se mesmo seguindo as soluções propostas abaixo você não conseguir solucionar o seu problema, encaminhe um e-mail para suporte@robocore.net para que possamos te ajudar da melhor maneira possível.

Arduino IDE Retornou a Mensagem "#error Use this example with the ESP32"

Como vimos anteriormente, esta é uma mensagem personalizada que criamos no início do código para quando o modelo de placa selecionado não está corretamente selecionado, portanto certifique-se que o modelo da placa nas "Ferramentas" da IDE está como "ESP32 Dev Module".

Monitor Serial Apresenta Pontos Infinitamente e Não se Conecta

Se isso acontecer, verifique as variáveis REDE e SENHA do código carregado, pois é possível que elas não estejam exatamente iguais aos parâmetros configurados no roteador. Além disso, certifique-se que tanto a rede quanto a senha não possuem caracteres especiais, como acentos, pois o ESP32 não deve estar os interpretando corretamente.

Monitor Serial Apresentou a Mensagem "Falha na conexao com o servidor."

Se esta mensagem for exibida no monitor serial, verifique as variáveis ID_DISPOSITIVO e TOKEN_API, pois é possível que elas não sejam exatamente iguais aos parâmetros gerados na plataforma. Além disso, verifique se o seu dispositivo está com a opção "Conectado" selecionada na plataforma, como na imagem abaixo. Se não estiver selecionado, selecione esta opção e observe o resultado ao tentar novamente.

dispositivo-conectado
Dispositivo Conectado

Valor Atualizado na Plataforma Não é Igual ao Enviado pelo ESP32

Caso a mensagem exibida pelo monitor serial seja diferente dos valores que foram atualizados na plataforma, verifique se o campo "Formato de payload", na seção "Opções de payload" do dispositivo, está corretamente selecionado para "JSON" como na imagem a seguir.

payload-configurado-json
"Payload" Configurado como "JSON"
Avatar