#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "Button.h"
#include "AlarmTone.h"
#include "Clock.h"
#include "config.h"
#include <RTClib.h>
#include <Servo.h>
Servo myServo;
RTC_DS3231 rtc;
const int SERVO_PIN = 3;
const int latchPin = 10;
const int clockPin = 9;
const int dataPin = 12;
const int outputEnable = 11;
const int SPEAKER_PIN = A3;
Button hourButton(A0);
Button minuteButton(A1);
Button alarmButton(A2);
AlarmTone alarmTone;
Clock clock;
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C-Adresse 0x27 für ein 16x2 Display
enum DisplayState {
DisplayClock,
DisplayAlarmStatus,
DisplayAlarmTime,
DisplayAlarmActive
};
DisplayState displayState = DisplayClock;
long lastStateChange = 0;
void changeDisplayState(DisplayState newValue) {
displayState = newValue;
lastStateChange = millis();
}
long millisSinceStateChange() {
return millis() - lastStateChange;
}
const unsigned long alarmDuration = 10000; // 10 Sekunden in Millisekunden
void displayTime() {
DateTime now = clock.now();
bool blinkState = now.second() % 2 == 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
lcd.print(now.hour());
lcd.print(":");
lcd.print(now.minute());
lcd.print(":");
lcd.print(now.second());
lcd.setCursor(0, 1);
lcd.print("Alarm: ");
lcd.print(clock.alarmEnabled() ? "ON " : "OFF");
}
void clockState() {
displayTime();
if (alarmButton.read() == Button::RELEASED && clock.alarmActive()) {
alarmButton.has_changed(); // Read alarmButton has_changed() to clear its state
changeDisplayState(DisplayAlarmActive);
return;
}
if (hourButton.pressed()) {
clock.incrementHour();
}
if (minuteButton.pressed()) {
clock.incrementMinute();
}
if (alarmButton.pressed()) {
clock.toggleAlarm();
changeDisplayState(DisplayAlarmStatus);
}
}
void alarmStatusState() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Alarm: ");
lcd.print(clock.alarmEnabled() ? "ON " : "OFF");
if (millisSinceStateChange() > ALARM_STATUS_DISPLAY_TIME) {
changeDisplayState(clock.alarmEnabled() ? DisplayAlarmTime : DisplayClock);
return;
}
}
void alarmTimeState() {
DateTime alarm = clock.alarmTime();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Alarm Time: ");
lcd.print(alarm.hour());
lcd.print(":");
lcd.print(alarm.minute());
if (millisSinceStateChange() > ALARM_HOUR_DISPLAY_TIME || alarmButton.pressed()) {
changeDisplayState(DisplayClock);
return;
}
if (hourButton.pressed()) {
clock.incrementAlarmHour();
lastStateChange = millis();
}
if (minuteButton.pressed()) {
clock.incrementAlarmMinute();
lastStateChange = millis();
}
if (alarmButton.pressed()) {
changeDisplayState(DisplayClock);
}
}
void alarmState() {
static unsigned long alarmStartTime = 0;
displayTime();
if (alarmButton.read() == Button::RELEASED) {
alarmTone.play();
alarmStartTime = millis(); // Speichere die aktuelle Zeit beim Start des Alarmtons
myServo.write(90); // Beispielwert, anpassen Sie dies an den gewünschten Drehwinkel
}
if (alarmButton.pressed()) {
alarmTone.stop();
}
if (alarmButton.released()) {
alarmTone.stop();
bool longPress = alarmButton.repeat_count() > 0;
if (longPress) {
clock.stopAlarm();
myServo.write(0); // Setzen Sie die Servo-Position auf die Ausgangsposition
changeDisplayState(DisplayClock);
}
}
}
void updateLEDs(int minuteLED) {
digitalWrite(latchPin, LOW);
if (minuteLED < 8) {
shiftOut(dataPin, clockPin, MSBFIRST, 1 << minuteLED);
shiftOut(dataPin, clockPin, MSBFIRST, 0);
} else {
shiftOut(dataPin, clockPin, MSBFIRST, 0);
shiftOut(dataPin, clockPin, MSBFIRST, 1 << (minuteLED - 8));
}
digitalWrite(latchPin, HIGH);
}
void setup() {
Serial.begin(115200);
myServo.attach(SERVO_PIN);
myServo.write(0); // Setzen Sie die Servo-Position auf die Ausgangsposition
clock.begin();
hourButton.begin();
hourButton.set_repeat(500, 200);
minuteButton.begin();
minuteButton.set_repeat(500, 200);
alarmButton.begin();
alarmButton.set_repeat(1000, -1);
alarmTone.begin(SPEAKER_PIN);
lcd.init(); // Initialisiere das I2C-Display
lcd.backlight(); // Hintergrundbeleuchtung aktivieren
pinMode(dataPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(outputEnable, OUTPUT);
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, let's set the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
}
void loop() {
DateTime now = rtc.now();
int minuteLED = (now.minute() / 5) % 12;
updateLEDs(minuteLED);
switch (displayState) {
case DisplayClock:
clockState();
break;
case DisplayAlarmStatus:
alarmStatusState();
break;
case DisplayAlarmTime:
alarmTimeState();
break;
case DisplayAlarmActive:
alarmState();
break;
}
delay(1000); // Warte 1 Sekunde, um die Zeit zu aktualisieren
}