Atividade 2 versao 1.0
This commit is contained in:
429
src/esp32-ntp-clock.ino
Normal file
429
src/esp32-ntp-clock.ino
Normal file
@@ -0,0 +1,429 @@
|
||||
// ============================================================================
|
||||
// Sistema de monitoramento de cozinha com ESP32
|
||||
// Monitora temperatura, umidade e gás com detecção avançada de incêndio
|
||||
// Envia dados via MQTT e controla coifa e ar-condicionado
|
||||
// ============================================================================
|
||||
|
||||
// INCLUDES
|
||||
#include <DHT.h> // Sensor DHT22
|
||||
#include <PubSubClient.h> // MQTT
|
||||
#include <RTClib.h> // RTC DS1307
|
||||
#include <WiFi.h> // WiFi
|
||||
|
||||
// ============================================================================
|
||||
// DEFINES - Pinos GPIO
|
||||
// ============================================================================
|
||||
#define DHTPIN 32 // Sensor DHT22 (temperatura/umidade)
|
||||
#define DHTTYPE DHT22 // Tipo sensor DHT
|
||||
#define MQ2PIN 33 // Sensor MQ2 (qualidade do ar/gás)
|
||||
#define ALARME_SONORO 4 // Alarme sonoro
|
||||
#define COIFA 17 // Coifa (exaustor)
|
||||
#define AR_CONDICIONADO 16 // Ar-condicionado
|
||||
|
||||
// ============================================================================
|
||||
// ENUMS
|
||||
// ============================================================================
|
||||
enum statusCozinha {
|
||||
NOMINAL, // Sem alerta
|
||||
GAS, // Detecção de gás
|
||||
TEMP_ALTA, // Temperatura acima do limite
|
||||
UMIDADE_ALTA, // Umidade acima do limite
|
||||
INCENDIO // Possível incêndio (padrão: ΔT > 5°C + Δumidade < -10% em 30s)
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// CONSTANTES - Limiares de alarme
|
||||
// ============================================================================
|
||||
const int GAS_ON = 940; // Ativação gás (~1000ppm)
|
||||
const int GAS_OFF = 916; // Desativação gás (~500ppm)
|
||||
const float TEMP_ON_DEFAULT = 30.0; // Temperatura máxima padrão (°C)
|
||||
const float TEMP_HISTERESE = 2.0; // Histerese temperatura
|
||||
const float UMIDADE_ON_DEFAULT = 70.0; // Umidade máxima padrão (%)
|
||||
const float UMIDADE_HISTERESE = 5.0; // Histerese umidade
|
||||
|
||||
// Detecção de incêndio
|
||||
const uint32_t JANELA_TEMPO_INCENDIO = 30; // Janela: 30 segundos
|
||||
const float DELTA_TEMP_INCENDIO = 5.0; // Aumento mínimo: 5°C
|
||||
const float DELTA_UMIDADE_INCENDIO = -10.0; // Queda mínima: -10%
|
||||
|
||||
// ============================================================================
|
||||
// CONSTANTES - WiFi e MQTT
|
||||
// ============================================================================
|
||||
const char* WIFI_SSID = "Wokwi-GUEST";
|
||||
const char* WIFI_PASSWORD = "";
|
||||
const char* MQTT_BROKER = "77.37.69.84";
|
||||
const int MQTT_PORT = 1883;
|
||||
const char* MQTT_SUB_TOPICS[] = { "cozinha/max_tmp", "cozinha/max_umi" };
|
||||
const char* MQTT_PUB_TOPIC = "cozinha";
|
||||
const int MQTT_SUB_COUNT = sizeof(MQTT_SUB_TOPICS) / sizeof(MQTT_SUB_TOPICS[0]);
|
||||
|
||||
// ============================================================================
|
||||
// VARIÁVEIS GLOBAIS - Objetos
|
||||
// ============================================================================
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
RTC_DS1307 RTC;
|
||||
WiFiClient espClient;
|
||||
PubSubClient mqtt(espClient);
|
||||
DateTime now;
|
||||
|
||||
// ============================================================================
|
||||
// VARIÁVEIS GLOBAIS - Estado do sistema
|
||||
// ============================================================================
|
||||
int alarmStatus = NOMINAL;
|
||||
float umidade = 0.0;
|
||||
float temperatura = 0.0;
|
||||
int iqAR = 0;
|
||||
|
||||
// Variáveis de configuração (atualizáveis via MQTT)
|
||||
float TEMP_ON = TEMP_ON_DEFAULT;
|
||||
float TEMP_OFF = TEMP_ON - TEMP_HISTERESE;
|
||||
float UMIDADE_ON = UMIDADE_ON_DEFAULT;
|
||||
float UMIDADE_OFF = UMIDADE_ON - UMIDADE_HISTERESE;
|
||||
|
||||
// Variáveis para detecção de incêndio
|
||||
float temp_inicio = 0.0;
|
||||
float umidade_inicio = 0.0;
|
||||
uint32_t timestamp_inicio = 0;
|
||||
|
||||
// Buffer MQTT
|
||||
char msg[256];
|
||||
char MQTT_CLIENTID[32];
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES AUXILIARES - Callbacks MQTT
|
||||
// ============================================================================
|
||||
void mqttCallback(char* topic, byte* payload, unsigned int length)
|
||||
{
|
||||
Serial.print("[MQTT] Mensagem em [");
|
||||
Serial.print(topic);
|
||||
Serial.println("]");
|
||||
|
||||
// Copia payload para buffer null-terminated
|
||||
char buf[64];
|
||||
int n = (length < (int)sizeof(buf) - 1) ? length : (int)sizeof(buf) - 1;
|
||||
memcpy(buf, payload, n);
|
||||
buf[n] = '\0';
|
||||
|
||||
Serial.print("[MQTT] payload: ");
|
||||
Serial.println(buf);
|
||||
|
||||
// Processa tópicos
|
||||
if (strcmp(topic, "cozinha/max_tmp") == 0) {
|
||||
float v = atof(buf);
|
||||
if (!isnan(v)) {
|
||||
TEMP_ON = v;
|
||||
TEMP_OFF = TEMP_ON - TEMP_HISTERESE;
|
||||
Serial.print("[MQTT] TEMP_ON = ");
|
||||
Serial.println(TEMP_ON);
|
||||
}
|
||||
} else if (strcmp(topic, "cozinha/max_umi") == 0) {
|
||||
float v = atof(buf);
|
||||
if (!isnan(v)) {
|
||||
UMIDADE_ON = v;
|
||||
UMIDADE_OFF = UMIDADE_ON - UMIDADE_HISTERESE;
|
||||
Serial.print("[MQTT] UMIDADE_ON = ");
|
||||
Serial.println(UMIDADE_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES AUXILIARES - Conectividade
|
||||
// ============================================================================
|
||||
// Conecta o ESP32 à rede WiFi
|
||||
void connectWiFi()
|
||||
{
|
||||
Serial.print("[WiFi] Conectando...");
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
int attempts = 0;
|
||||
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
attempts++;
|
||||
}
|
||||
Serial.println("\r\n[WiFi] Conectado!");
|
||||
}
|
||||
|
||||
// Inscreve em tópicos MQTT para receber atualizações de limiares
|
||||
void mqttSubscribe()
|
||||
{
|
||||
Serial.println("[MQTT] Conectado!");
|
||||
for (int i = 0; i < MQTT_SUB_COUNT; ++i) {
|
||||
if (mqtt.subscribe(MQTT_SUB_TOPICS[i])) {
|
||||
Serial.print("[MQTT] Tópico: ");
|
||||
Serial.println(MQTT_SUB_TOPICS[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Conecta ao broker MQTT
|
||||
void connectMQTT()
|
||||
{
|
||||
mqtt.setServer(MQTT_BROKER, MQTT_PORT);
|
||||
mqtt.setCallback(mqttCallback);
|
||||
|
||||
while (!mqtt.connected()) {
|
||||
Serial.println("[MQTT] Conectando...");
|
||||
if (mqtt.connect(MQTT_CLIENTID)) {
|
||||
mqttSubscribe();
|
||||
break;
|
||||
} else {
|
||||
Serial.print("[MQTT] Falha rc=");
|
||||
Serial.println(mqtt.state());
|
||||
delay(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES AUXILIARES - Sensores
|
||||
// ============================================================================
|
||||
// Lê valores de temperatura e umidade do sensor DHT22
|
||||
void read_DHT()
|
||||
{
|
||||
umidade = dht.readHumidity();
|
||||
temperatura = dht.readTemperature();
|
||||
|
||||
if (isnan(umidade) || isnan(temperatura)) {
|
||||
Serial.println("[DHT] Erro na leitura!");
|
||||
umidade = 0.0;
|
||||
temperatura = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void read_MQ2()
|
||||
{
|
||||
iqAR = analogRead(MQ2PIN);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES - Detecção de alarmes
|
||||
// ============================================================================
|
||||
// Detecta padrão de possível incêndio: aumento de temperatura > 5°C + queda de umidade > 10% em 30 segundos
|
||||
void detect_fire()
|
||||
{
|
||||
// Inicializa janela de monitoramento na primeira chamada
|
||||
if (temp_inicio == 0.0) {
|
||||
temp_inicio = temperatura;
|
||||
umidade_inicio = umidade;
|
||||
timestamp_inicio = now.secondstime();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calcula tempo decorrido
|
||||
uint32_t tempo_decorrido = now.secondstime() - timestamp_inicio;
|
||||
|
||||
// Verifica padrão de incêndio a cada 30 segundos
|
||||
if (tempo_decorrido >= JANELA_TEMPO_INCENDIO) {
|
||||
float delta_temp = temperatura - temp_inicio;
|
||||
float delta_umidade = umidade - umidade_inicio;
|
||||
|
||||
// Debug: exibe deltas
|
||||
Serial.print("[INCENDIO] ΔT: ");
|
||||
Serial.print(delta_temp);
|
||||
Serial.print("°C | ΔUmidade: ");
|
||||
Serial.print(delta_umidade);
|
||||
Serial.println("%");
|
||||
|
||||
// Verifica condições críticas
|
||||
if (delta_temp > DELTA_TEMP_INCENDIO && delta_umidade < DELTA_UMIDADE_INCENDIO) {
|
||||
Serial.println("[ALERTA] INCÊNDIO DETECTADO!");
|
||||
alarmStatus = INCENDIO;
|
||||
}
|
||||
|
||||
// Reseta janela
|
||||
temp_inicio = temperatura;
|
||||
umidade_inicio = umidade;
|
||||
timestamp_inicio = now.secondstime();
|
||||
}
|
||||
}
|
||||
|
||||
// Verifica qual alarme deve ser ativado baseado nos limites
|
||||
void check_alarm()
|
||||
{
|
||||
// Atualiza RTC
|
||||
now = RTC.now();
|
||||
|
||||
// Detecção de incêndio (máxima prioridade)
|
||||
detect_fire();
|
||||
if (alarmStatus == INCENDIO) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Verifica gás
|
||||
if (alarmStatus == GAS) {
|
||||
if (iqAR <= GAS_OFF) {
|
||||
alarmStatus = NOMINAL;
|
||||
}
|
||||
} else if (iqAR > GAS_ON) {
|
||||
alarmStatus = GAS;
|
||||
return;
|
||||
}
|
||||
|
||||
// Verifica umidade
|
||||
if (alarmStatus == UMIDADE_ALTA) {
|
||||
if (umidade <= UMIDADE_OFF) {
|
||||
alarmStatus = NOMINAL;
|
||||
}
|
||||
} else if (umidade > UMIDADE_ON) {
|
||||
alarmStatus = UMIDADE_ALTA;
|
||||
return;
|
||||
}
|
||||
|
||||
// Verifica temperatura
|
||||
if (alarmStatus == TEMP_ALTA) {
|
||||
if (temperatura <= TEMP_OFF) {
|
||||
alarmStatus = NOMINAL;
|
||||
}
|
||||
} else if (temperatura > TEMP_ON) {
|
||||
alarmStatus = TEMP_ALTA;
|
||||
return;
|
||||
}
|
||||
|
||||
// Nenhum alarme ativo
|
||||
if (alarmStatus != GAS && alarmStatus != UMIDADE_ALTA
|
||||
&& alarmStatus != TEMP_ALTA) {
|
||||
alarmStatus = NOMINAL;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES - Leitura e publicação
|
||||
// ============================================================================
|
||||
// Realiza leitura de todos os sensores e publica dados via MQTT
|
||||
void leitura_sensores()
|
||||
{
|
||||
read_DHT();
|
||||
read_MQ2();
|
||||
|
||||
// Formata e publica via MQTT
|
||||
snprintf(msg, sizeof(msg),
|
||||
"{\"tmp\": %.2f, \"umi\": %.2f, \"gas\": %d, \"alarme\": %d}",
|
||||
temperatura, umidade, iqAR, alarmStatus);
|
||||
Serial.print("[MQTT] Publicando: ");
|
||||
Serial.println(msg);
|
||||
mqtt.publish(MQTT_PUB_TOPIC, msg);
|
||||
|
||||
// Verifica alarmes
|
||||
check_alarm();
|
||||
}
|
||||
|
||||
// Processa ativação de periféricos baseado no alarme
|
||||
void processa_alarme()
|
||||
{
|
||||
// Desativa todos antes de processar
|
||||
digitalWrite(ALARME_SONORO, LOW);
|
||||
digitalWrite(COIFA, LOW);
|
||||
digitalWrite(AR_CONDICIONADO, LOW);
|
||||
|
||||
if (alarmStatus == NOMINAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ativa periféricos conforme alarme
|
||||
switch (alarmStatus) {
|
||||
case INCENDIO:
|
||||
digitalWrite(ALARME_SONORO, HIGH);
|
||||
digitalWrite(COIFA, HIGH);
|
||||
digitalWrite(AR_CONDICIONADO, HIGH);
|
||||
Serial.println("[ALARME] INCÊNDIO!");
|
||||
break;
|
||||
case GAS:
|
||||
digitalWrite(ALARME_SONORO, HIGH);
|
||||
digitalWrite(COIFA, HIGH);
|
||||
Serial.println("[ALARME] GÁS DETECTADO!");
|
||||
break;
|
||||
case UMIDADE_ALTA:
|
||||
digitalWrite(COIFA, HIGH);
|
||||
Serial.println("[ALARME] UMIDADE ALTA!");
|
||||
break;
|
||||
case TEMP_ALTA:
|
||||
digitalWrite(AR_CONDICIONADO, HIGH);
|
||||
Serial.println("[ALARME] TEMPERATURA ALTA!");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES - Inicialização
|
||||
// ============================================================================
|
||||
void rtc_setup()
|
||||
{
|
||||
if (!RTC.begin()) {
|
||||
Serial.println("[RTC] Erro: não encontrado!");
|
||||
while (1)
|
||||
delay(1000);
|
||||
}
|
||||
Serial.println("[RTC] Inicializado");
|
||||
}
|
||||
|
||||
// Inicializa o ESP32 e configura os periféricos
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
delay(100);
|
||||
|
||||
Serial.println("\n[SETUP] Iniciando sistema...");
|
||||
|
||||
// Inicializa DHT
|
||||
dht.begin();
|
||||
Serial.println("[DHT] Inicializado");
|
||||
|
||||
// Gera ID único MQTT
|
||||
snprintf(MQTT_CLIENTID, sizeof(MQTT_CLIENTID), "esp32_%08X",
|
||||
(uint32_t)(ESP.getEfuseMac() & 0xFFFFFFFF));
|
||||
|
||||
// Configura ADC
|
||||
analogReadResolution(10);
|
||||
|
||||
// Configura pinos
|
||||
pinMode(ALARME_SONORO, OUTPUT);
|
||||
pinMode(COIFA, OUTPUT);
|
||||
pinMode(AR_CONDICIONADO, OUTPUT);
|
||||
pinMode(MQ2PIN, INPUT);
|
||||
pinMode(DHTPIN, INPUT);
|
||||
|
||||
// Desativa todos os atuadores
|
||||
digitalWrite(ALARME_SONORO, LOW);
|
||||
digitalWrite(COIFA, LOW);
|
||||
digitalWrite(AR_CONDICIONADO, LOW);
|
||||
|
||||
// Conecta
|
||||
connectWiFi();
|
||||
connectMQTT();
|
||||
rtc_setup();
|
||||
|
||||
// Primeira leitura
|
||||
now = RTC.now();
|
||||
leitura_sensores();
|
||||
|
||||
Serial.println("[SETUP] Pronto!\n");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LOOP PRINCIPAL
|
||||
// ============================================================================
|
||||
// Loop principal - executa continuamente
|
||||
void loop()
|
||||
{
|
||||
// Verifica MQTT
|
||||
if (!mqtt.connected()) {
|
||||
connectMQTT();
|
||||
}
|
||||
mqtt.loop();
|
||||
|
||||
// Lê sensores
|
||||
leitura_sensores();
|
||||
|
||||
// Processa alarme
|
||||
processa_alarme();
|
||||
|
||||
// Aguarda 2 segundos
|
||||
unsigned long start = millis();
|
||||
while (millis() - start < 2000UL) {
|
||||
mqtt.loop();
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user