back to top

Uyanmanın En Akıllı Yolu: Akıllı Çalar Saat Projesi

Sabah alarm sesiyle uyanmak bir çile mi? Artık değil! Bu blog yazısında sizlere; hem Wi-Fi bağlantılı, hem Telegram’dan kontrol edilebilen, hem de LED’li gece lambasına dönüşebilen bir Akıllı Çalar Saat projesini tanıtıyoruz.

akıllı çalar saat

Sadece sıradan bir saat değil; tamamen programlanabilir bir uyanma deneyimi. Uyanmakta zorlanıyorsanız sürekli çalan alarmı susturmak için bir matematik sorusu çözmeniz gerekebilir, LED’ler sabaha özel animasyonlarla yanabilir, hatta önemli günlerde farklı renkler ve melodilerle sizi karşılayabilir. Üstelik tüm kontrol sizin elinizde.

Sabahlar sadece çalmakla kalmamalı, sizi motive de etmeli. Akıllı çalar saat projesi tam da bunu yapıyor. Güne enerjik, eğlenceli ve biraz da zeka dolu bir başlangıç sunuyor!

Kullanılan Malzemeler

ÜRÜN ADIÜRÜN KODU
6 mm x 14 mm Mini Kablolu Titreşim Motoru12856
Buzzer, 5V-12V, 12mm12267
Mini Sarhoş Teker Plastik – 2 Adet18103
NodeMCU V3 ESP8266 ESP-12E Kartı17202
TTP223 Tekli Dokunmatik Anahtar15422
GePro UM-55, 5 V 1 A Adaptör16827
10×10 cm Delikli Pertinaks17771
4 Pinli Push Buton – Siyah15702
Mini Anahtar – Siyah15661
0.96 inç I2C OLED Ekran – SSD130618504
WS2812 8’li Şerit Led16074
LM2596 Mini Ayarlanabilir Voltaj Regülatör Kartı11750

Projenin Özellikleri

  • Gerçek zamanlı saat bilgisi NTP sunucularından alınır.
  • OLED ekran sayesinde saat her an görünür.
  • WS2812 LED Şerit gece lambası olarak kullanılabilir.
  • Dokunmatik butonla LED kontrolü sağlanır. 
  • Farklı renk modlarıyla önemli olaylar için özel uyarılar verilebilir.
  • Telegram botu ile alarm kurulabilir, kapatılabilir.
  • Alarmı kapatmak için matematik sorusu çözme modu aktif edilebilir.

Devre Şeması

Projede NodeMCU ESP8266 kartı merkezde yer alıyor. NTP tabanlı saat bilgisi Wi-Fi üzerinden alınıyor ve OLED ekranda görüntüleniyor. WS2812 LED’ler renkli bildirimleri sağlarken, buzzer ve titreşim motoru alarm için sesli ve fiziksel uyarı veriyor.

akıllı çalar saat devre şeması

3D Baskı Tasarımı

Proje kasası tamamen 3D yazıcı ile basılabilecek şekilde tasarlandı. LED’ler, ekran, dokunmatik buton ve ESP kartı için ayrılı yuvalar bulunuyor.

3D tasarımları görmek için parça adlarına tıklayabilirsiniz.

Parçalar:

akıllı çalar saat 3d gövde
akıllı çalar saat 3d kapak

Kodlar

Kod; Wi-Fi bağlantısı, Telegram API kullanımı, saat görüntüleme, alarm kurma, LED kontrolü ve buzzer fonksiyonlarını kapsar.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <time.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

const char* botToken = ""; // kendi token'ını buraya koyun
const char* chatID = ""; // kendi chat id’n

// WiFi bilgileri
const char* ssid = "";
const char* password = "";

// Zaman sunucusu ve saat dilimi
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 10800;   // Türkiye için GMT+3 -> 3*3600
const int daylightOffset_sec = 0;   // Yaz saati yoksa 0

WiFiClientSecure secured_client;
UniversalTelegramBot bot(botToken, secured_client);

// NTPClient için gerekli nesneler
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 10800, 60000); // 10800 = GMT+3 (Türkiye), 60000 = 60sn'de bir güncelle

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET     -1
#define SCREEN_ADDRESS 0x3C 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define LED_PIN 2
#define NUM_LEDS 8
#define TOUCH_PIN 14
#define BUTON1 12
#define BUTON2 13
#define BUZZER 15
#define ROLE   0

Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

bool ledState = false;
bool lastTouchState = LOW;
bool alarmKuruluyor = false;
bool alarmAktif = false;
String alarmSaati = "";
bool soruModuAktif = false;
bool alarmCaliyor = false;
int dogruCevap = 0;
bool gunesDogumu = false;
bool onemliAlarm = false;
bool etkinlikAlarm = false;

void setup() 
{
  Serial.begin(115200);
  pinMode(TOUCH_PIN, INPUT);
  pinMode(BUTON1, INPUT_PULLUP);
  pinMode(BUTON2, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);
  pinMode(ROLE, OUTPUT);
  digitalWrite(BUZZER, LOW);

  strip.begin();
  strip.setBrightness(50); 
  strip.clear();
  strip.show();
  strip.setPixelColor(0, strip.Color(0, 0, 0));
  delay(100);
  ledKapa();

  // OLED ekran başlatma
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    Serial.println("SSD1306 ekran başlatılamadı!");
    while (true);
  }

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("WiFi baglaniyor...");
  display.display();

  // WiFi'ye bağlan
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi baglandi!");

  // NTP zamanı başlat
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("WiFi baglandi!");
  display.display();
  delay(1000);

  secured_client.setInsecure(); // SSL sertifika doğrulamasını kapat (Telegram için)
  timeClient.begin(); // Saat istemcisi başlatılıyor
}

void loop() 
{
  // 1. Saat güncelleme ve OLED'e yazdırma
  timeClient.update();

  // Saat ve dakikayı ayrı al
  int saatInt = timeClient.getHours();
  int dakikaInt = timeClient.getMinutes();

  // Tek basamaklı sayıları sıfırla tamamla
  String saatStr = (saatInt < 10 ? "0" : "") + String(saatInt);
  String dakikaStr = (dakikaInt < 10 ? "0" : "") + String(dakikaInt);

  // Saniyesiz saat formatı oluştur
  String saat = saatStr + ":" + dakikaStr;

  // Ekranda ortalamak için konum hesapla
  int16_t x1, y1;
  uint16_t w, h;
  display.setTextSize(2);
  display.getTextBounds(saat, 0, 0, &x1, &y1, &w, &h);
  int x = (SCREEN_WIDTH - w) / 2;
  int y = (SCREEN_HEIGHT - h) / 2;

  // Ekrana yaz
  display.clearDisplay();
  display.setCursor(x, y);
  display.println(saat);
  display.display();


  // 2. Dokunmatik sensörü kontrol et
  bool touchState = digitalRead(TOUCH_PIN);

  if (touchState == HIGH && lastTouchState == LOW) 
  {
    ledState = !ledState;
    if (ledState) 
    {
      ledAc();
    } 
    else 
    {
      ledKapa();
    }
    strip.show();
    delay(200); // debounce
  }
  lastTouchState = touchState;

  // Telegram mesajlarını kontrol et
  int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
  while (numNewMessages) {
    for (int i = 0; i < numNewMessages; i++) {
      String text = bot.messages[i].text;
      String chat_id = bot.messages[i].chat_id;

      if (text == "/alarm_kur")
      {
        bot.sendMessage(chat_id, "Lütfen alarm saatini HH.MM formatında girin (örn: 16.20)", "");
        alarmKuruluyor = true;
      }
      else if (alarmKuruluyor) 
      {
        if (text.length() == 5 && text.charAt(2) == '.')
        {
          alarmSaati = text;
          alarmAktif = true;
          alarmKuruluyor = false;
          bot.sendMessage(chat_id, "Alarm kuruldu: " + alarmSaati, "");
        }
        else
        {
          bot.sendMessage(chat_id, "Hatalı format. Lütfen HH.MM şeklinde girin.", "");
        }
      }
      else if (text == "/soru_modu_ac") 
      {
        soruModuAktif = true;
        bot.sendMessage(chat_id, "Soru ile alarm kapatma modu AKTİF.", "");
      } 
      else if (text == "/soru_modu_kapat") {
        soruModuAktif = false;
        bot.sendMessage(chat_id, "Soru modu KAPATILDI. Alarm klasik çalacak.", "");
      }
      else if (alarmCaliyor) {
        // Alarm çalıyorsa gelen mesajın sayı olup olmadığını kontrol et
        int gelenCevap = text.toInt();
        if (gelenCevap == dogruCevap) {
          alarmCaliyor = false;
          digitalWrite(BUZZER, LOW);
          digitalWrite(ROLE, LOW);
          display.clearDisplay();
          display.setCursor(0, 0);
          display.setTextSize(2);
          display.println("DURDU");
          display.display();
          bot.sendMessage(chat_id, "Doğru cevap! Alarm durduruldu ✅", "");
        } else {
          bot.sendMessage(chat_id, "Yanlış cevap ❌. Alarm devam ediyor!", "");
        }
      }
      else if (text == "/led_ac"){ledAc();bot.sendMessage(chat_id, "Ledler Açılıyor..", "");}
      else if (text == "/led_kapa"){ledKapa();bot.sendMessage(chat_id, "Ledler Kapatılıyor..", "");}
      else if (text == "/gun_dogumu_ac"){gunesDogumu=true;bot.sendMessage(chat_id, "Gün Doğumu Animasyonu Açılıyor..", "");}
      else if (text == "/gun_dogumu_kapa"){gunesDogumu=false;bot.sendMessage(chat_id, "Gün Doğumu Animasyonu Kapatılıyor..", "");}
      else if (text == "/onemli_alarm_kur")
      {
        bot.sendMessage(chat_id, "Lütfen alarm saatini HH.MM formatında girin (örn: 16.20)", "");
        onemliAlarm = true;
        alarmKuruluyor = true;
      }
      else if (text == "/etkinlik_alarm_kur")
      {
        bot.sendMessage(chat_id, "Lütfen alarm saatini HH.MM formatında girin (örn: 16.20)", "");
        etkinlikAlarm = true;
        alarmKuruluyor = true;
      }
    }
    numNewMessages = bot.getUpdates(bot.last_message_received + 1);
  }

  // Alarm kontrolü
  if (alarmAktif) {
    String simdi = timeClient.getFormattedTime(); // "HH:MM:SS"
    String simdiSaatDakika = simdi.substring(0, 2) + "." + simdi.substring(3, 5); // "HH.MM"

    if (simdiSaatDakika == alarmSaati)
    {
      if (gunesDogumu){gradualSunrise();}
      if (onemliAlarm){onemliAlarmAnimasyonu();onemliAlarm=false;}
      if (etkinlikAlarm){etkinlikAlarm();etkinlikAlarm=false;}
      bot.sendMessage(chatID, "Alarm çalıyor! 🔔", "");
      alarmCal();
      alarmAktif = false; // alarm tekrar çalmaz
    }
  }

  // Eğer soru modu aktifse ve alarm çalıyorsa, fiziksel butonla da durdurma şansı ver
  if (alarmCaliyor)
  {
    // Fiziksel butonla durdurma
    if (digitalRead(BUTON1) == LOW || digitalRead(BUTON2) == LOW)
    {
      alarmCaliyor = false;
      digitalWrite(BUZZER, LOW);
      digitalWrite(ROLE, LOW);
      display.clearDisplay();
      display.setCursor(0, 0);
      display.setTextSize(2);
      display.println("DURDU");
      display.display();
      bot.sendMessage(chatID, "Alarm fiziksel olarak durduruldu.", "");
    }
    else
    {
      for (int i = 0; i < 5; i++) 
      {
        digitalWrite(BUZZER, HIGH);
        digitalWrite(ROLE, HIGH);
        delay(500);
        digitalWrite(BUZZER, LOW);
        digitalWrite(ROLE, LOW);
        delay(500);
      }
    }
  }

  //delay(100); // loop'u yavaşlat, sistem stabilitesi için
}


void alarmCal()
{
  if (soruModuAktif) {
    alarmCaliyor = true;
    int sayi1 = random(1, 10);
    int sayi2 = random(1, 10);
    dogruCevap = sayi1 + sayi2;

    // OLED'e soruyu yaz
    display.clearDisplay();
    display.setCursor(0, 0);
    display.setTextSize(1);
    display.println("Alarm! Cevapla:");
    display.setTextSize(2);
    display.print(sayi1);
    display.print(" + ");
    display.print(sayi2);
    display.print(" = ?");
    display.display();

    // Telegram’a soruyu gönder
    bot.sendMessage(chatID, "Alarm çalıyor! 🔔\nCevapla: " + String(sayi1) + " + " + String(sayi2) + " = ?", "");

    // Alarmı sürekli çalıştırmak için döngüye girme (loop içinde yapılacak)
  } else {
    // Normal alarm davranışı
    for (int i = 0; i < 5; i++) {
      digitalWrite(BUZZER, HIGH);
      digitalWrite(ROLE, HIGH);
      delay(500);
      digitalWrite(BUZZER, LOW);
      digitalWrite(ROLE, LOW);
      delay(500);
    }
  }
}

void ledAc()
{
  for (int i = 0; i < NUM_LEDS; i++) 
  {
    strip.setPixelColor(i, strip.Color(255, 232, 26));
  }
  strip.show();
}
void ledKapa()
{
  for (int i = 0; i < NUM_LEDS; i++) 
  {
    strip.setPixelColor(i, strip.Color(0, 0, 0));
  }
  strip.show();
}

void gradualSunrise() {
  for (int i = 0; i < 255; i++) {
    // Her LED'in kırmızı ve yeşil rengini artırarak altın sarısı rengini oluştur
    int red = map(i, 0, 255, 0, 255);    // Kırmızı 0'dan 255'e
    int green = map(i, 0, 255, 0, 215);  // Yeşil 0'dan 215'e
    int blue = 0;                         // Mavi sıfırda kalacak

    for (int j = 0; j < NUM_LEDS; j++) {
      strip.setPixelColor(j, strip.Color(red, green, blue));
    }
    strip.show();  // LED'lere yeni renkleri uygula
    delay(20);  // 10ms'lik bir gecikme, yavaşça geçiş yapabilmesi için
  }
}

void etkinlikAlarm()
{
  for (int i = 0; i < NUM_LEDS; i++) 
  {
    strip.setPixelColor(i, strip.Color(0, 0, 150));
  }
  strip.show();

  int melody[] ={262,  294,  330,  349,  392,  440,  494,  523,  587,  659,  698,  784,  880};

  int melodyLength = sizeof(melody) / sizeof(melody[0]);
  // 10'dan geriye sayım
  for (int i = 10; i >= 0; i--) {
    // i'yi string'e dönüştür
    String str = String(i);
    
    int16_t x1, y1;
    uint16_t w, h;
    display.setTextSize(2);
    
    // getTextBounds fonksiyonuna string olarak geçiyoruz
    display.getTextBounds(str.c_str(), 0, 0, &x1, &y1, &w, &h);
    
    int x = (SCREEN_WIDTH - w) / 2;
    int y = (SCREEN_HEIGHT - h) / 2;
    display.clearDisplay();
    display.setCursor(x, y);
    display.print(i);  // Geri sayımı ekrana yazdır
    display.display();
    delay(1000);  // 1 saniye bekle
}

  for (int i = 0; i < melodyLength; i++)
  {
    tone(BUZZER, melody[i], 300);  // 300ms uzunluğunda her nota çalınır
    delay(300);  // Bir nota arasındaki bekleme
  }
  noTone(BUZZER);
}

void onemliAlarmAnimasyonu() {
  for (int i = 0; i < 255; i++) {
    // Her LED'in kırmızı ve yeşil rengini artırarak altın sarısı rengini oluştur
    int red = map(i, 0, 255, 0, 255);    // Kırmızı 0'dan 255'e
    int green = 0;
    int blue = 0;                         // Mavi sıfırda kalacak

    for (int j = 0; j < NUM_LEDS; j++) {
      strip.setPixelColor(j, strip.Color(red, green, blue));
    }
    strip.show();  // LED'lere yeni renkleri uygula
    delay(5);  // 10ms'lik bir gecikme, yavaşça geçiş yapabilmesi için
  }
}

Bu proje, uyanma deneyiminizi bir adım öteye taşıyor. Sadece bir saat değil, sabahlarınızı planlayan, randevuları hatırlatan ve sizi gülümseterek uyandıran bir sistem.

Sen de kendi akıllı çalar saatini yap ve sabahlara yepyeni bir başlangıç ver!

Alarm kur, ledleri yak, titreşimi hisset ve gününe enerjiyle başla!

Detaylı anlatım ve yapım aşamaları için YouTube videomuzu izleyebilirsiniz!

https://www.youtube.com/watch?v=1OEvfvl3iKs

Son Çıkan Yazılar

CEVAP VER

Lütfen yorumunuzu giriniz!
Lütfen isminizi buraya giriniz