#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ---------------------- CONFIGURAÇÕES ------------------------------------------------
// WiFi
const char* ssid = "SEU_SSID";
const char* password = "SUA_SENHA";
// MQTT
const char* mqtt_server = "broker.hivemq.com"; // ou outro broker que use no aplicativo IoT MQTT Panel
const int mqtt_port = 1883;
const char* mqtt_user = ""; // se houver autenticação
const char* mqtt_pass = ""; // se houver
// Tópicos MQTT — vamos definir um tópico por relé, por exemplo “casa/rele1”, “casa/rele2”, etc.
const char* topic_prefix = "casa/";
// OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Mapeamento de pinos dos relés
const int relePins[8] = { 13, 12, 14, 27, 26, 25, 33, 32 };
// Pinos dos botões (para os 3 primeiros relés)
const int botaoPins[3] = { 34, 35, 39 };
// LEDs de status
const int ledMQTTcon = 2;
const int ledMQTTsend = 15;
const int ledMQTTrecv = 4;
// Estado atual dos relés (0 = desligado, 1 = ligado)
int releState[8] = {0,0,0,0,0,0,0,0};
// Objeto MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// --------------- FUNÇÕES AUXILIARES ---------------------------------------------------
void atualizarDisplay(const char* linha1, const char* linha2) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println(linha1);
display.println(linha2);
display.display();
}
void piscarLed(int pin, int tempoMillis) {
digitalWrite(pin, HIGH);
delay(tempoMillis);
digitalWrite(pin, LOW);
}
// Envia estado de todos os relés via MQTT (por exemplo após uma mudança local)
void publicarEstados() {
for (int i = 0; i < 8; i++) {
char topic[64];
snprintf(topic, sizeof(topic), "%s/rele%d", topic_prefix, i+1);
const char* msg = (releState[i] ? "ON" : "OFF");
client.publish(topic, msg);
// Indica envio
piscarLed(ledMQTTsend, 50);
}
}
// Callback quando receber mensagem MQTT
void mqttCallback(char* topic, byte* payload, unsigned int length) {
// Indica recepção de mensagem
piscarLed(ledMQTTrecv, 50);
// Converte payload para string
char msg[20];
if (length < sizeof(msg)) {
memcpy(msg, payload, length);
msg[length] = '\0';
} else {
strncpy(msg, "?", sizeof(msg));
msg[sizeof(msg)-1] = '\0';
}
// Exibe no display brevemente
atualizarDisplay("Msg recebida:", msg);
// Verifica qual relé foi endereçado: tópico “casa/releX”
String top = String(topic);
if (top.startsWith(String(topic_prefix) + "/rele")) {
int idx = top.charAt(top.length()-1) - '1'; // se for “rele1” etc
if (idx >= 0 && idx < 8) {
if (strcasecmp(msg, "ON") == 0) {
releState[idx] = 1;
digitalWrite(relePins[idx], HIGH);
} else if (strcasecmp(msg, "OFF") == 0) {
releState[idx] = 0;
digitalWrite(relePins[idx], LOW);
}
}
}
}
// Conecta ao broker MQTT
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("Tentando conectar MQTT...");
if (client.connect("ESP32Casa", mqtt_user, mqtt_pass)) {
Serial.println("conectado");
digitalWrite(ledMQTTcon, HIGH);
// Subscreve todos os tópicos de relés
for (int i = 0; i < 8; i++) {
char topic[64];
snprintf(topic, sizeof(topic), "%s/rele%d", topic_prefix, i+1);
client.subscribe(topic);
}
} else {
Serial.print("falhou, rc=");
Serial.print(client.state());
Serial.println(" — tentando de novo em 5s");
digitalWrite(ledMQTTcon, LOW);
delay(5000);
}
}
}
// Verifica botões para acionamento manual dos 3 primeiros relés
void checarBotoes() {
for (int i = 0; i < 3; i++) {
if (digitalRead(botaoPins[i]) == LOW) { // supondo botão com pull-up
// alternar estado
releState[i] = 1 - releState[i];
digitalWrite(relePins[i], releState[i] ? HIGH : LOW);
// publicar estado após a mudança
char topic[64];
snprintf(topic, sizeof(topic), "%s/rele%d", topic_prefix, i+1);
client.publish(topic, releState[i] ? "ON" : "OFF");
// piscar LED de envio
piscarLed(ledMQTTsend, 50);
delay(300); // debouncing simples
}
}
}
// -------------- SETUP E LOOP -----------------------------------------------------------
void setup() {
Serial.begin(115200);
// Inicializa pinos
for (int i = 0; i < 8; i++) {
pinMode(relePins[i], OUTPUT);
digitalWrite(relePins[i], LOW);
}
for (int i = 0; i < 3; i++) {
pinMode(botaoPins[i], INPUT_PULLUP);
}
pinMode(ledMQTTcon, OUTPUT);
pinMode(ledMQTTsend, OUTPUT);
pinMode(ledMQTTrecv, OUTPUT);
// Inicializa display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("Falha ao inicializar SSD1306");
while (true) delay(10);
}
display.clearDisplay();
display.display();
// Conecta ao WiFi
WiFi.begin(ssid, password);
atualizarDisplay("Conectando WiFi...", "");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi conectado!");
atualizarDisplay("WiFi conectado", WiFi.localIP().toString().c_str());
// Inicia cliente MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(mqttCallback);
// Conecta ao MQTT
reconnectMQTT();
// Publica estados iniciais dos relés
publicarEstados();
}
void loop() {
if (!client.connected()) {
digitalWrite(ledMQTTcon, LOW);
reconnectMQTT();
}
client.loop();
// Verifica botões
checarBotoes();
// Atualiza display com status atual
String l1 = String("WiFi: ") + (WiFi.status()==WL_CONNECTED ? "OK" : "X");
String l2 = String("MQTT: ") + (client.connected() ? "OK" : "X");
atualizarDisplay(l1.c_str(), l2.c_str());
delay(200);
}