#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ESP32Servo.h>
// --- Configurações Wi-Fi ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// --- Configurações MQTT ---
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
// --- Tópicos MQTT ---
// Quarto
const char* topicoLuz = "smarthouseJLR/quarto/luz";
const char* topicoTomada = "smarthouseJLR/quarto/tomada";
const char* topicoCortina = "smarthouseJLR/quarto/cortina";
// Sala de skar
const char* topicoSensor = "smarthouseJLR/sala/lerSensor";
const char* topicoLed = "smarthouseJLR/sala/led1";
const char* topicoarCondicionado = "smarthouseJLR/sala/arCondicionado";
const char* topicoUmidificador = "smarthouseJLR/sala/umidificador";
// Sala de Garagem
const char* topicoGaragemLed = "smarthouseJLR/garagem/led";
const char* topicoGaragemBascular = "smarthouseJLR/garagem/bascular";
const char* topicoGaragemSocial = "smarthouseJLR/garagem/social";
// --- Configuração do DHT22 ---
#define DHTPIN 18
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// --- Pinos ---
const int sensorMov = 23;
const int portaoBasc = 17;
const int portaoSocial = 22;
const int ledGaragem = 16;
const int pinLuz = 13;
const int pinTomada = 12;
const int pinStep = 26;
const int pinDir = 27;
const int tempoMov = 1000; // 5 segundos
const int pinVermelho = 2;
const int ac = 4;
const int humidifier = 5;
//Definindo variáveis para temperatura e umidade
float umidade = 0;
float temperatura = 0;
// --- Step timing (microsegundos entre pulsos) ---
const unsigned long stepInterval = 1600; // ~625 passos/s (HIGH+LOW)
unsigned long lastMsg = 0; //Armazena o tempo da última mensagem enviada
const long interval = 2000; //Intervalo entre publicações(2 segundos)
// --- Estado da cortina (não-bloqueante) ---
volatile bool cortinaMoving = false;
bool cortinaAbrir = false;
unsigned long movimentoInicio = 0;
unsigned long lastStepMicros = 0;
// --- Flags para controle de automação ---
bool autoArCondicionado = true;
bool autoUmidificador = true;
// --- MQTT e controle ---
WiFiClient espClient;
PubSubClient client(espClient);
Servo servo1;
Servo servo2;
// --- Wi-Fi ---
void setup_wifi() {
delay(10);
Serial.println("Conectando ao Wi-Fi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("\n✅ Wi-Fi conectado. IP: ");
Serial.println(WiFi.localIP());
}
// --- Funções para ativar automação (avaliam a condição atual e aplicam ação imediatamente) ---
void activateAutoAr() {
autoArCondicionado = true;
float t = dht.readTemperature();
if (!isnan(t)) {
temperatura = t;
if (t >= 28) {
digitalWrite(ac, HIGH);
client.publish("saladE/status", "Ar-condicionado ligado automaticamente");
Serial.println("❄️ Automacao AR: ligado (condicao atual)");
} else if (t <= 20) {
digitalWrite(ac, LOW);
client.publish("saladE/status", "Ar-condicionado desligado automaticamente");
Serial.println("❄️ Automacao AR: desligado (condicao atual)");
} else {
Serial.println("❄️ Automacao AR: ativo (sem mudanca necessária agora)");
}
} else {
Serial.println("Erro ao ler DHT ao ativar automacao AR");
}
}
void activateAutoHumidifier() {
autoUmidificador = true;
float h = dht.readHumidity();
if (!isnan(h)) {
umidade = h;
if (h <= 20) {
digitalWrite(humidifier, HIGH);
client.publish("saladE/status", "Umidificador ligado automaticamente");
Serial.println("💧 Automacao Umidificador: ligado (condição atual)");
} else if (h >= 80) {
digitalWrite(humidifier, LOW);
client.publish("saladE/status", "Umidificador desligado automaticamente");
Serial.println("💧 Automacao Umidificador: desligado (condição atual)");
} else {
Serial.println("💧 Automacao Umidificador: ativo (sem mudança necessaria agora)");
}
} else {
Serial.println("Erro ao ler DHT ao ativar automacao do umidificador");
}
}
// --- (antiga) função moverCortina (mantida caso queira usar direto) ---
void moverCortinaBlocking(bool abrir) {
digitalWrite(pinDir, abrir ? HIGH : LOW);
unsigned long inicio = millis();
while (millis() - inicio < tempoMov) {
digitalWrite(pinStep, HIGH);
delayMicroseconds(800);
digitalWrite(pinStep, LOW);
delayMicroseconds(800);
}
Serial.println(abrir ? "🚪 Cortina aberta" : "🚪 Cortina fechada");
}
// --- Callback MQTT ---
void callback(char* topic, byte* payload, unsigned int length) {
String msg = "";
for (unsigned int i = 0; i < length; i++) {
msg += (char)payload[i];
}
msg.trim();
Serial.printf("📥 [%s]: %s\n", topic, msg.c_str());
if (String(topic) == topicoLuz) {
digitalWrite(pinLuz, msg == "ON" ? HIGH : LOW);
Serial.println(msg == "ON" ? "💡 Luz ligada" : "💡 Luz desligada");
}
else if (String(topic) == topicoTomada) {
digitalWrite(pinTomada, msg == "ON" ? HIGH : LOW);
Serial.println(msg == "ON" ? "🔌 Tomada ligada" : "🔌 Tomada desligada");
}
else if (String(topic) == topicoCortina) {
// Agora não bloqueamos: setamos o estado e o loop fará os pulsos
if (msg == "ABRIR") {
cortinaAbrir = true;
cortinaMoving = true;
movimentoInicio = millis();
Serial.println("➡️ Comando: ABRIR (movendo cortina)");
}
else if (msg == "FECHAR") {
cortinaAbrir = false;
cortinaMoving = true;
movimentoInicio = millis();
Serial.println("⬅️ Comando: FECHAR (movendo cortina)");
}
else if (msg == "PARAR") {
cortinaMoving = false;
Serial.println("⏹️ Comando: PARAR (movimento interrompido)");
}
else {
Serial.println("⚠️ Payload da cortina invalido (use 'ABRIR', 'FECHAR' ou 'PARAR')");
}
}
else if (String(topic) == topicoLed) {
digitalWrite(pinVermelho, msg == "ON" ? HIGH : LOW);
}
else if (String(topic) == topicoarCondicionado) {
if (msg == "AUTO_ON") {
activateAutoAr();
Serial.println("❄️ Automacao do Ar-condicionado ATIVADA via comando");
}
else if (msg == "AUTO_OFF") {
autoArCondicionado = false;
Serial.println("❄️ Automacao do Ar-condicionado DESATIVADA via comando");
}
else if (!autoArCondicionado) { // Só aceita ON/OFF se não estiver automático
if (msg == "ON") {
digitalWrite(ac, HIGH);
Serial.println("❄️ Ar-condicionado ligado manualmente");
}
else if (msg == "OFF") {
digitalWrite(ac, LOW);
Serial.println("❄️ Ar-condicionado desligado manualmente");
}
else {
Serial.println("⚠️ Payload arCondicionado invalido");
}
} else {
Serial.println("ℹ️ Ignorando comando manual - modo automatico ativo");
}
}
else if (String(topic) == topicoUmidificador) {
if (msg == "AUTO_ON") {
activateAutoHumidifier();
Serial.println("💧 Automação do Umidificador ATIVADA via comando");
}
else if (msg == "AUTO_OFF") {
autoUmidificador = false;
Serial.println("💧 Automação do Umidificador DESATIVADA via comando");
}
else if (!autoUmidificador) { // Só aceita ON/OFF se não estiver automático
if (msg == "ON") {
digitalWrite(humidifier, HIGH);
Serial.println("💧 Umidificador ligado manualmente");
}
else if (msg == "OFF") {
digitalWrite(humidifier, LOW);
Serial.println("💧 Umidificador desligado manualmente");
}
else {
Serial.println("⚠️ Payload umidificador invalido");
}
} else {
Serial.println("ℹ️ Ignorando comando manual - modo automatico ativo");
}
}else if(String(topic) == topicoGaragemLed){
if(msg == "ON"){
digitalWrite(ledGaragem, HIGH);
Serial.println("Luz da garagem foi acesa. ");
} else if(msg == "OFF"){
digitalWrite(ledGaragem, LOW);
Serial.println("Luz da garagem foi apagada. ");
}
}else if(String(topic) == topicoGaragemSocial){
if(msg == "abrir"){
abrirPortaoSocial();
}
}else if(String(topic) == topicoGaragemBascular){
if(msg == "abrir"){
abrirPortaoBasc();
}else if(msg == "fechar"){
fecharPortaoBasc();
}
}
}
// ------------ Função para controlar os portões... ------------
void abrirPortaoBasc(){
servo2.write(180);
client.publish("smarthouseJLR/garagem/bascular" ,"Portao Bascular aberto");
}
void fecharPortaoBasc(){
client.publish("smarthouseJLR/garagem/bascular" ,"Portao Bascular fechado");
servo2.write(0);
}
void abrirPortaoSocial(){
int pos = 0;
digitalWrite(ledGaragem, HIGH);
Serial.println("Abrindo portao social");
client.publish("smarthouseJLR/garagem/social" ,"Abrindo portao social");
for(pos = 0; pos <= 180; pos += 1){
servo1.write(pos);
delay(15);
}
client.publish("smarthouseJLR/garagem/social" , "Portao social aberto!");
delay(5000);
Serial.println("Fechando portao social");
client.publish("smarthouseJLR/garagem/social" ,"Fechando portao social");
digitalWrite(ledGaragem, LOW);
for(pos = 180; pos >= 0; pos -=1){
servo1.write(pos);
delay(15);
}
}
// ----------------- Função para detectar movimento... -------------- //
void detectarMov() {
if(digitalRead(sensorMov) == HIGH){
Serial.println("Movimento Detectado, acendendo luzes!");
client.publish("smarthouseJLR/garagem", "Movimento detectado!");
delay(300);
digitalWrite(ledGaragem, HIGH);
delay(5000);
digitalWrite(ledGaragem, LOW);
}
}
// --- Reconectar MQTT ---
void reconnect(){
while (!client.connected()){
String clientId = "ESP32Client-" + String(random(0xffff), HEX);
Serial.print("Conectando ao MQTT...");
if (client.connect(clientId.c_str())){
Serial.println("✅ conectado");
client.subscribe(topicoLuz);
client.subscribe(topicoTomada);
client.subscribe(topicoCortina);
client.subscribe(topicoLed);
client.subscribe(topicoarCondicionado);
client.subscribe(topicoUmidificador);
client.subscribe(topicoGaragemLed);
client.subscribe(topicoGaragemBascular);
client.subscribe(topicoGaragemSocial);
} else {
Serial.printf("❌ falhou rc=%d, tentando em 5s\n", client.state());
delay(5000);
}
}
}
// --- Setup ---
void setup(){
Serial.begin(115200);
servo1.attach(portaoSocial, 500, 2400);
servo2.attach(portaoBasc, 500, 2400);
setup_wifi();
dht.begin();
pinMode(sensorMov, INPUT);
pinMode(ledGaragem, OUTPUT);
pinMode(pinVermelho, OUTPUT);
pinMode(ac, OUTPUT);
pinMode(humidifier, OUTPUT);
pinMode(pinLuz, OUTPUT);
pinMode(pinTomada, OUTPUT);
pinMode(pinStep, OUTPUT);
pinMode(pinDir, OUTPUT);
digitalWrite(pinVermelho, LOW);
digitalWrite(ac, LOW);
digitalWrite(humidifier, LOW);
digitalWrite(pinStep, LOW);
digitalWrite(pinDir, LOW);
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
// --- Loop principal (faz os pulsos da cortina sem bloquear) ---
void loop(){
detectarMov();
if (!client.connected()) {
reconnect();
}
client.loop();
unsigned long now = millis();
if(now - lastMsg > interval ){
lastMsg = now;
float h = dht.readHumidity();
float t =dht.readTemperature();
if(isnan(h) || isnan(t)){
Serial.println("Erro ao ler Sensor DRT22");
return;
}
if(h != umidade || t != temperatura){ //Verifica se há mudanças nas variáveis
umidade = h; //Atualiza os valores
temperatura = t;
String payload = "{";
payload += "\"temperatura\": " + String (t,1) + ",";//Um dígito decimal
payload += "\"umidade\": " + String(h,1);//Um dígito decimal
payload += "}";
Serial.print("Publicando: ");//Mostra o que será enviado
Serial.println(payload);
client.publish(topicoSensor, payload.c_str());
delay(2000);
// --- Controle automático umidificador ---
// Controle automático do Ar-condicionado
if (autoArCondicionado) {
if (temperatura >= 28) digitalWrite(ac, HIGH);
else if (temperatura <= 20) digitalWrite(ac, LOW);
}
// Controle automático do Umidificador
if (autoUmidificador) {
if (umidade <= 20) digitalWrite(humidifier, HIGH);
else if (umidade >= 80) digitalWrite(humidifier, LOW);
}
}
}
// Controle não-bloqueante do motor da cortina
if (cortinaMoving) {
// define direção
digitalWrite(pinDir, cortinaAbrir ? HIGH : LOW);
// se já passou o tempo total, para o movimento
if (millis() - movimentoInicio >= tempoMov) {
cortinaMoving = false;
Serial.println(cortinaAbrir ? "✅ Cortina (aberta) - fim do movimento" : "✅ Cortina (fechada) - fim do movimento");
} else {
// gera pulsos de step com intervalo controlado (não-bloqueante)
unsigned long now = micros();
if (now - lastStepMicros >= stepInterval) {
lastStepMicros = now;
digitalWrite(pinStep, HIGH);
delayMicroseconds(2); // pulso curto
digitalWrite(pinStep, LOW);
}
}
}
}