#include <Keypad.h>
#include <Adafruit_NeoPixel.h>
#include <EEPROM.h>
// ==========================================
// 1. PİN VE DONANIM TANIMLAMALARI
// ==========================================
#define NEOPIXEL_PIN 10
#define MOTOR_YUKARI_PIN 11
#define MOTOR_ASAGI_PIN 12
#define SOKAK_LAMBA_PIN 13
#define UST_SINIR_PIN A0
#define ALT_SINIR_PIN A1
#define TOPLAM_LED 256
Adafruit_NeoPixel strip = Adafruit_NeoPixel(TOPLAM_LED, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
// ==========================================
// 2. RENK VE PROJE AYARLARI
// ==========================================
uint32_t RENK_KAPALI = strip.Color(0, 0, 0);
uint32_t RENK_1_GENEL = strip.Color(255, 200, 50); // Gün Işığı
uint32_t RENK_2_VURGU = strip.Color(255, 0, 0); // Kırmızı
uint32_t RENK_KURULUM = strip.Color(0, 255, 0); // Yeşil
// KAT VE DAİRE MANTIĞI
const int DAIRE_PER_KAT = 2; // Her katta 2 daire
const int BLOK_MAX_DAIRE = 16; // 8 kat x 2 daire = 16 daire
// ==========================================
// 3. TUŞ TAKIMI (KEYPAD) AYARLARI
// ==========================================
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// ==========================================
// 4. VERİTABANI YAPISI
// ==========================================
struct Daire { char blok; byte daireNo; char kategori; int ilkLed; int sonLed; };
Daire daireler[64];
const int TOPLAM_DAIRE = 64;
// ==========================================
// 5. SİSTEM DEĞİŞKENLERİ
// ==========================================
bool kurulumModu = false;
String tusHafizasi = "";
unsigned long sonIslemZamani = 0;
bool isHold = false;
int aktifAnimasyon = 0;
bool sokakLambaDurum = false;
bool motorCalisiyor = false;
int motorYon = 1;
// ==========================================
// 6. BAŞLANGIÇ (SETUP)
// ==========================================
void setup() {
Serial.begin(9600);
strip.begin();
strip.show();
pinMode(MOTOR_YUKARI_PIN, OUTPUT);
pinMode(MOTOR_ASAGI_PIN, OUTPUT);
pinMode(SOKAK_LAMBA_PIN, OUTPUT);
pinMode(UST_SINIR_PIN, INPUT_PULLUP);
pinMode(ALT_SINIR_PIN, INPUT_PULLUP);
keypad.addEventListener(keypadEvent);
keypad.setHoldTime(800);
// OTOMATİK VERİTABANI OLUŞTURUCU (4 Blok, 16'şar Daire, Toplam 64 Daire)
int ledIdx = 0;
char bloklar[] = {'A', 'B', 'C', 'D'};
for(int b=0; b<4; b++){
for(int d=1; d<=16; d++){
daireler[b*16 + d-1] = {bloklar[b], (byte)d, 'A', ledIdx, ledIdx+3};
ledIdx += 4;
}
}
// EEPROM Yüklemesi
for (int i = 0; i < TOPLAM_DAIRE; i++) {
byte kayitliKategori = EEPROM.read(i);
if (kayitliKategori != 255) daireler[i].kategori = kayitliKategori;
}
Serial.println("Sistem Hazir.");
}
// ==========================================
// 7. ANA DÖNGÜ (LOOP)
// ==========================================
void loop() {
keypad.getKey();
motorKontrol();
if(aktifAnimasyon > 0) animasyonOynat();
if (kurulumModu && (millis() - sonIslemZamani > 20000)) {
kurulumModu = false;
tusHafizasi = "";
tumBinayiYak(RENK_KAPALI);
Serial.println("Kurulum Modu Zaman Asimi! Cikildi.");
}
}
// ==========================================
// 8. TUŞ OLAYLARI (KISA / UZUN BASIM)
// ==========================================
void keypadEvent(KeypadEvent key){
switch (keypad.getState()){
case PRESSED:
isHold = false;
sonIslemZamani = millis();
break;
case HOLD:
isHold = true;
if (kurulumModu) break;
if (key >= 'A' && key <= 'D') {
aktifAnimasyon = 0;
kategoriGoster(key);
} else if (key >= '1' && key <= '9') {
tumBinayiYak(RENK_KAPALI);
aktifAnimasyon = key - '0';
Serial.println("Animasyon " + String(aktifAnimasyon) + " Basladi!");
} else if (key == '0') {
aktifAnimasyon = 0;
tumBinayiYak(RENK_KAPALI);
Serial.println("Tum komutlar iptal edildi. Sistem Kapatildi.");
}
tusHafizasi = "";
break;
case RELEASED:
if (!isHold) {
sonIslemZamani = millis();
if (key == '*') sokakLambasiToggle();
else if (key == '#') kareTusuIsle();
else {
tusHafizasi += key;
if (!kurulumModu && key >= 'A' && key <= 'D') {
aktifAnimasyon = 0;
String rakam = tusHafizasi.substring(0, tusHafizasi.length() - 1);
if (rakam.length() > 0) daireVurgula(key, rakam.toInt());
else blokToggle(key);
tusHafizasi = "";
}
}
}
break;
}
}
// ==========================================
// 9. YARDIMCI KONTROLLER
// ==========================================
void kareTusuIsle() {
if (tusHafizasi == "112118") {
kurulumModu = !kurulumModu;
aktifAnimasyon = 0;
tusHafizasi = "";
tumBinayiYak(kurulumModu ? RENK_KURULUM : RENK_KAPALI);
return;
}
if (kurulumModu) {
if (tusHafizasi.length() >= 3) {
char blok = tusHafizasi.charAt(0);
char yeniKat = tusHafizasi.charAt(tusHafizasi.length() - 1);
int daireNo = tusHafizasi.substring(1, tusHafizasi.length() - 1).toInt();
kurulumKaydet(blok, daireNo, yeniKat);
}
tusHafizasi = "";
} else {
if (tusHafizasi == "") {
motorCalisiyor = !motorCalisiyor;
Serial.println(motorCalisiyor ? "Motor Calisti." : "Motor Durduruldu.");
}
tusHafizasi = "";
}
}
void sokakLambasiToggle() {
sokakLambaDurum = !sokakLambaDurum;
digitalWrite(SOKAK_LAMBA_PIN, sokakLambaDurum ? HIGH : LOW);
}
void motorKontrol() {
if (motorCalisiyor) {
if (motorYon == 1) {
digitalWrite(MOTOR_YUKARI_PIN, HIGH);
digitalWrite(MOTOR_ASAGI_PIN, LOW);
if (digitalRead(UST_SINIR_PIN) == LOW) {
motorCalisiyor = false;
motorYon = -1;
}
} else {
digitalWrite(MOTOR_YUKARI_PIN, LOW);
digitalWrite(MOTOR_ASAGI_PIN, HIGH);
if (digitalRead(ALT_SINIR_PIN) == LOW) {
motorCalisiyor = false;
motorYon = 1;
}
}
} else {
digitalWrite(MOTOR_YUKARI_PIN, LOW);
digitalWrite(MOTOR_ASAGI_PIN, LOW);
}
}
// ==========================================
// 10. NEOPIXEL MANTIK VE ANİMASYONLARI
// ==========================================
void blokToggle(char blok) {
bool blokAcik = false;
for(int i=0; i<TOPLAM_DAIRE; i++) {
if(daireler[i].blok == blok && strip.getPixelColor(daireler[i].ilkLed) != 0) blokAcik = true;
}
int toplamKat = BLOK_MAX_DAIRE / DAIRE_PER_KAT;
if (!blokAcik) {
for (int k = 1; k <= toplamKat; k++) {
for(int i=0; i<TOPLAM_DAIRE; i++) {
if(daireler[i].blok == blok) {
int katNo = ((daireler[i].daireNo - 1) / DAIRE_PER_KAT) + 1;
if (katNo == k) for(int l=daireler[i].ilkLed; l<=daireler[i].sonLed; l++) strip.setPixelColor(l, RENK_1_GENEL);
}
}
strip.show();
delay(150);
}
} else {
for (int k = toplamKat; k >= 1; k--) {
for(int i=0; i<TOPLAM_DAIRE; i++) {
if(daireler[i].blok == blok) {
int katNo = ((daireler[i].daireNo - 1) / DAIRE_PER_KAT) + 1;
if (katNo == k) for(int l=daireler[i].ilkLed; l<=daireler[i].sonLed; l++) strip.setPixelColor(l, RENK_KAPALI);
}
}
strip.show();
delay(150);
}
}
}
void daireVurgula(char blok, int daireNo) {
for(int i=0; i<TOPLAM_DAIRE; i++) {
if(daireler[i].blok == blok && daireler[i].daireNo == daireNo) {
uint32_t mevcut = strip.getPixelColor(daireler[i].ilkLed);
if(mevcut == RENK_2_VURGU) {
bool blokAcik = false;
for(int j=0; j<TOPLAM_DAIRE; j++) {
if(daireler[j].blok == blok && strip.getPixelColor(daireler[j].ilkLed) == RENK_1_GENEL) blokAcik = true;
}
uint32_t hedef = blokAcik ? RENK_1_GENEL : RENK_KAPALI;
for(int l=daireler[i].ilkLed; l<=daireler[i].sonLed; l++) strip.setPixelColor(l, hedef);
} else {
for(int l=daireler[i].ilkLed; l<=daireler[i].sonLed; l++) strip.setPixelColor(l, RENK_2_VURGU);
}
strip.show();
break;
}
}
}
void kategoriGoster(char kategori) {
tumBinayiYak(RENK_KAPALI);
for (int i = 0; i < TOPLAM_DAIRE; i++) {
if (daireler[i].kategori == kategori) {
for (int l = daireler[i].ilkLed; l <= daireler[i].sonLed; l++) strip.setPixelColor(l, RENK_1_GENEL);
}
}
strip.show();
}
void kurulumKaydet(char blok, int daireNo, char yeniKat) {
for (int i = 0; i < TOPLAM_DAIRE; i++) {
if (daireler[i].blok == blok && daireler[i].daireNo == daireNo) {
EEPROM.update(i, yeniKat);
daireler[i].kategori = yeniKat;
for (int l = daireler[i].ilkLed; l <= daireler[i].sonLed; l++) strip.setPixelColor(l, RENK_2_VURGU);
strip.show(); delay(500);
for (int l = daireler[i].ilkLed; l <= daireler[i].sonLed; l++) strip.setPixelColor(l, RENK_KURULUM);
strip.show();
break;
}
}
}
void tumBinayiYak(uint32_t renk) {
for (int i = 0; i < TOPLAM_LED; i++) strip.setPixelColor(i, renk);
strip.show();
}
// Animasyonların iptal edilip edilmediğini kontrol eden güvenlik fonksiyonu
bool iptalKontrol() {
keypad.getKey();
return (aktifAnimasyon == 0);
}
// ==========================================
// 11. ÖZEL ANİMASYON ALANI (1-9 UZUN BASIM)
// ==========================================
void animasyonOynat() {
uint32_t renk1 = strip.Color(255, 0, 0);
uint32_t renk2 = strip.Color(0, 0, 255);
uint32_t renk3 = strip.Color(255, 255, 255);
switch(aktifAnimasyon) {
case 1: // RASTGELE YANIP SÖNME (Pırıltı)
strip.setPixelColor(random(TOPLAM_LED), RENK_1_GENEL);
strip.show(); delay(20);
strip.setPixelColor(random(TOPLAM_LED), RENK_KAPALI);
break;
case 2: // POLİS ÇAKARI (Kırmızı - Mavi)
for(int i=0; i<TOPLAM_LED; i+=2) strip.setPixelColor(i, renk1);
for(int i=1; i<TOPLAM_LED; i+=2) strip.setPixelColor(i, RENK_KAPALI);
strip.show(); delay(150); if(iptalKontrol()) break;
for(int i=0; i<TOPLAM_LED; i+=2) strip.setPixelColor(i, RENK_KAPALI);
for(int i=1; i<TOPLAM_LED; i+=2) strip.setPixelColor(i, renk2);
strip.show(); delay(150);
break;
case 3: // GÖKKUŞAĞI AKIŞI
static long ilkPixelHUE = 0;
for(int i=0; i<strip.numPixels(); i++) {
int pixelHue = ilkPixelHUE + (i * 65536L / strip.numPixels());
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
}
strip.show(); delay(10);
ilkPixelHUE += 256;
if(ilkPixelHUE >= 65536) ilkPixelHUE = 0;
break;
case 4: // Kayan Kırmızı Nokta (Yılan)
static int yilanPoz = 0;
tumBinayiYak(RENK_KAPALI);
for(int i=0; i<5; i++) strip.setPixelColor((yilanPoz+i)%TOPLAM_LED, renk1);
strip.show(); delay(30);
yilanPoz++; if(yilanPoz >= TOPLAM_LED) yilanPoz = 0;
break;
case 5: // NEFES ALAN IŞIK (Breathing)
static int parlaklik = 0;
static int yon = 5;
strip.setBrightness(parlaklik);
tumBinayiYak(RENK_1_GENEL);
parlaklik += yon;
if(parlaklik <= 0 || parlaklik >= 255) yon = -yon;
delay(20);
if(aktifAnimasyon == 0) strip.setBrightness(255); // Çıkarken parlaklığı düzelt
break;
case 6: // RENK SİLİCİ (Wipe)
static int wipeLed = 0;
static int durum = 0;
strip.setPixelColor(wipeLed, durum == 0 ? renk2 : RENK_KAPALI);
strip.show(); delay(10);
wipeLed++;
if(wipeLed >= TOPLAM_LED) { wipeLed = 0; durum = !durum; }
break;
case 7: // FLAŞÖR (Tüm Site Yan Sön)
tumBinayiYak(renk3); delay(100); if(iptalKontrol()) break;
tumBinayiYak(RENK_KAPALI); delay(100);
break;
case 8: // BLOK BLOK GEZİNME
static int aktifBlok = 0;
char b[] = {'A', 'B', 'C', 'D'};
tumBinayiYak(RENK_KAPALI);
for(int i=0; i<TOPLAM_DAIRE; i++) {
if(daireler[i].blok == b[aktifBlok]) {
for(int l=daireler[i].ilkLed; l<=daireler[i].sonLed; l++) strip.setPixelColor(l, RENK_1_GENEL);
}
}
strip.show(); delay(400);
aktifBlok++; if(aktifBlok > 3) aktifBlok = 0;
break;
case 9: // KARIŞIK RENKLER
for(int i=0; i<TOPLAM_LED; i++) {
strip.setPixelColor(i, strip.Color(random(255), random(255), random(255)));
}
strip.show(); delay(200);
break;
}
}