#include <WiFi.h>
#include <ThingerESP32.h>
#include <DHTesp.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define USER_ID "enzobernardini"
#define DEVICE_ID "ESP32_DataCenter_Global"
#define DEVICE_CREDENTIAL "DataMonitor"
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""
#define PIN_DHT 15
#define LED_ALERTA 26
#define LED_OK 25
#define EXAUSTOR_BUZZER 2
#define BTN_MUDAR_TELA 14
#define BTN_FALHA_AR1 18
#define BTN_ALTA_UMIDADE 19
DHTesp sensorDHT;
LiquidCrystal_I2C lcd(0x27, 16, 2);
ThingerESP32 thing(USER_ID, DEVICE_ID, DEVICE_CREDENTIAL);
float tempAtual = 0.0;
float umidAtual = 0.0;
float ganhoTemp = 0.0;
float ganhoUmid = 0.0;
bool falhaAr1 = false;
bool umidadeAltaSimulada = false;
bool exaustorAtivoRemoto = false;
int telaAtualLCD = 0;
unsigned long tempoUltimaLeitura = 0;
unsigned long tempoComunicacaoThinger = 0;
bool antMudarTela = HIGH;
bool antFalhaAr1 = HIGH;
bool antAltaUmid = HIGH;
String nivelRisco = "BAIXO";
String statusServidor = "ATIVO";
String statusAr1 = "LIGADO";
String statusAr2 = "DESLIGADO";
String statusExaustor = "DESLIGADO";
void atualizarDisplay() {
lcd.clear();
if (telaAtualLCD == 0) {
lcd.setCursor(0, 0);
lcd.print("T:"); lcd.print(tempAtual, 1); lcd.print("C U:"); lcd.print(umidAtual, 0); lcd.print("%");
lcd.setCursor(0, 1);
lcd.print("RISCO: "); lcd.print(nivelRisco);
} else {
lcd.setCursor(0, 0);
lcd.print("AR1:"); lcd.print(statusAr1);
lcd.setCursor(0, 1);
lcd.print("AR2:"); lcd.print(statusAr2);
}
}
void gerenciarExaustor() {
if (nivelRisco == "CRITICO" || exaustorAtivoRemoto) {
statusExaustor = "LIGADO";
digitalWrite(EXAUSTOR_BUZZER, HIGH);
} else {
statusExaustor = "DESLIGADO";
digitalWrite(EXAUSTOR_BUZZER, LOW);
}
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
lcd.init();
lcd.backlight();
pinMode(LED_ALERTA, OUTPUT);
pinMode(LED_OK, OUTPUT);
pinMode(EXAUSTOR_BUZZER, OUTPUT);
pinMode(BTN_MUDAR_TELA, INPUT_PULLUP);
pinMode(BTN_FALHA_AR1, INPUT_PULLUP);
pinMode(BTN_ALTA_UMIDADE, INPUT_PULLUP);
sensorDHT.setup(PIN_DHT, DHTesp::DHT22);
thing.add_wifi(WIFI_SSID, WIFI_PASSWORD);
thing["temperatura"] >> [](pson& out) { out = tempAtual; };
thing["umidade"] >> [](pson& out) { out = umidAtual; };
thing["risco"] >> [](pson& out) { out = nivelRisco; };
thing["status_servidor"] >> [](pson& out) { out = statusServidor; };
thing["status_ar1"] >> [](pson& out) { out = statusAr1; };
thing["status_ar2"] >> [](pson& out) { out = statusAr2; };
thing["status_exaustor"] >> [](pson& out) { out = statusExaustor; };
thing["exaustor_remoto"] << [](pson& in) {
if (in.is_empty()) {
in = exaustorAtivoRemoto;
} else {
exaustorAtivoRemoto = in;
Serial.print("[IOT] Comando do exaustor recebido via Dashboard: ");
Serial.println(exaustorAtivoRemoto ? "LIGAR" : "DESLIGAR");
gerenciarExaustor();
atualizarDisplay();
}
};
}
void loop() {
thing.handle();
bool lerMudarTela = digitalRead(BTN_MUDAR_TELA);
bool lerFalhaAr1 = digitalRead(BTN_FALHA_AR1);
bool lerAltaUmid = digitalRead(BTN_ALTA_UMIDADE);
unsigned long tempoAgora = millis();
static unsigned long ultimaTrocaBotao = 0;
const unsigned long tempoDebounce = 200;
if (tempoAgora - ultimaTrocaBotao >= tempoDebounce) {
if (lerMudarTela == LOW && antMudarTela == HIGH) {
telaAtualLCD = !telaAtualLCD;
atualizarDisplay();
ultimaTrocaBotao = tempoAgora;
}
if (lerFalhaAr1 == LOW && antFalhaAr1 == HIGH) {
falhaAr1 = !falhaAr1;
Serial.print("[SIMULADOR] Alterou estado de falha do Ar 1 para: ");
Serial.println(falhaAr1 ? "COM DEFEITO" : "NORMAL");
ultimaTrocaBotao = tempoAgora;
}
if (lerAltaUmid == LOW && antAltaUmid == HIGH) {
umidadeAltaSimulada = !umidadeAltaSimulada;
Serial.print("[SIMULADOR] Alterou estado de infiltração de umidade para: ");
Serial.println(umidadeAltaSimulada ? "CRÍTICA" : "NORMAL");
ultimaTrocaBotao = tempoAgora;
}
}
antMudarTela = lerMudarTela;
antFalhaAr1 = lerFalhaAr1;
antAltaUmid = lerAltaUmid;
if (millis() - tempoUltimaLeitura >= 2500) {
TempAndHumidity dados = sensorDHT.getTempAndHumidity();
if (isnan(dados.temperature) || isnan(dados.humidity)) {
dados.temperature = 22.0;
dados.humidity = 45.0;
}
if (falhaAr1) {
if (statusAr2 == "LIGADO") {
ganhoTemp += 0.0;
} else if (statusAr2 == "EMERGENCIA") {
ganhoTemp -= 2.5;
} else {
ganhoTemp += 3.5;
}
if (ganhoTemp > 25.0) ganhoTemp = 25.0;
} else {
ganhoTemp -= 4.0;
}
if (ganhoTemp < 0.0) ganhoTemp = 0.0;
if (umidadeAltaSimulada) {
if (statusExaustor == "LIGADO") {
ganhoUmid -= 6.0;
} else {
ganhoUmid += 12.0;
}
if (ganhoUmid > 40.0) ganhoUmid = 40.0;
} else {
ganhoUmid -= 8.0;
}
if (ganhoUmid < 0.0) ganhoUmid = 0.0;
tempAtual = dados.temperature + ganhoTemp;
umidAtual = dados.humidity + ganhoUmid;
if (tempAtual > 35.0 || umidAtual > 75.0) {
nivelRisco = "CRITICO";
statusServidor = "PROTECAO";
statusAr1 = falhaAr1 ? "DEFEITO" : "LIGADO";
statusAr2 = "EMERGENCIA";
digitalWrite(LED_ALERTA, HIGH);
digitalWrite(LED_OK, LOW);
}
else if (tempAtual > 28.0 || umidAtual > 60.0) {
nivelRisco = "ALTO";
statusServidor = "ATENCAO";
statusAr1 = falhaAr1 ? "DEFEITO" : "LIGADO";
statusAr2 = "LIGADO";
digitalWrite(LED_ALERTA, HIGH);
digitalWrite(LED_OK, LOW);
}
else {
nivelRisco = "BAIXO";
statusServidor = "ATIVO";
statusAr1 = "LIGADO";
statusAr2 = "DESLIGADO";
digitalWrite(LED_ALERTA, LOW);
digitalWrite(LED_OK, HIGH);
}
gerenciarExaustor();
atualizarDisplay();
tempoUltimaLeitura = millis();
}
if (millis() - tempoComunicacaoThinger >= 3000) {
thing.stream("temperatura");
thing.stream("umidade");
thing.stream("risco");
thing.stream("status_servidor");
thing.stream("status_ar1");
thing.stream("status_ar2");
thing.stream("status_exaustor");
tempoComunicacaoThinger = millis();
}
}