#include <WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// WiFi ve MQTT Bilgileri
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqttServer = "151.250.232.219";
const char* mqtt_user = "";
const char* mqtt_pass = "";
const int port = 1883;
// Pin Tanımlamaları
const int pinGreen = 16;
const int doorSensorPin = 15;
const int wifiStatus = 2;
// MT8870 DTMF Pinleri
const int Q1 = 33;
const int Q2 = 32;
const int Q3 = 13;
const int Q4 = 12;
const int StD = 26;
// DTMF Değişkenleri
volatile bool yeniTusVar = false;
String girilenRakamlar = "";
int secilenDaireIndex = -1;
// Daire Seçim Zamanlayıcısı Değişkenleri
unsigned long daireSecimZamani = 0;
const unsigned long daireSecimZorunluSure = 25000; // 25 saniye LCD TIMEOUT
// Daire Tanımlamaları
struct Daire {
String tuslananKod;
String mqttEtiketi;
String blok;
String daireNo;
};
Daire daireListesi[] = {
{"0101", "A11", "A1", "1"},
{"1220", "A21", "A2", "1"},
{"1230", "B11", "B1", "1"},
{"0124", "A21", "A2", "1"},
{"2011", "C11", "C1", "1"}
};
const int daireSayisi = sizeof(daireListesi) / sizeof(daireListesi[0]);
char clientId[50];
WiFiClient espClient;
PubSubClient client(espClient);
Ticker relayTimer;
unsigned long lastPublishTime = 0;
const long interval = 2000;
bool lastSentState = HIGH;
// Status LED için Zamanlayıcı Değişkenleri
unsigned long lastLedBlinkTime = 0;
bool ledState = LOW;
// Wi-Fi bağlantı denemesi için zamanlayıcılar
unsigned long lastWifiCheck = 0;
const unsigned long wifiInterval = 10000; // 10 saniyede bir bağlanmayı dene
void IRAM_ATTR stdInterrupt() {
yeniTusVar = true;
}
void turnOffRelay() {
digitalWrite(pinGreen, LOW);
Serial.println("Zaman Doldu: Röle otomatik KAPATILDI");
if (WiFi.status() == WL_CONNECTED && client.connected()) {
client.publish("role/lock", "OFF");
}
}
void updateStatusLED() {
bool wifiOk = (WiFi.status() == WL_CONNECTED);
bool mqttOk = client.connected();
if (wifiOk && mqttOk) {
digitalWrite(wifiStatus, HIGH); // Wi-Fi ve MQTT Bağlı -> Sürekli YANAR
}
else if (wifiOk && !mqttOk) {
// Sadece Wi-Fi Bağlı -> Yanıp Söner (250ms aralıkla)
if (millis() - lastLedBlinkTime >= 250) {
lastLedBlinkTime = millis();
ledState = !ledState;
digitalWrite(wifiStatus, ledState);
}
}
else {
digitalWrite(wifiStatus, LOW); // İnternet yoksa -> SÖNÜK
}
}
void lcdDefaultEkran() {
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("HOSGELDiNiZ");
lcd.setCursor(0, 1);
lcd.print("Kod: ");
}
void setup() {
Serial.begin(115200);
snprintf(clientId, sizeof(clientId), "ESP32-%ld", random(1000000));
pinMode(pinGreen, OUTPUT);
digitalWrite(pinGreen, LOW);
pinMode(doorSensorPin, INPUT_PULLUP);
pinMode(wifiStatus, OUTPUT);
pinMode(Q1, INPUT_PULLDOWN);
pinMode(Q2, INPUT_PULLDOWN);
pinMode(Q3, INPUT_PULLDOWN);
pinMode(Q4, INPUT_PULLDOWN);
pinMode(StD, INPUT_PULLDOWN);
attachInterrupt(digitalPinToInterrupt(StD), stdInterrupt, RISING);
lcd.init();
lcd.backlight();
lcdDefaultEkran();
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); // İlk açılış denemesi
client.setServer(mqttServer, port);
client.setCallback(callback);
}
char dtmfToChar(int n) {
if (n == 10 || n == 0) return '0';
if (n >= 1 && n <= 9) return (char)(n + '0');
if (n == 11) return '*';
if (n == 12) return '#';
return ' ';
}
void checkDTMF() {
if (yeniTusVar) {
delay(200); // Debounce süresi
int sayi = (digitalRead(Q4) << 3) | (digitalRead(Q3) << 2) | (digitalRead(Q2) << 1) | digitalRead(Q1);
char tus = dtmfToChar(sayi);
yeniTusVar = false;
if (tus == ' ') return;
Serial.print("Tuşlandı: "); Serial.println(tus);
// İnternetsiz modda dairenin '*' tuşuna basmasını beklediğimiz aşama
if (secilenDaireIndex != -1) {
if (tus == '*') {
// --- YEREL KAPI AÇMA (İnternetsiz mod) ---
digitalWrite(pinGreen, HIGH);
relayTimer.once(1.5, turnOffRelay); // 1.5 saniye sonra otomatik kapat
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Kapi Acildi!");
delay(2000);
// Sıfırla
girilenRakamlar = "";
secilenDaireIndex = -1;
lcdDefaultEkran();
}
else if (tus == '#') {
// İptal Et
girilenRakamlar = "";
secilenDaireIndex = -1;
lcdDefaultEkran();
}
return;
}
// Normal Kod Girme Aşaması
if (tus >= '0' && tus <= '9') {
girilenRakamlar += tus;
lcd.setCursor(0, 1);
lcd.print("Kod: " + girilenRakamlar + " ");
if (girilenRakamlar.length() == 4) {
daireyiBulVeIslemYap(girilenRakamlar);
}
}
else if (tus == '#') {
// Temizle
girilenRakamlar = "";
lcdDefaultEkran();
} else if (tus == '*') {
// --- HER DURUMDA KAPI AÇMA (DTMF)---
digitalWrite(pinGreen, HIGH);
relayTimer.once(1.5, turnOffRelay); // 1.5 saniye sonra otomatik kapat
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Kapi Acildi!");
delay(2000);
// Sıfırla
girilenRakamlar = "";
secilenDaireIndex = -1;
lcdDefaultEkran();
}
}
}
void daireyiBulVeIslemYap(String kod) {
bool bulundu = false;
for (int i = 0; i < daireSayisi; i++) {
if (daireListesi[i].tuslananKod == kod) {
bulundu = true;
secilenDaireIndex = i;
daireSecimZamani = millis();
// KONTROL: İnternet ve MQTT bağlı mı?
if (WiFi.status() == WL_CONNECTED && client.connected()) {
// İNTERNET VAR: Direkt MQTT topic gönder, * bekleme
char tpc[50];
sprintf(tpc, "daire/%s/open", daireListesi[i].mqttEtiketi.c_str());
client.publish(tpc, "DING");
//daireSecimZamani = millis(); // 25 saniyelik sayacı başlat
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(daireListesi[i].blok + " Blk D:" + daireListesi[i].daireNo);
lcd.setCursor(0, 1);
lcd.print("Zil caliniyor...");
delay(2000);
// Sıfırla ve ana ekrana dön
girilenRakamlar = "";
}
else {
// İNTERNET YOK: '*' tuşunu beklemek üzere indexi ve zamanı kaydet
// secilenDaireIndex = i;
// daireSecimZamani = millis(); // 25 saniyelik sayacı başlat
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(daireListesi[i].blok + " Blk D:" + daireListesi[i].daireNo);
lcd.setCursor(0, 1);
lcd.print("* Bekleniyor...");
}
break;
}
}
if (!bulundu) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tanimsiz Daire!");
delay(2000);
girilenRakamlar = "";
lcdDefaultEkran();
}
}
void loop() {
unsigned long currentMillis = millis();
// Seçilen daire için 25 saniye zaman aşımı kontrolü
if (secilenDaireIndex != -1) {
if (currentMillis - daireSecimZamani >= daireSecimZorunluSure) {
girilenRakamlar = "";
secilenDaireIndex = -1;
lcdDefaultEkran();
Serial.println("25 sn süre doldu: Daire seçim ekranı zaman aşımına uğradı.");
}
}
if (WiFi.status() == WL_CONNECTED) {
if (!client.connected()) {
mqttReconnect();
}
client.loop();
} else {
// Wi-Fi kopuksa belirli aralıklarla yeniden bağlanmayı dene
if (currentMillis - lastWifiCheck >= wifiInterval) {
lastWifiCheck = currentMillis;
WiFi.begin(ssid, password);
}
}
updateStatusLED();
checkDTMF();
// Kapı Sensörü Mantığı (Sadece internet/MQTT bağlıysa veri gönder)
bool currentDoorState = digitalRead(doorSensorPin);
if (currentDoorState == LOW) {
if (currentMillis - lastPublishTime >= interval) {
lastPublishTime = currentMillis;
if (WiFi.status() == WL_CONNECTED && client.connected()) {
client.publish("door/status", "DOOROPEN");
}
lastSentState = LOW;
}
}
else if (currentDoorState == HIGH && lastSentState == LOW) {
if (WiFi.status() == WL_CONNECTED && client.connected()) {
client.publish("door/status", "DOORCLOSE");
}
lastSentState = HIGH;
}
}
void callback(char* topic, byte* message, unsigned int length) {
String payload = "";
for (unsigned int i = 0; i < length; i++) payload += (char)message[i];
if (payload == "ON") {
secilenDaireIndex = -1;
digitalWrite(pinGreen, HIGH);
Serial.println("Kapı Açıldı..");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Kapi Acildi!");
delay(2000);
lcdDefaultEkran();
relayTimer.once(1.5, turnOffRelay);
} else if (payload == "OFF") {
digitalWrite(pinGreen, LOW);
relayTimer.detach();
}
}
void mqttReconnect() {
static unsigned long lastReconnectAttempt = 0;
if (millis() - lastReconnectAttempt > 5000) {
lastReconnectAttempt = millis();
if (client.connect(clientId, mqtt_user, mqtt_pass)) {
client.subscribe("role/lock");
Serial.println("MQTT Bagli");
}
}
}KAPI DURUM SW
KAPI OMATİĞİ RÖLE
DTMF
WiFi-MQTT DURUM