// 🕒 קוד משולב: ניהול השכמה + תאורה + שירים + תצוגה
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <Adafruit_NeoPixel.h>
// הגדרות NeoPixel
#define NEOPIXEL_PIN 6
#define NUMPIXELS 16
Adafruit_NeoPixel strip(NUMPIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
// צבעים: כתום, צהוב, לבן, כחול
uint8_t colors[][3] = {
{255, 164, 61}, // כתום
{241, 252, 119}, // צהוב
{255, 255, 255}, // לבן
{139, 215, 252} // כחול
};
// תצוגה + RTC
LiquidCrystal_I2C lcd(0x27, 16, 2);
RTC_DS1307 rtc;
// זמן נוכחי וזמן השכמה
int h = 0, m = 0, s = 0;
int alarmH = 0, alarmM = 0;
int wakeBefore = 0; // דקות לפני השכמה
// לחצנים
#define BTN_SET 4
#define BTN_UP 3
#define BTN_DOWN 5
#define BUTTON_PIN 12
#define ALT_BUTTON_PIN 7
#define BUZZER_PIN 8
// משתנים
int setState = 0;
int currentSong = 1;
bool buttonPressed = false;
bool pirTriggered = false;
bool songStarted = false;
bool lightStarted = false;
unsigned long lastActionTime = 0;
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
rtc.begin();
pinMode(BTN_SET, INPUT_PULLUP);
pinMode(BTN_UP, INPUT_PULLUP);
pinMode(BTN_DOWN, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(ALT_BUTTON_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
if (!rtc.isrunning()) rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
strip.begin();
strip.show();
}
void loop() {
DateTime now = rtc.now();
h = now.hour();
m = now.minute();
s = now.second();
int alarmMin = alarmH * 60 + alarmM;
int startMin = alarmMin - wakeBefore;
int nowMin = h * 60 + m;
// תאורה מתחילה לפני זמן ההשכמה
if (nowMin >= startMin && nowMin < alarmMin && !lightStarted) {
lightStarted = true;
startLightSequence();
}
if (nowMin >= startMin && nowMin < alarmMin) {
tone(BUZZER_PIN, 1000);
} else {
noTone(BUZZER_PIN);
}
if (nowMin == alarmMin && !songStarted) {
songStarted = true;
playSong(1);
}
if (nowMin > alarmMin && songStarted) {
songStarted = false;
pirTriggered = false;
currentSong = 1;
}
if (digitalRead(ALT_BUTTON_PIN) == LOW && !pirTriggered) {
delay(200);
pirTriggered = true;
playSong(4);
}
if (digitalRead(BUTTON_PIN) == LOW && !buttonPressed && !pirTriggered) {
buttonPressed = true;
delay(200);
if (currentSong == 1) playSong(2);
else if (currentSong == 2) playSong(3);
}
if (digitalRead(BUTTON_PIN) == HIGH) buttonPressed = false;
// הגדרת זמן בתצוגה
if (digitalRead(BTN_SET) == LOW) {
delay(200);
setState++;
if (setState > 4) setState = 0;
}
if (setState == 1) updateWithHold(alarmH, 0, 23);
else if (setState == 2) updateWithHold(alarmM, 0, 59);
else if (setState == 3) updateWithHold(wakeBefore, 0, 59);
lcd.setCursor(0, 0);
if (setState == 0) lcd.print("Set alarm ");
else if (setState == 1) { lcd.print("Set hour: "); printTwoDigits(alarmH); lcd.print(" "); }
else if (setState == 2) { lcd.print("Set min: "); printTwoDigits(alarmM); lcd.print(" "); }
else if (setState == 3) { lcd.print("Set awake: "); lcd.print(wakeBefore); lcd.print("m "); }
else if (setState == 4) {
lcd.print("Alarm "); printTwoDigits(alarmH); lcd.print(":"); printTwoDigits(alarmM); lcd.print(", "); lcd.print(wakeBefore); lcd.print("m ");
}
lcd.setCursor(0, 1);
lcd.print("Time "); printTwoDigits(h); lcd.print(":"); printTwoDigits(m); lcd.print(":"); printTwoDigits(s); lcd.print(" ");
delay(100);
}
void startLightSequence() {
for (int c = 0; c < 4; c++) {
uint8_t r = colors[c][0];
uint8_t g = colors[c][1];
uint8_t b = colors[c][2];
strip.clear();
strip.show();
for (int i = 0; i < NUMPIXELS; i++) {
float factor = (c == 2) ? 1.0 : 0.5 + 0.5 * float(i) / (NUMPIXELS - 1);
strip.setPixelColor(i, strip.Color(r * factor, g * factor, b * factor));
strip.show();
delay(150);
}
fillAllPixels(r, g, b);
if (c == 0) {
bool skipBlink = waitForButtonOrTimeout(10000);
if (!skipBlink) blinkWithButton(r, g, b, 10000, 300);
} else {
bool skip = waitForButtonOrTimeout(10000);
if (skip) continue;
}
if (c == 3) while (true); // עצירה בכחול
}
}
void fillAllPixels(uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < NUMPIXELS; i++) strip.setPixelColor(i, strip.Color(r, g, b));
strip.show();
}
bool waitForButtonOrTimeout(unsigned long durationMs) {
unsigned long start = millis();
while (millis() - start < durationMs) {
if (digitalRead(BUTTON_PIN) == LOW) {
delay(200);
return true;
}
delay(20);
}
return false;
}
bool blinkWithButton(uint8_t r, uint8_t g, uint8_t b, unsigned long durationMs, int interval) {
unsigned long start = millis();
bool on = true;
while (millis() - start < durationMs) {
if (digitalRead(BUTTON_PIN) == LOW) {
delay(200);
return true;
}
if (on) fillAllPixels(r, g, b);
else { strip.clear(); strip.show(); }
on = !on;
delay(interval);
}
return false;
}
void playSong(int songNumber) {
currentSong = songNumber;
lastActionTime = millis();
switch (songNumber) {
case 1: Serial.println("🎵 Play rustling leaves"); break;
case 2: Serial.println("🎵 Play bird chirping"); break;
case 3: Serial.println("🎵 Play truck reverse"); break;
case 4: Serial.println("🎵 Playing 'Happy'"); break;
default: Serial.println("⚠️ Unknown song"); break;
}
}
void updateWithHold(int &value, int minVal, int maxVal) {
static bool wasUpHeld = false;
static bool wasDownHeld = false;
static unsigned long lastRepeatTime = 0;
if (digitalRead(BTN_UP) == LOW) {
if (!wasUpHeld) {
lastActionTime = millis();
value = (value + 1 > maxVal) ? minVal : value + 1;
wasUpHeld = true;
} else if (millis() - lastActionTime > 400 && millis() - lastRepeatTime > 150) {
value = (value + 1 > maxVal) ? minVal : value + 1;
lastRepeatTime = millis();
}
} else wasUpHeld = false;
if (digitalRead(BTN_DOWN) == LOW) {
if (!wasDownHeld) {
lastActionTime = millis();
value = (value - 1 < minVal) ? maxVal : value - 1;
wasDownHeld = true;
} else if (millis() - lastActionTime > 400 && millis() - lastRepeatTime > 150) {
value = (value - 1 < minVal) ? maxVal : value - 1;
lastRepeatTime = millis();
}
} else wasDownHeld = false;
}
void printTwoDigits(int number) {
if (number < 10) lcd.print("0");
lcd.print(number);
}