#include <WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <MFRC522.h>
#include <DHT.h>
// ========== CONFIGURAÇÕES ==========
#define SSID "Wokwi-GUEST"
#define PASSWORD ""
#define MQTT_SERVER "broker.hivemq.com"
#define MQTT_PORT 1883
#define MQTT_TOPIC_SENSORES "iot/sensores"
#define MQTT_TOPIC_RFID "iot/rfid/acesso"
#define MQTT_TOPIC_COMANDOS "iot/rfid/comandos"
// Pinos
#define RST_PIN 4
#define SS_PIN 5
#define DHT_PIN 15
#define PIR_PIN 25
#define LED_VERDE 16
#define LED_VERMELHO 17
#define BUZZER 33
#define LED_INTERNO 12
#define LED_EXTERNO 13
#define GAS_PIN 34
#define LDR_PIN 35
#define DHTTYPE DHT22
#define LUZ_MAX 30000.0 // lux (acima disto desliga os LEDs, salvo eventos)
// Tempo que os LEDs permanecem acesos após evento (ms)
#define TEMPO_MOVIMENTO_MS 5000
#define TEMPO_RFID_MS 2000
// ========== GLOBAIS ==========
MFRC522 rfid(SS_PIN, RST_PIN);
DHT dht(DHT_PIN, DHTTYPE);
WiFiClient espClient;
PubSubClient client(espClient);
// UIDs autorizados
byte uidBlue[4] = {0xDE, 0xAD, 0xBE, 0xEF}; // Blue Card
byte uidGreen[4] = {0x11, 0x22, 0x33, 0x44}; // Green Card
// Controlo de temporizadores
unsigned long tempoUltimoMovimento = 0;
unsigned long tempoUltimoRFID = 0;
// ========== FUNÇÕES ==========
void setup_wifi() {
delay(10);
Serial.print("Conectando ao WiFi");
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi conectado!");
}
void callback(char* topic, byte* payload, unsigned int length) {
String msg;
for (int i = 0; i < length; i++) msg += (char)payload[i];
if (msg == "LIGAR_LED_EXTERNO") digitalWrite(LED_EXTERNO, HIGH);
else if (msg == "DESLIGAR_LED_EXTERNO") digitalWrite(LED_EXTERNO, LOW);
}
void reconnect() {
while (!client.connected()) {
if (client.connect("ESP32_RFID_ACESSO")) {
client.subscribe(MQTT_TOPIC_COMANDOS);
} else {
delay(5000);
}
}
}
float analogToLux(int valor) {
return (valor / 4095.0) * 100000.0;
}
// Controla os LEDs brancos (interno e externo) conforme:
// - Eventos (movimento ou RFID) ligam-nos temporariamente.
// - Se não houver eventos recentes, segue a regra do LDR.
void controlarLEDsBrancos(float lux, bool movimentoDetectado, bool rfidOcorreu) {
unsigned long agora = millis();
// Actualiza timers com base nos eventos actuais
if (movimentoDetectado) {
tempoUltimoMovimento = agora;
}
if (rfidOcorreu) {
tempoUltimoRFID = agora;
}
// Decide estado do LED interno: ligado se movimento recente OU (lux baixo e sem movimento)
bool ligarInterno = false;
if (agora - tempoUltimoMovimento < TEMPO_MOVIMENTO_MS) {
ligarInterno = true; // movimento recente -> acende LED interno
} else if (lux <= LUZ_MAX) {
ligarInterno = true; // pouca luz -> acende LED interno
}
// Decide estado do LED externo: ligado se RFID recente OU (lux baixo e sem RFID)
bool ligarExterno = false;
if (agora - tempoUltimoRFID < TEMPO_RFID_MS) {
ligarExterno = true; // tentativa de RFID recente -> acende LED externo
} else if (lux <= LUZ_MAX) {
ligarExterno = true; // pouca luz -> acende LED externo
}
digitalWrite(LED_INTERNO, ligarInterno ? HIGH : LOW);
digitalWrite(LED_EXTERNO, ligarExterno ? HIGH : LOW);
// Mensagens de depuração (opcional)
if (movimentoDetectado) Serial.println("Movimento: LED interno aceso por 5s");
if (rfidOcorreu) Serial.println("RFID: Presença na Porta!");
}
bool isAuthorized(byte *uid, byte size) {
if (size == 4) {
if (memcmp(uid, uidBlue, 4) == 0) return true;
if (memcmp(uid, uidGreen, 4) == 0) return true;
}
return false;
}
void grantAccess() {
digitalWrite(LED_VERDE, HIGH);
tone(BUZZER, 5000, 500);
delay(800);
digitalWrite(LED_VERDE, LOW);
}
void denyAccess() {
digitalWrite(LED_VERMELHO, HIGH);
tone(BUZZER, 500, 1000);
delay(800);
digitalWrite(LED_VERMELHO, LOW);
}
void setup() {
Serial.begin(115200);
pinMode(LED_VERDE, OUTPUT);
pinMode(LED_VERMELHO, OUTPUT);
pinMode(BUZZER, OUTPUT);
pinMode(LED_INTERNO, OUTPUT);
pinMode(LED_EXTERNO, OUTPUT);
pinMode(PIR_PIN, INPUT);
pinMode(GAS_PIN, INPUT);
pinMode(LDR_PIN, INPUT);
// Inicialmente LEDs apagados (serão ligados pela lógica do LDR)
digitalWrite(LED_INTERNO, LOW);
digitalWrite(LED_EXTERNO, LOW);
SPI.begin(18, 19, 23, SS_PIN);
rfid.PCD_Init();
dht.begin();
setup_wifi();
client.setServer(MQTT_SERVER, MQTT_PORT);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) reconnect();
client.loop();
// --- Leitura de sensores (a cada 2 segundos) ---
static unsigned long lastSensor = 0;
if (millis() - lastSensor > 1000) {
lastSensor = millis();
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (isnan(temp)) temp = 0;
if (isnan(hum)) hum = 0;
int gas = analogRead(GAS_PIN);
int ldrValue = analogRead(LDR_PIN);
float lux = analogToLux(ldrValue);
bool movimento = digitalRead(PIR_PIN);
// Controla LEDs (passa também movimento para ligar temporariamente)
// Neste ponto, rfidOcorreu = false (será tratado mais à frente se houver RFID)
controlarLEDsBrancos(lux, movimento, false);
// Publica dados dos sensores
char payload[250];
snprintf(payload, sizeof(payload),
"{\"temp\":%.1f,\"hum\":%.1f,\"gas\":%d,\"lux\":%.1f,\"movimento\":%d}",
temp, hum, gas, lux, movimento);
client.publish(MQTT_TOPIC_SENSORES, payload);
Serial.print("Sensores enviados: ");
Serial.println(payload);
}
// --- Leitura RFID ---
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
Serial.print("UID lido: ");
for (byte i = 0; i < rfid.uid.size; i++) {
Serial.print(rfid.uid.uidByte[i], HEX);
Serial.print(" ");
}
Serial.println();
bool autorizado = isAuthorized(rfid.uid.uidByte, rfid.uid.size);
if (autorizado) {
grantAccess();
client.publish(MQTT_TOPIC_RFID, "{\"status\":\"autorizado\",\"usuario\":\"Autorizado\"}");
} else {
denyAccess();
client.publish(MQTT_TOPIC_RFID, "{\"status\":\"negado\",\"usuario\":\"Desconhecido\"}");
}
// Força a atualização do LED externo devido ao evento RFID
// Relê o LDR para obter lux actual e chama controlo com rfidOcorreu = true
int ldrValue = analogRead(LDR_PIN);
float lux = analogToLux(ldrValue);
bool movimento = digitalRead(PIR_PIN);
controlarLEDsBrancos(lux, movimento, true); // evento RFID
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
delay(500);
}
}