ESP32-C6 na Prática: Comunicação MQTT

Este post faz parte da série ESP32-C6 na Prática

Introdução

Neste artigo, mostraremos como criar uma comunicação MQTT (Message Queuing Telemetry Transport), utilizando a placa de desenvolvimento ESP32-C6 DevKitC-1

Nosso projeto terá como objetivo o envio e recebimento de mensagens via MQTT para controlar o estado de um LED, além de incluir uma funcionalidade extra: atualizar dinamicamente as credenciais do broker MQTT utilizando WebSocket, sem a necessidade de regravar o firmware.

Para conhecer mais a placa de desenvolvimento consulte nosso artigo Introdução à Placa ESP32-C6-DevKitC-1: Ideal para IoT

Características do MQTT

  • Usa o protocolo de mensagens publicador/assinante
  • Suporta comunicação assíncrona
  • Utiliza padrão de tópicos para organizar mensagem
  • Confíavel

A estrutura envolve três componentes:

  • Broker MQTT: servidor responsável por gerenciar os tópicos e repassar as mensagens
  • Publisher (publicador): dispositivo que envia mensagens
  • Subscriber (assinante): dispositivo que recebe mensagem de um tópico

Para saber mais sobre o protocolo MQTT, veja o artigo do professor Marcelo Barros https://embarcados.com.br/mqtt-protocolos-para-iot/

Materiais Necessários

Para desenvolver nossa aplicação os materiais utilizados foram:

Para configurar o ambiente e instalar o suporte a ESP32-C6 veja o artigo ESP32-C6 na Prática: Seu Primeiro “Hello World”

Circuito

O circuito utilizado para este artigo será a placa ESP32-C6 DevKitC-1 para gerir o Web Server e se conectar ao Broker MQTT como publicador e assinante no tópico, o LED para sinalizar as ações via MQTT e o botão para publicar o estado do LED. 

Como o ESP32-C6 possui resistores internos de pull-up, não utilizaremos um resistor externo para o botão. 

ESP32-C6 na Prática: Comunicação MQTT
Figura 1: Circuito desenvolvido

Código

No projeto proposto, o ESP23-C6 DevKitC-1 é conectado à rede local para gerir o Websocket. Assim, é necessário conectar a placa à rede utilizando as credenciais do Wi-Fi.

Também precisamos instalar as bibliotecas PubSubClient pelo gerenciador de bibliotecas da Arduino IDE por Nick O´Leary

Em seguida, copie o endereço IP apresentado no monitor serial (Figura 2) e cole-o no navegador de sua preferência (Figura 3).

ESP32-C6 na Prática: Comunicação MQTT
Figura 2: Monitor Serial
ESP32-C6 na Prática: Comunicação MQTT
Figura 3: Página HTML

Todo o código desenvolvido está disponível para consulta em download.

Vamos utilizar os seguintes endereços de brokers e WebSocket Port para nossa aplicação Web.

NomeEndereçoTCP PortWebSocket Port
EMQXbroker.emqx.io18838084
HiveMQbroker.hivemq.com18838884
Tabela 1: Brokers públicos

Para nosso exemplo, começamos definindo as configurações para se trabalhar com MQTT. Assim, precisamos associar as definições com os tipos que serão constantes no desenvolvimento e as que iremos alterar via WebSocket.

// Definicao de variaveis
#define topic_led "esp32/led/vermelho"  // Tópico MQTT para o LED Vermelho
#define broker_default "broker.emqx.io" // Endereço do Broker MQTT - Se desejar utilizar outro, substitua este pelo endereço do seu broker
#define mqtt_tcp_port_default 1883      // Porta do Broker MQTT TCP
#define mqtt_ws_port_default 8084       // Porta do Broker MQTT WebSocket emqx
#define id_mqtt "esp32c6_guilherme"     // ID do cliente MQTT - Pode ser alterado, mas deve ser único para cada cliente conectado ao broker

// Definição dos Tópicos MQTT
const char* topic_led_vermelho = topic_led;

// Configuração do Broker MQTT
const int mqtt_port = mqtt_tcp_port_default;
const char* idMqtt = id_mqtt;
String mqtt_server = broker_default;
int mqtt_ws_port = mqtt_ws_port_default;

Depois seguimos com a configuração do WebSocket que já realizamos no artigo {WebScoket}. Agora diferenciando para enviar e receber o endereço e porta do broker.

// Função para lidar com eventos do WebSocket
void onWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%lu connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      client->text("mqtt_server=" + mqtt_server + ";mqtt_port=" + String(mqtt_ws_port) + ";topic_led_vermelho=" + String(topic_led_vermelho));
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%lu disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      {
        String msg = "";
        for (size_t i = 0; i < len; i++) {
          msg += (char)data[i];
        }
        Serial.println("Mensagem recebida via WebSocket: " + msg);
        mqtt_server = msg.substring(msg.indexOf("mqtt_server=") + 12, msg.indexOf(";mqtt_port="));
        mqtt_ws_port = msg.substring(msg.indexOf("mqtt_port=") + 10).toInt();


        Serial.println("Novo servidor MQTT: " + mqtt_server);
        Serial.println("Nova porta WebSocket MQTT: " + String(mqtt_ws_port));
        mqtt.disconnect();
        break;
      }
    default:
      break;
  }
}

Usamos freeRTOS para ler o estado do botão de forma assíncrona às atividades, assim a task é responsável por publicar a mensagem no tópico para alternar o estado do led.

/*-------------------------------------------------------------------------------
  Tarefa para ler o estado do botão e publicar a mensagem no tópico MQTT
 *---------------------------------------------------------------------------*/
void taskBotao(void* parameter) {
  for (;;) {
    button.update();                                           // Atualiza o estado do botão
    if (button.wasPressed()) {                                 // Verifica se o botão foi pressionado
      Serial.println("Botão pressionado");                    
      ledState = !ledState;                                    // Inverte o estado do LED
      String msg = ledState ? "ON" : "OFF";                    
      mqtt.publish(topic_led_vermelho, msg.c_str(), false);    // Publica a mensagem no tópico do LED Vermelho
    }
    vTaskDelay(pdMS_TO_TICKS(100));                            // Aguarda 100 ms antes de verificar novamente
  }
}

Também definimos a função para conexão ao Broker MQTT e a função de callback

// Função de conexao ao Broker MQTT
void connectMQTT() {
  while (!mqtt.connected()) {                                                        
    Serial.println("Conectando ao broker: " + mqtt_server + ":" + String(mqtt_port));
    mqtt.setServer(mqtt_server.c_str(), mqtt_port);


    if (mqtt.connect(idMqtt)) {
      Serial.println("Conectado!");


      // Assinar os tópicos dos LEDs
      mqtt.subscribe(topic_led_vermelho);


      // Imprime a mensagem no monitor serial
      Serial.println("Assinado nos tópicos: ");
      Serial.println(topic_led_vermelho);
    } else {
      Serial.print("Falha, código: ");  // Imprime a mensagem no monitor serial
      Serial.println(mqtt.state());     // Imprime o código de erro no monitor serial
      delay(5000);                      // Aguarda 5 segundos e tenta novamente
    }
  }
}
// Callback para processar mensagens recebidas do MQTT
void callback(char* topic, byte* message, unsigned int length) {
  String msg = "";                   // Cria uma string para armazenar a mensagem
  for (int i = 0; i < length; i++){  // Percorre a mensagem recebida
    msg += (char)message[i];         // Concatena os caracteres da mensagem
  }


  // Imprime a mensagem recebida no monitor serial - Log
  Serial.print("Mensagem recebida no tópico: ");
  Serial.println(topic);
  Serial.print("Conteúdo: ");
  Serial.println(msg);


  // Verifica se a mensagem é para o LED vermelho
  if (strcmp(topic, topic_led_vermelho) == 0){  // Compara o tópico recebido com o tópico do LED Vermelho
      if (msg == "ON") {
        setLED(true);
      } else if (msg == "OFF") {
        setLED(false);
      }
  }
}

O script do websocket para alterar o broker e enviar para o ESP32-C6

function salvarConfiguracoes() {
        mqtt_server = document.getElementById("mqtt_server").value;
        mqtt_port = document.getElementById("mqtt_port").value;


        if (!mqtt_server || !mqtt_port) {
          alert("Por favor, preencha o Broker MQTT e a Porta WebSocket MQTT.");
          return;
        }
        if (websocket && websocket.readyState === WebSocket.OPEN) {
          websocket.send(`mqtt_server=${mqtt_server};mqtt_port=${mqtt_port}`);
          console.log("Configurações salvas via WebSocket");
          iniciarClienteMQTT();
        } else {
          console.warn("WebSocket não conectado");
        }
      }

Função para se conectar ao broker, ser assinante e publicador

function iniciarClienteMQTT() {
        if (mqttClient && mqttClient.connected) {
          mqttClient.end(); // desconecta se já estava conectado
        }


        mqttClient = mqtt.connect(`wss://${mqtt_server}:${mqtt_port}/mqtt`);


        mqttClient.on("connect", () => {
          document.getElementById("status").textContent = "Conectado!";
          mqttClient.subscribe(topic_led_vermelho);
        });


        mqttClient.on("message", (topic, message) => {
          console.log(`Mensagem: ${message.toString()} do tópico: ${topic}`);
          if (topic === topic_led_vermelho) {
            atualizarEstado(message.toString());
          }
        });
      }
function toggleLed(element) {
        const comando = element.checked ? "ON" : "OFF";
        mqttClient.publish(topic_led_vermelho, comando);
      }

Configuração conexão MQTTX:

ESP32-C6 na Prática: Comunicação MQTT
Figura 4: Configuração MQTTX

Configuração conexão App MQTT Client

Figura 5: Configuração broker e assinatura

Resultados

No exemplo abaixo, utilizamos um servidor web, um botão físico e o MQTTX para publicar valores no tópico esp32/led/vermelho. Além disso, o ESP32 também assina esse tópico para receber atualizações enviadas pelo broker. O monitor serial exibe um log com todas as atividades realizadas.

Figura 6: Resultados obtidos

Atenção: Caso você receba uma falha na conexão MQTT com o status -2, isso indica que a porta TCP 1883 está bloqueada pelo firewall do seu roteador Wi-Fi. Para resolver esse problema, utilize as credenciais do hotspot do celular ou reconfigure seu roteador para liberar a porta 1883.

Conclusão

Neste artigo, mostramos como criar uma comunicação MQTT e um servidor local utilizando a placa ESP32-C6 DevKitC-1 para controlar dispositivos. A interface HTML foi integrada ao firmware, permitindo comunicação em tempo real com o hardware.

Para leitores que não estão familiarizados com HTML e JavaScript, pode haver certa dificuldade inicial, mas existem diversas ferramentas e recursos online que podem auxiliar nesse processo em HTML Basic Examples

Convidamos você a explorar outros projetos com o protocolo MQTT, como transmissão de sensores, gráficos em tempo real, controle múltiplo de dispositivos, e a compartilhar seus resultados com a comunidade por meio de artigos, vídeos ou repositórios abertos.

Referências

ESP32-C6 na Prática

ESP32-C6 na Prática: Comunicação Bidirecional sem Wi-Fi usando ESP-NOW ESP32-C6 na Prática: ESP RainMaker com Arduino IDE
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
0 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Home » Comunicação » ESP32-C6 na Prática: Comunicação MQTT

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: