#include <WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(5, 21, 23, 22, 26, 13); //RS,E,D5,D6,D7,D8 diğer uçlar ve R/W GND
//1 -> 26 , 3 -> 13 kullanıldı
// WiFi ve MQTT Bilgileri
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqttServer = "151.250.232.129";
const char* mqtt_user = "";
const char* mqtt_pass = "";
const int port = 1883;
// Pin Tanımlamaları
const int pinGreen = 32;
const int doorSensorPin = 34;
const int wifiStatus = 2;
const int onhook = 36;
const int ahize_kapat = 25;
// MT8870 DTMF Pinleri
const int Q1 = 16;
const int Q2 = 17;
const int Q3 = 18;
const int Q4 = 19;
const int StD = 15;
char keys[16] = {
'1', '2', '3', 'A',
'4', '5', '6', 'B',
'7', '8', '9', 'C',
'*', '0', '#', 'D'
};
// DTMF Değişkenleri
volatile bool yeniTusVar = false;
volatile bool buton_basili = 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"}, {"0102", "A12", "A1", "2"}, {"0103", "A13", "A1", "3"}, {"0104", "A14", "A1", "4"},
{"0105", "A15", "A1", "5"}, {"0106", "A16", "A1", "6"}, {"0107", "A17", "A1", "7"}, {"0108", "A18", "A1", "8"},
{"0201", "A21", "A2", "1"}, {"0202", "A22", "A2", "2"}, {"0203", "A23", "A2", "3"}, {"0204", "A24", "A2", "4"},
{"0205", "A25", "A2", "5"}, {"0206", "A26", "A2", "6"}, {"0207", "A27", "A2", "7"}, {"0208", "A28", "A2", "8"},
{"0301", "B11", "B1", "1"}, {"0302", "B12", "B1", "2"}, {"0303", "B13", "B1", "3"}, {"0304", "B14", "B1", "4"},
{"0305", "B15", "B1", "5"}, {"0306", "B16", "B1", "6"}, {"0307", "B17", "B1", "7"}, {"0308", "B18", "B1", "8"},
{"0401", "B21", "B2", "1"}, {"0402", "B22", "B2", "2"}, {"0403", "B23", "B2", "3"}, {"0404", "B24", "B2", "4"},
{"0405", "B25", "B2", "5"}, {"0406", "B26", "B2", "6"}, {"0407", "B27", "B2", "7"}, {"0408", "B28", "B2", "8"},
{"0501", "C11", "C1", "1"}, {"0502", "C12", "C1", "2"}, {"0503", "C13", "C1", "3"}, {"0504", "C14", "C1", "4"},
{"0505", "C15", "C1", "5"}, {"0506", "C16", "C1", "6"}, {"0507", "C17", "C1", "7"}, {"0508", "C18", "C1", "8"},
{"0601", "C21", "C2", "1"}, {"0602", "C22", "C2", "2"}, {"0603", "C23", "C2", "3"}, {"0604", "C24", "C2", "4"},
{"0605", "C25", "C2", "5"}, {"0606", "C26", "C2", "6"}, {"0607", "C27", "C2", "7"}, {"0608", "C28", "C2", "8"},
{"0701", "D11", "D1", "1"}, {"0702", "D12", "D1", "2"}, {"0703", "D13", "D1", "3"}, {"0704", "D14", "D1", "4"},
{"0705", "D15", "D1", "5"}, {"0706", "D16", "D1", "6"}, {"0707", "D17", "D1", "7"}, {"0708", "D18", "D1", "8"},
{"0801", "D21", "D2", "1"}, {"0802", "D22", "D2", "2"}, {"0803", "D23", "D2", "3"}, {"0804", "D24", "D2", "4"},
{"0805", "D25", "D2", "5"}, {"0806", "D26", "D2", "6"}, {"0807", "D27", "D2", "7"}, {"0808", "D28", "D2", "8"}
};
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
hw_timer_t *timer = NULL;
volatile bool timerFlag = false;
//volatile bool buton_basili=false;
int tusa_basma_suresi=0;
int tusa_basma_suresi_max=3;
volatile bool ahizeSifirlaIstegi = false;
int oncekiOnhookDurumu = HIGH;
volatile uint8_t onHookBasmaSayisi = 0;
void IRAM_ATTR stdInterrupt() {
if (digitalRead(StD) == HIGH) { yeniTusVar = true; }
//if (digitalRead(onhook) == LOW) buton_basili = true;
}
void IRAM_ATTR onTimer() {
int simdikiDurum = digitalRead(onhook);
// 1. Daire arama / ahize sıfırlama kontrolü (Ahize butonuna yeni basıldı mı?)
if (oncekiOnhookDurumu == HIGH && simdikiDurum == LOW) {
// Butona basıldı anı (Falling Edge)
ahizeSifirlaIstegi = true;
onHookBasmaSayisi++;
}
oncekiOnhookDurumu = simdikiDurum;
// 2. Mevcut ESP32 Restart (Uzun basma) sayacı mantığı
if (!simdikiDurum && (tusa_basma_suresi < tusa_basma_suresi_max)) {
tusa_basma_suresi++;
}
if (simdikiDurum) {
tusa_basma_suresi = 0;
}
if (tusa_basma_suresi >= tusa_basma_suresi_max) {
ESP.restart();
}
}
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);
}
else if (wifiOk && !mqttOk) {
if (millis() - lastLedBlinkTime >= 250) {
lastLedBlinkTime = millis();
ledState = !ledState;
digitalWrite(wifiStatus, ledState);
}
}
else {
digitalWrite(wifiStatus, LOW);
}
}
void lcdDefaultEkran() {
/*
lcd.clear();
lcd.setCursor(0, 0); lcd.print("Daire Numarasini");
lcd.setCursor(0, 1); lcd.print(" aramak icin ");
delay(1000);
lcd.setCursor(0, 0); lcd.print(" YESiL BUTONA ");
lcd.setCursor(0, 1); lcd.print(" BASIN ");
delay(1000);
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("HOSGELDiNiZ");
delay(2000);*/
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Blk + 5sn + D.No");
lcd.setCursor(0, 1);
lcd.print("Daire No: ");
delay(300);
lcd.setCursor(0, 0);
lcd.print("Blk + + D.No");
lcd.setCursor(0, 1);
lcd.print("Daire No: ");
delay(300);
}
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");
}
}
}
void setup() {
Serial.begin(115200);
snprintf(clientId, sizeof(clientId), "ESP32-%ld", random(1000000));
timer = timerBegin(1000000);
timerAttachInterrupt(timer, &onTimer);
timerAlarm(timer, 1000000, true, 0);
pinMode(pinGreen, OUTPUT);
digitalWrite(pinGreen, LOW);
pinMode(doorSensorPin, INPUT);
pinMode(wifiStatus, OUTPUT);
pinMode(Q1, INPUT_PULLDOWN);
pinMode(Q2, INPUT_PULLDOWN);
pinMode(Q3, INPUT_PULLDOWN);
pinMode(Q4, INPUT_PULLDOWN);
pinMode(StD, INPUT_PULLDOWN);
pinMode(onhook, INPUT);
pinMode(ahize_kapat, OUTPUT);
attachInterrupt(digitalPinToInterrupt(StD), stdInterrupt, RISING);
//attachInterrupt(digitalPinToInterrupt(onhook), stdInterrupt, FALLING);
lcd.begin(16, 2);
//lcdDefaultEkran();
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
// --- KRİTİK EKLENEN OPTİMİZASYONLAR ---
client.setServer(mqttServer, port);
client.setCallback(callback);
client.setKeepAlive(5); // Keep-alive süresini 5 saniyeye düşür
client.setSocketTimeout(1); // Soket zaman aşımını 1 saniyeye çek (bloklamayı önler)
digitalWrite(ahize_kapat, HIGH);
delay(3000);
digitalWrite(ahize_kapat, LOW);
delay(100);
}
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 && onHookBasmaSayisi) {
delay(50); // Debounce süresi 200ms'den 50ms'ye indirildi (Hızlı tepki için)
int sayi = (digitalRead(Q4) << 3) | (digitalRead(Q3) << 2) | (digitalRead(Q2) << 1) | digitalRead(Q1);
//char tus = dtmfToChar(sayi);
char tus = keys[sayi];
yeniTusVar = false;
if (tus == ' ') return;
// Geçerli bir tuş basıldı; 25 saniyelik zamanlayıcıyı tazeleyin
daireSecimZamani = millis();
Serial.print("Tuşlandı: "); Serial.println(tus);
if (secilenDaireIndex != -1) {
if (tus == '#') {
digitalWrite(pinGreen, HIGH);
relayTimer.once(1.5, turnOffRelay);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Kapi Acildi!");
delay(2000);
girilenRakamlar = "";
secilenDaireIndex = -1;
lcdDefaultEkran();
}
else if (tus == '*') {
buton_basili=false;
girilenRakamlar = "";
secilenDaireIndex = -1;
lcdDefaultEkran();
}
return;
}
if (tus >= '0' && tus <= '9') {
girilenRakamlar += tus;
lcd.setCursor(0, 1);
lcd.print("Daire No: " + girilenRakamlar + " ");
if (girilenRakamlar.length() == 4) {
daireyiBulVeIslemYap(girilenRakamlar);
}
}
else if (tus == '*') {
girilenRakamlar = "";
lcdDefaultEkran();
} else if (tus == '#') {
digitalWrite(pinGreen, HIGH);
relayTimer.once(1.5, turnOffRelay);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Kapi Acildi!");
delay(2000);
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();
if (WiFi.status() == WL_CONNECTED && client.connected()) {
char tpc[50];
snprintf(tpc, sizeof(tpc), "daire/%s/open", daireListesi[i].mqttEtiketi.c_str());
client.publish(tpc, "DING");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(daireListesi[i].blok + " Blok D:" + daireListesi[i].daireNo);
lcd.setCursor(0, 1);
lcd.print("Zil caliniyor...");
delay(2000);
girilenRakamlar = "";
//lcdDefaultEkran();
}
else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(daireListesi[i].blok + " Blok D:" + daireListesi[i].daireNo);
lcd.setCursor(0, 1);
lcd.print("Zil caliniyor...");
}
break;
}
}
if (!bulundu) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tanimsiz Daire!");
delay(2000);
girilenRakamlar = "";
lcdDefaultEkran();
}
}
void onHookStatus(){
unsigned long currentMillis = millis();
if (currentMillis - daireSecimZamani >= daireSecimZorunluSure) {
digitalWrite(ahize_kapat, HIGH);
delay(500);
digitalWrite(ahize_kapat, LOW);
delay(200);
}
}
void loop() {
unsigned long currentMillis = millis();
if (onHookBasmaSayisi == 2) {
ahizeSifirlaIstegi = false; // Bayrağı indir
onHookBasmaSayisi = 0;
// Sıfırlama işlemleri
girilenRakamlar = "";
secilenDaireIndex = -1;
buton_basili = false;
// Röle veya ahize kapatma tetiklemesi gerekiyorsa (isteğe bağlı kısa röle darbesi)
digitalWrite(ahize_kapat, HIGH);
delay(200);
digitalWrite(ahize_kapat, LOW);
lcdDefaultEkran();
Serial.println("Ahize butonuna basılarak ekran ve girişler sıfırlandı.");
} else if (onHookBasmaSayisi == 1 && ahizeSifirlaIstegi) {
Serial.println("Tuşla...!");
ahizeSifirlaIstegi = false;
}
if (girilenRakamlar.length() > 0 || secilenDaireIndex != -1) {
if (currentMillis - daireSecimZamani >= daireSecimZorunluSure) {
girilenRakamlar = "";
secilenDaireIndex = -1;
digitalWrite(ahize_kapat, HIGH);
delay(3000);
digitalWrite(ahize_kapat, LOW);
delay(100);
lcdDefaultEkran();
Serial.println("25 sn süre doldu: Daire seçim ekranı zaman aşımına uğradı.");
}
}
if (girilenRakamlar.length() == 0 && secilenDaireIndex == -1) {
lcd.setCursor(0, 0); lcd.print("Daire Numarasini");
lcd.setCursor(0, 1); lcd.print(" aramak icin ");
delay(1000);
lcd.setCursor(0, 0); lcd.print(" YESiL BUTONA ");
lcd.setCursor(0, 1); lcd.print(" BASIN ");
delay(1000);
}
if(girilenRakamlar.length() > 0 && secilenDaireIndex == -1) {
lcd.setCursor(0, 0);
lcd.print("Blk + + D.No");
lcd.setCursor(0, 1);
lcd.print("Daire No: ");
delay(300);
lcd.setCursor(0, 0);
lcd.print("Blk + 5sn + D.No");
lcd.setCursor(0, 1);
lcd.print("Daire No: ");
delay(300);
}
if (WiFi.status() == WL_CONNECTED) {
if (!client.connected()) {
mqttReconnect();
}
client.loop(); // Ağ trafiğini işler
} else {
if (currentMillis - lastWifiCheck >= wifiInterval) {
lastWifiCheck = currentMillis;
WiFi.begin(ssid, password);
}
}
updateStatusLED();
checkDTMF();
//if (digitalRead(onhook) == LOW) {delay(3000); secilenDaireIndex = -1; lcdDefaultEkran(); delay(1000); girilenRakamlar = "";}
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;
}
}KAPI DURUM SW
KAPI OMATİĞİ RÖLE
DTMF
WiFi-MQTT DURUM
ONHOOK BUTONU
AHİZE_KAPAT