/*
Controle de LEDs via MQTT com ESP32
- Conecta-se à rede Wi-Fi
- Comunica-se com broker MQTT
- Controla LEDs vermelho e azul através de comandos
- Publica status dos LEDs no broker
*/
// ================= BIBLIOTECAS =================
#include <WiFi.h> // Biblioteca para conexão com redes Wi-Fi
#include "PubSubClient.h" // Biblioteca para comunicação usando o protocolo MQTT
// ================= CONSTANTES E DEFINIÇÕES =================
// Configurações de Hardware
const int LED_VERMELHO = 2; // Define o pino do LED vermelho como GPIO2
const int LED_AZUL = 12; // Define o pino do LED azul como GPIO12
// Configurações de Rede
const char *SSID_WIFI = "Wokwi-GUEST"; // Nome (SSID) da rede Wi-Fi que será conectada
const char *SENHA_WIFI = ""; // Senha da rede Wi-Fi
// Configurações MQTT
const char *BROKER_MQTT = "iotsistemas.com.br"; // Endereço do broker MQTT
const int PORTA_MQTT = 1883; // Porta padrão para MQTT sem TLS
const char *USUARIO_MQTT = "univap"; // Usuário para autenticação no broker
const char *SENHA_MQTT = "univap"; // Senha para autenticação no broker
// Tópicos MQTT
const char *TOPICO_LED_VERMELHO = "univap/eletronica/helio/ledVermelho"; // Tópico para comandos do LED vermelho
const char *TOPICO_LED_AZUL = "univap/eletronica/helio/ledAzul"; // Tópico para comandos do LED azul
const char *TOPICO_STATUS = "univap/eletronica/helio/status"; // Tópico para publicação do status dos LEDs
// ================= VARIÁVEIS GLOBAIS =================
WiFiClient clienteWiFi; // Cria um cliente para gerenciar a conexão Wi-Fi
PubSubClient clienteMQTT(clienteWiFi); // Cria o cliente MQTT utilizando a conexão Wi-Fi
String idCliente; // ID único do cliente MQTT para identificar o ESP32 no broker
// ================= PROTÓTIPOS DE FUNÇÃO =================
bool conectarWiFi(); // Função para conectar ao Wi-Fi
bool conectarMQTT(); // Função para conectar ao broker MQTT
void receberMensagemMQTT(char* topico, byte* payload, unsigned int length); // Callback para processar mensagens recebidas via MQTT
void inscreverTopico(const char* topico); // Função para inscrição em um tópico MQTT
void publicarMensagem(const char* topico, const char* mensagem); // Função para publicar mensagens em um tópico MQTT
void processarComandoLED(int pinoLED, String comando, String nomeLED); // Função para processar comandos de controle dos LEDs
// ================= SETUP (INICIALIZAÇÃO) =================
void setup() {
Serial.begin(115200); // Inicializa a comunicação serial com baud rate de 115200
while (!Serial); // Aguarda a inicialização da porta serial
// Configura os pinos dos LEDs como saída
pinMode(LED_VERMELHO, OUTPUT); // Configura pino do LED vermelho como saída
pinMode(LED_AZUL, OUTPUT); // Configura pino do LED azul como saída
digitalWrite(LED_VERMELHO, LOW); // Garante que o LED vermelho inicie desligado
digitalWrite(LED_AZUL, LOW); // Garante que o LED azul inicie desligado
Serial.println("\nIniciando sistema de controle de LEDs via MQTT..."); // Mensagem informativa no monitor serial
// Conecta ao Wi-Fi
if (conectarWiFi()) { // Tenta conectar-se à rede Wi-Fi
Serial.println("Wi-Fi conectado com sucesso!");
Serial.print("Endereço IP: ");
Serial.println(WiFi.localIP()); // Exibe o IP atribuído ao ESP32
clienteMQTT.setServer(BROKER_MQTT, PORTA_MQTT); // Configura o servidor MQTT (broker)
clienteMQTT.setCallback(receberMensagemMQTT); // Define a função callback para mensagens recebidas
// Conecta ao broker MQTT
if (conectarMQTT()) { // Tenta conectar-se ao broker MQTT
inscreverTopico(TOPICO_LED_VERMELHO); // Inscreve no tópico do LED vermelho
inscreverTopico(TOPICO_LED_AZUL); // Inscreve no tópico do LED azul
}
} else {
Serial.println("Falha na conexão Wi-Fi!"); // Exibe erro caso não consiga conectar ao Wi-Fi
}
}
// ================= LOOP (PRINCIPAL) =================
void loop() {
// Verifica se ainda está conectado ao Wi-Fi, se não, tenta reconectar
if (WiFi.status() != WL_CONNECTED) {
conectarWiFi();
}
// Verifica se ainda está conectado ao MQTT, se não, tenta reconectar
if (!clienteMQTT.connected()) {
conectarMQTT();
// Após reconectar ao broker, reinscreve-se nos tópicos
inscreverTopico(TOPICO_LED_VERMELHO);
inscreverTopico(TOPICO_LED_AZUL);
}
clienteMQTT.loop(); // Mantém a comunicação MQTT ativa, processa mensagens recebidas
}
// ================= FUNÇÕES =================
// Conecta ao Wi-Fi
bool conectarWiFi() {
if (WiFi.status() == WL_CONNECTED) { // Se já estiver conectado ao Wi-Fi
return true; // Retorna verdadeiro
}
Serial.print("Conectando ao Wi-Fi ");
Serial.print(SSID_WIFI);
WiFi.mode(WIFI_STA); // Configura o ESP32 como estação Wi-Fi
WiFi.begin(SSID_WIFI, SENHA_WIFI); // Inicia o processo de conexão ao Wi-Fi
unsigned long tempoInicio = millis(); // Armazena o tempo atual para controle de timeout
while (WiFi.status() != WL_CONNECTED) { // Aguarda até conectar
delay(500); // Espera 500ms entre tentativas
Serial.print("."); // Exibe pontos enquanto aguarda
if (millis() - tempoInicio > 20000) { // Se ultrapassar 20 segundos sem conectar
Serial.println("\nTempo excedido na conexão Wi-Fi!");
return false; // Retorna falso (falha na conexão)
}
}
Serial.println("\nConectado!"); // Mensagem de sucesso
return true;
}
bool conectarMQTT() {
if (clienteMQTT.connected()) { // Se já estiver conectado ao broker
return true;
}
Serial.print("Conectando ao Broker MQTT: ");
Serial.println(BROKER_MQTT);
// Gera um ID único usando o endereço MAC do ESP32 + número aleatório
String enderecoMAC = WiFi.macAddress();
enderecoMAC.replace(":", ""); // Remove os dois-pontos do MAC
// Gera um número aleatório entre 0 e 9999
randomSeed(analogRead(0)); // Inicializa o gerador de números aleatórios
int numeroAleatorio = random(10000); // Gera número entre 0-9999
// Monta ID único do cliente com MAC + número aleatório
idCliente = "ESP32-" + enderecoMAC + "-" + String(numeroAleatorio);
// Tenta conectar ao broker com usuário e senha
if (clienteMQTT.connect(idCliente.c_str(), USUARIO_MQTT, SENHA_MQTT)) {
Serial.println("Conectado ao broker com sucesso!");
Serial.print("ID do cliente: ");
Serial.println(idCliente);
return true;
} else {
Serial.print("Falha na conexão, estado: ");
Serial.println(clienteMQTT.state()); // Exibe código de erro da conexão MQTT
return false;
}
}
// Callback para mensagens MQTT recebidas
void receberMensagemMQTT(char* topico, byte* payload, unsigned int length) {
String mensagem; // Armazena a mensagem recebida
for (int i = 0; i < length; i++) { // Converte cada byte recebido em caractere
mensagem += (char)payload[i];
}
Serial.print("Mensagem recebida [");
Serial.print(topico); // Exibe o tópico da mensagem recebida
Serial.print("]: ");
Serial.println(mensagem); // Exibe a mensagem recebida
// Verifica qual LED deve ser controlado com base no tópico
if (String(topico) == TOPICO_LED_VERMELHO) {
processarComandoLED(LED_VERMELHO, mensagem, "vermelho");
}
else if (String(topico) == TOPICO_LED_AZUL) {
processarComandoLED(LED_AZUL, mensagem, "azul");
}
}
// Inscreve em um tópico MQTT
void inscreverTopico(const char* topico) {
if (clienteMQTT.subscribe(topico)) { // Tenta inscrever-se no tópico
Serial.print("Inscrito no tópico: ");
Serial.println(topico);
} else {
Serial.print("Falha ao se inscrever no tópico: ");
Serial.println(topico);
}
}
// Publica mensagem em um tópico MQTT
void publicarMensagem(const char* topico, const char* mensagem) {
if (clienteMQTT.publish(topico, mensagem)) { // Publica mensagem no tópico
Serial.print("Mensagem publicada [");
Serial.print(topico);
Serial.print("]: ");
Serial.println(mensagem);
} else {
Serial.print("Falha ao publicar no tópico: ");
Serial.println(topico);
}
}
// Processa comandos dos LEDs
void processarComandoLED(int pinoLED, String comando, String nomeLED) {
comando.toLowerCase(); // Converte comando para letras minúsculas
String mensagemStatus; // Armazena mensagem de status do LED
if (comando == "ligar") { // Se comando recebido for "ligar"
digitalWrite(pinoLED, HIGH); // Liga o LED
mensagemStatus = "LED " + nomeLED + " ligado";
Serial.println(mensagemStatus); // Exibe status no serial
publicarMensagem(TOPICO_STATUS, mensagemStatus.c_str()); // Publica status no tópico de status
}
else if (comando == "desligar") { // Se comando recebido for "desligar"
digitalWrite(pinoLED, LOW); // Desliga o LED
mensagemStatus = "LED " + nomeLED + " desligado";
Serial.println(mensagemStatus);
publicarMensagem(TOPICO_STATUS, mensagemStatus.c_str());
}
else { // Caso comando seja inválido
String mensagemErro = "Comando inválido para LED " + nomeLED + ": " + comando;
Serial.println(mensagemErro);
publicarMensagem(TOPICO_STATUS, mensagemErro.c_str());
}
}