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.

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
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.

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:


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!