O ESP32, SoC mais recente da Espressif Systems, se consolidou no mercado maker como uma das principais escolhas para aqueles que querem fazer protótipos ou projetos com conectividade, bons recursos computacionais (processamento e memórias) e baixo preço. Ainda, o ESP32 pode ser programado com a Arduino IDE, o que facilita a vida das pessoas já habituadas ao Arduino, tornando seu aprendizado e uso muito mais simples e rápido.

 

Por possuir conectividade à Internet, o ESP32 se torna apto a utilizar os mais diversos protocolos de comunicação utilizados em Internet das Coisas, dentre eles o MQTT. O MQTT é, em sua essência, um protocolo de comunicação M2M (Machine-to-Machine) de simples concepção, leve em termos de poder computacional exigido e uso de Internet exigido e facilmente utilizável nas linguagens de programação mais requeridas no mercado (dentre elas: C, C++, Java, Python e JavaScript). Sua versatilidade, baixa exigência de recursos computacionais e baixos requisitos de banda de Internet o fizeram um dos principais protocolos de comunicação com as maiores plataformas IoT do mercado.

Dada a importância do MQTT e a popularidade do ESP32, este artigo juntará estes dois mundos: aqui, você aprenderá como utilizar comunicação MQTT (envio e recepção de informações) no ESP32.

 

Material necessário

Para realizar a comunicação MQTT aqui proposta, você precisará apenas de um ESP32 e um cabo micro-USB para programação e alimentação. Pode-se utilizar qualquer placa que possua um ESP32, dentre elas a ESP32 Devkit 1 (uma das mais acessíveis do mercado neste quesito), mostrada na figura 1.

 

 

ESP32 Devkit 1 (fonte da imagem: https://www.filipeflop.com/produto/modulo-wifi-esp32-bluetooth/ )
ESP32 Devkit 1 (fonte da imagem: https://www.filipeflop.com/produto/modulo-wifi-esp32-bluetooth/ )

 

 

Ainda, como utilizaremos a Arduino IDE para programar o ESP32, é necessário a ter instalada em seu computador. Recomendo a instalação da versão mais recente da Arduino IDE para seu sistema operacional (Windows, Linux ou Mac OS X). Para fazer o download, acesse o link https://www.arduino.cc/en/Main/Software  .

 

MQTT - informações gerais

O MQTT (Message Queue Telemetry Transport) é em um protocolo de mensagens leve / light-weight criado em 1999. Seu objetivo original era ser um protocolo adequado para comunicação entre máquinas / dispositivos em rede (tanto local como Internet), ou seja, M2M (acrônimo para Machine-to-Machine). Pelo fato de não utilizar alto poder computacional (processamento e uso de memória RAM), assim como não utilizar alta banda de Internet, o MQTT é um dos protocolos mais adequados atualmente para comunicação M2M e telemetria em dispositivos embarcados de forma geral. Justamente por isso, o MQTT é popular em se tratando de Internet das Coisas.

Simplificadamente, uma comunicação MQTT é composta das seguintes partes:

 

Publishers: o(s) dispositivo(s) que irá (irão) disponibilizar informações.

Subscribers: o(s) dispositivo(s) que irá (irão) receber as informações.

Broker: este é o servidor da comunicação MQTT. Ele fica “na nuvem” (em um servidor na Internet, acessível de qualquer lugar do mundo desde que haja conexão com à Internet). Teoricamente, não há limites máximo e mínimo especificados de subscribers e publishers em uma mesma comunicação MQTT, portanto a escalabilidade de uma comunicação MQTT pode ser altíssima.

Há brokers pagos e grátis sendo os grátis referidos como brokers públicos. O seguinte site fornece uma lista de brokers públicos para uso geral: https://github.com/mqtt/mqtt.github.io/wiki/public_brokers 

 

IMPORTANTE: apesar da distinção entre publisher e subscriber, um mesmo dispositivo pode, de forma simultânea, publicar (fazer publish) em N tópicos diferentes e se subscrever (ser subscriber) em X tópicos distintos. Ou seja, um mesmo dispositivo pode ser publisher e subscriber, o que significa que todos podem enviar e receber informações.

 

Dizendo em outras palavras: os dispositivos publishers enviam informações para o Broker. Por sua vez, os dispositivos subscribers recebem tais informações do Broker e ele gerencia a troca de mensagens. Ou seja, o “trabalho pesado” de sincronizar o envio e recebimento fica sob inteira responsabilidade do Broker, o que faz com que os sistemas embarcados (publishers e subscribers) fiquem livre para gerenciar outras coisas, inclusive entrar em sleep ou deep sleep mode. Então, além de utilizar poucos recursos computacionais, pode-se afirmar que o MQTT leva a uma redução de consumo energético (se comparado a alguns outros protocolos de comunicação, como o HTTP, por exemplo).

Observe o diagrama da comunicação MQTT mostrado na figura 2.

 

 

Figura 2 - diagrama de comunicação MQTT (fonte: https://www.filipeflop.com/blog/controle-monitoramento-iot-nodemcu-e-mqtt/)
Figura 2 - diagrama de comunicação MQTT (fonte: https://www.filipeflop.com/blog/controle-monitoramento-iot-nodemcu-e-mqtt/)

 

Sem entrar no mérito da especificação oficial do protocolo MQTT, uma mensagem MQTT publicada / enviada possui duas partes muito importantes:

 

Tópico: “chave” / identificação da informação publicada. É usado para direcionar a informação publicada / enviada a quem assina (quem “dá subscribe”) no tópico, permitindo ao broker MQTT gerenciar esta entrega de mensagens. O tópico consiste de uma string (por exemplo: MQTTTesteTopico)

 

Payload: informação que deseja enviar (propriamente dita).

Um publisher, conectado ao Broker (servidor MQTT) , envia / publica as informações em um dado momento. Os subscribers, assim como os publishers, também estão conectados aos brokers e “escutando” mensagens trafegadas com o tópico-alvo. Quando uma mensagem com o tópico alvo é publicada, automaticamente são direcionadas aos subscribers.

 

Em outras palavras: uma solução em Internet das Coisas que usa MQTT possui somente um servidor (Broker), sendo todo o restante composto de clients MQTT. Isto é uma característica muito positiva, uma vez que dessa forma o servidor não precisa conhecer (e nem ter acesso direto) às redes em que os clientes MQTT estão conectados. Dessa forma, não há necessidade da infraestrutura de rede dos clientes MQTT ser reconfigurada para redirecionar portas e nem liberar acessos aos IPs dos clientes, por exemplo.

Em termos de portas de comunicação MQTT, tipicamente há duas opções:

 

Porta 1883: conexão com broker MQTT sem encriptação. Por razões de segurança, é recomendado o uso de MQTT com conexão não encriptada somente para testes rápidos, protótipos e afins, nunca em produtos finais.

Porta 8883: conexão com broker MQTT com encriptação (usando TLS/SSL).

 

O uso de encriptação na conexão MQTT é algo não tão simples de se fazer e foge do escopo deste livro. Portanto, para fins didáticos, os exemplos do livro utilizarão conexão com broker sem encriptação (porta 1883) somente.

 

Instalação da biblioteca para comunicação MQTT

Agora chegou a hora de instalarmos a biblioteca PubSubClient, biblioteca na qual permitirá com que o módulo WiFi LoRa 32(V2) se comunique com a Internet utilizando o protocolo MQTT. Tal biblioteca é open-source, podendo ser obtida gratuitamente em: https://github.com/knolleary/pubsubclient 

Para instalar esta biblioteca, vamos seguir o procedimento abaixo:

 

1. Acesse o repositório da biblioteca ( https://github.com/knolleary/pubsubclient ) e baixe-a clicando em “Clone or Download” e depois em “Download ZIP” , conforme mostra a figura 3.

 

 

Figura 3 - Obtenção da biblioteca PubSubClient diretamente do repositório oficial
Figura 3 - Obtenção da biblioteca PubSubClient diretamente do repositório oficial

 

 

Guarde o arquivo ZIP baixado em uma pasta conhecida e de fácil acesso para você

 

2. Agora, na Arduino IDE, vamos instalar a biblioteca que acabamos de baixar. Para isso, vamos clicar no menu “Sketch”, depois em “Incluir Biblioteca” e, por fim, clicar em “Adicionar biblioteca .ZIP”, conforme a figura 4.

 

 

Figura 4 - caminho para inclusão de biblioteca Arduino em formato de arquivo compactado
Figura 4 - caminho para inclusão de biblioteca Arduino em formato de arquivo compactado

 

 

3. Na janela que abrir, procure pelo arquivo da biblioteca que você baixou (conforme passo 1 deste procedimento) e clique em “Abrir”.

Desta forma, concluímos a instalação da biblioteca PubSubClient!

 

Tópicos MQTT para este exemplo

No exemplo deste artigo, usaremos dois tópicos MQTT: um para enviar informações do ESP32 para o broker MQTT e outro para receber informações do broker MQTT no ESP32. Veja estes tópicos na tabela 1.

Tópico

Fluxo de informação

INCB_ESP32_envia_informacao

ESP32 -> broker MQTT

INCB_ESP32_recebe_informacao

Broker MQTT -> ESP32

Tabela 1 - tópicos MQTT utilizados no exemplo 

 

Código-fonte

O código-fonte deste exemplo está a seguir. IMPORTANTE: para total compreensão, leia atentamente aos comentários contidos no código-fonte. 

 

//Programa: comunicação MQTT com ESP32
//Autor: Pedro Bertoleti
 
/* Headers */ 
#include <WiFi.h> /* Header para uso das funcionalidades de wi-fi do ESP32 */
#include <PubSubClient.h>  /*  Header para uso da biblioteca PubSubClient */
 
/* Defines do MQTT */
/* IMPORTANTE: recomendamos fortemente alterar os nomes
               desses tópicos. Caso contrário, há grandes
               chances de você enviar e receber mensagens de um ESP32
               de outra pessoa.
*/
/* Tópico MQTT para recepção de informações do broker MQTT para ESP32 */
#define TOPICO_SUBSCRIBE "INCB_ESP32_recebe_informacao"   
/* Tópico MQTT para envio de informações do ESP32 para broker MQTT */
#define TOPICO_PUBLISH   "INCB_ESP32_envia_informacao"  
/* id mqtt (para identificação de sessão) */
/* IMPORTANTE: este deve ser único no broker (ou seja, 
               se um client MQTT tentar entrar com o mesmo 
               id de outro já conectado ao broker, o broker 
               irá fechar a conexão de um deles).
*/
#define ID_MQTT  "INCB_Cliente_MQTT"     
/*  Variáveis e constantes globais */
/* SSID / nome da rede WI-FI que deseja se conectar */
const char* SSID = "SSID"; 
/*  Senha da rede WI-FI que deseja se conectar */
const char* PASSWORD = "SENHA"; 
  
/* URL do broker MQTT que deseja utilizar */
const char* BROKER_MQTT = "broker.hivemq.com"; 
/* Porta do Broker MQTT */
int BROKER_PORT = 1883;
 
 
/* Variáveis e objetos globais */
WiFiClient espClient;
PubSubClient MQTT(espClient);
  
//Prototypes
void init_serial(void);
void init_wifi(void);
void init_mqtt(void);
void reconnect_wifi(void); 
void mqtt_callback(char* topic, byte* payload, unsigned int length);
void verifica_conexoes_wifi_mqtt(void);
 
/* 
 *  Implementações das funções
 */
void setup() 
{
    init_serial();
    init_wifi();
    init_mqtt();
}
  
/* Função: inicializa comunicação serial com baudrate 115200 (para fins de monitorar no terminal serial 
*          o que está acontecendo.
* Parâmetros: nenhum
* Retorno: nenhum
*/
void init_serial() 
{
    Serial.begin(115200);
}
 
/* Função: inicializa e conecta-se na rede WI-FI desejada
 * Parâmetros: nenhum
 * Retorno: nenhum
 */
void init_wifi(void) 
{
    delay(10);
    Serial.println("------Conexao WI-FI------");
    Serial.print("Conectando-se na rede: ");
    Serial.println(SSID);
    Serial.println("Aguarde");
    reconnect_wifi();
}
  
/* Função: inicializa parâmetros de conexão MQTT(endereço do  
 *         broker, porta e seta função de callback)
 * Parâmetros: nenhum
 * Retorno: nenhum
 */
void init_mqtt(void) 
{
    /* informa a qual broker e porta deve ser conectado */
    MQTT.setServer(BROKER_MQTT, BROKER_PORT); 
    /* atribui função de callback (função chamada quando qualquer informação do 
    tópico subescrito chega) */
    MQTT.setCallback(mqtt_callback);            
}
  
/* Função: função de callback 
 *          esta função é chamada toda vez que uma informação de 
 *          um dos tópicos subescritos chega)
 * Parâmetros: nenhum
 * Retorno: nenhum
 * */
void mqtt_callback(char* topic, byte* payload, unsigned int length) 
{
    String msg;
 
    //obtem a string do payload recebido
    for(int i = 0; i < length; i++) 
    {
       char c = (char)payload[i];
       msg += c;
    }
    Serial.print("[MQTT] Mensagem recebida: ");
    Serial.println(msg);     
}
  
/* Função: reconecta-se ao broker MQTT (caso ainda não esteja conectado ou em caso de a conexão cair)
 *          em caso de sucesso na conexão ou reconexão, o subscribe dos tópicos é refeito.
 * Parâmetros: nenhum
 * Retorno: nenhum
 */
void reconnect_mqtt(void) 
{
    while (!MQTT.connected()) 
    {
        Serial.print("* Tentando se conectar ao Broker MQTT: ");
        Serial.println(BROKER_MQTT);
        if (MQTT.connect(ID_MQTT)) 
        {
            Serial.println("Conectado com sucesso ao broker MQTT!");
            MQTT.subscribe(TOPICO_SUBSCRIBE); 
        } 
        else
        {
            Serial.println("Falha ao reconectar no broker.");
            Serial.println("Havera nova tentatica de conexao em 2s");
            delay(2000);
        }
    }
}
  
/* Função: reconecta-se ao WiFi
 * Parâmetros: nenhum
 * Retorno: nenhum
*/
void reconnect_wifi() 
{
    /* se já está conectado a rede WI-FI, nada é feito. 
       Caso contrário, são efetuadas tentativas de conexão */
    if (WiFi.status() == WL_CONNECTED)
        return;
         
    WiFi.begin(SSID, PASSWORD);
     
    while (WiFi.status() != WL_CONNECTED) 
    {
        delay(100);
        Serial.print(".");
    }
   
    Serial.println();
    Serial.print("Conectado com sucesso na rede ");
    Serial.print(SSID);
    Serial.println("IP obtido: ");
    Serial.println(WiFi.localIP());
}
 
/* Função: verifica o estado das conexões WiFI e ao broker MQTT. 
 *         Em caso de desconexão (qualquer uma das duas), a conexão
 *         é refeita.
 * Parâmetros: nenhum
 * Retorno: nenhum
 */
void verifica_conexoes_wifi_mqtt(void)
{
    /* se não há conexão com o WiFI, a conexão é refeita */
    reconnect_wifi(); 
    /* se não há conexão com o Broker, a conexão é refeita */
    if (!MQTT.connected()) 
        reconnect_mqtt(); 
} 
 
/* programa principal */
void loop() 
{   
    /* garante funcionamento das conexões WiFi e ao broker MQTT */
    verifica_conexoes_wifi_mqtt();
    /* Envia frase ao broker MQTT */
    MQTT.publish(TOPICO_PUBLISH, "ESP32 se comunicando com MQTT");
 
    /* keep-alive da comunicação com broker MQTT */    
    MQTT.loop();
    /* Agurda 1 segundo para próximo envio */
    delay(1000);   
}

 

Para compilar e enviar o software compilado ao módulo, basta fazer da mesma forma como você faria no Arduino convencional. Ou seja, clique sobre o ícone em forma de “V” (em laranja na figura 5) para compilar e, para gravar o software no módulo, basta clicar no ícone em forma de seta para a direita (em amarelo na figura 5).

 

 

Figura 5 - botões da Arduino IDE para compilação e gravação de software
Figura 5 - botões da Arduino IDE para compilação e gravação de software

 

 

Testes e resultados

Para testar, utilize qualquer cliente MQTT disponível, como por exemplo o MQTTLens ( https://chrome.google.com/webstore/detail/mqttlens/hemojaaeigabkbcookmlgmdigohjobjm?hl=pt-BR ).

No cliente MQTT de sua escolha, publique qualquer mensagem no tópico que o ESP32 faz subscribe (no caso, utilizei o tópico INCB_ESP32_recebe_informacao) e observe a confirmação da recepção da mensagem no exemplo (via Serial Monitor, na Arduino IDE), conforme mostra a figura 6.

 

 

Figura 6 - Serial monitor mostrando mensagem enviada do broker MQTT para o ESP32
Figura 6 - Serial monitor mostrando mensagem enviada do broker MQTT para o ESP32

 

 

Ainda no cliente MQTT de sua escolha, se subscreva ao tópico que o ESP32 está publicando informações (no caso, utilizei o tópico INCB_ESP32_envia_informacao). Como resultado, você verá, segundo a segundo, a frase "ESP32 se comunicando com MQTT" chegar, conforme mostra a figura 7.

 

 

 

Figura 7 - cliente MQTT mostrando mensagem enviada do ESP32 para o broker MQTT
Figura 7 - cliente MQTT mostrando mensagem enviada do ESP32 para o broker MQTT

 

 

Desta forma, está validada a comunicação MQTT usando ESP32.

 

Conclusão

Neste artigo, vimos em linhas gerais o que é o protocolo de comunicação MQTT, do que é composta uma mensagem MQTT e, além disso, utilizamos um ESP32 para comunicação (envio e recepção) de mensagens MQTT para um broker.

Se aprofundando um pouco mais no conteúdo deste artigo, você conseguirá se comunicar com plataformas IoT diversas, podendo inserir seus projetos no mundo da Internet das Coisas de forma profissional.