//Eigene Uhr mit Display und folientaste zum konfigurieren der weckfunktion, snoozen und stoppen

#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Wire.h> 
#include "DCF77.h"
#include "Time.h"

#define I2C_ADDR 0x27       //LCD als I²C und dazu Größe festlegen
#define LCD_COLUMNS 16
#define LCD_LINES 2

LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys [ROWS] [COLS]      //Keypad - Werte der tasten definieren
{
  { '1', '2', '3', 'A'},
  { '4', '5', '6', 'B'},
  { '7', '8', '9', 'C'},
  { '*', '0', '#', 'D'},
};

uint8_t colPins[COLS] = { 5, 4, 3, 2 };  //Keypad - Pins definieren
uint8_t rowPins[ROWS] = { 9, 8, 7, 6 }; 

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

//DCF77
time_t time;
DCF77 DCF = DCF77(1,0);

//GLOBALE VARIABLEN
unsigned int jahr = 2023; 
unsigned int monat = 12;
unsigned int tag = 31;
unsigned int stunde = 0;  
unsigned int minute = 58;
unsigned int sekunde = 55;
char key;
int weckzeits = 61;
int weckzeitm = 61;
int weckzeith = 25;

/*------------------------------------------------------------------*/
void datum()    //Prüft auf Datumsänderung und passt ggf an
{
  //Februar
  if (monat == 2)               
  {
    //Schaltjahr
    if (((jahr%4==0) && (jahr%100!=0)) || (jahr%400==0))   
    {
      if (tag == 29)
      {
        tag = 1;
        monat += 1;
      }
    }
    else
    {
      if (tag == 28)
      {
        tag = 1;
        monat += 1;
      }
    }
  }

  //Monat mit 30 Tagen
  if ((monat == 4 || monat == 6 || monat == 9 || monat == 11) && tag == 31)
  {
    tag = 1;
    monat += 1;
  }

  //Monat mit 31 Tagen
  if ((monat == 1 || monat == 3 || monat == 5 || monat == 7 || monat == 8 || monat == 10) && (tag == 32))
  {
    tag = 1;
    monat += 1;
  }    
  
  //Neujahr
  if ((monat == 12) && (tag == 32))
  {
    tag = 1;
    monat = 1;
    jahr += 1;
  }
}

void ausgabe1()  //Standardausgabe Uhrzeit & Datum
{
  //UHRZEIT
  lcd.setCursor(2, 0);
  lcd.print(stunde);
  lcd.setCursor(4, 0);
  lcd.print(" : ");
  lcd.setCursor(7, 0);
  lcd.print(minute);
  lcd.setCursor(9, 0);
  lcd.print(" : ");
  if (sekunde > 9)  
  {
    lcd.setCursor(12, 0);
    lcd.print(sekunde);
  }
  else  //vorstehende 0                
  {
    lcd.setCursor(12, 0);
    lcd.print("0");
    lcd.setCursor(13, 0);
    lcd.print(sekunde);
  }

  //DATUM
  lcd.setCursor(0, 1);
  lcd.print("Date: ");
  lcd.setCursor(6, 1);
  lcd.print(tag);
  lcd.setCursor(8, 1);
  lcd.print(".");
  lcd.setCursor(9, 1);
  lcd.print(monat);
  lcd.setCursor(11, 1);
  lcd.print(".");
  lcd.setCursor(12, 1);
  lcd.print(jahr);
}

//Funkabgleich
unsigned long getDCFTime()
{ 
  time_t DCFtime = DCF.getTime();
  if (DCFtime==0) {
    Serial.print("n");  
  } else {
    Serial.print("u");  
  }
  return DCFtime;
}

void setweck()
{
  int hour = 0;
  int minutes = 0;
  int second = 0;
  bool tru = true;
  int pos = 4;

  //Setup Ausgabe
  lcd.setCursor(0, 0);
  lcd.print("Set Alarm Time:");
  lcd.setCursor(0, 1);
  lcd.print("    00");
  lcd.setCursor(6, 1);
  lcd.print(":");
  lcd.setCursor(7, 1);
  lcd.print("00");
  lcd.setCursor(9, 1);
  lcd.print(":");
  lcd.setCursor(10, 1);
  lcd.print("00");
  
  do  //Zeit eintragen
  {
    char key = keypad.getKey();
    int digit = key - '0';

    //Nummerntasten
    if (key >= '0' && key <= '9') 
    {
      switch (pos) 
      {
        case 4:
          hour = digit * 10;
          if (hour > 23) hour = 23;
          lcd.setCursor(4, 1);
          pos = 5;
          break;
        case 5:
          hour += digit;
          if (hour > 23) hour = 23;
          lcd.setCursor(5, 1);
          pos = 7;
          break;
        case 7:
          minutes = digit * 10;
          if (minutes > 59) minutes = 59;
          lcd.setCursor(7, 1);
          pos = 8;
          break;
        case 8:
          minutes += digit;
          if (minutes > 59) minutes = 59;
          lcd.setCursor(8, 1);
          pos = 10;
          break;
        case 10:
          second = digit * 10;
          if (second > 59) second = 59;
          lcd.setCursor(10, 1);
          pos = 11;
          break;
        case 11:
          second += digit;
          if (second > 59) second = 59;
          lcd.setCursor(11, 1);
          pos = 12;
          break;
        case 12:
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("  mit '#' ");
          lcd.setCursor(0, 1);
          lcd.print("bestaetigen     ");
      }
      //Anzeigen der Zeiten
      lcd.print(digit);
    }

    //Zeichentasten
    switch (key) 
    {
      case '*':       //Reset
        setweck();
        break;
     
      case '#':       //Save
        weckzeith = hour;
        weckzeitm = minutes;
        weckzeits = second;
        tru = false;
        return;
    }
  } while (tru);
}

void wecken()
{
  if (weckzeits == sekunde && weckzeitm == minute && weckzeith == stunde)
  {
    bool aufgestanden = false;
    do 
    {
      key = keypad.getKey();
      tone(13, 262);
      if (key == '0')
      {
        aufgestanden = true;
        noTone(13);
      }
    } while (!aufgestanden);
  }
}

void setclock()
{
  int hour = 0;
  int minutes = 0;
  int second = 0;
  bool tru1 = true;
  int pos = 4;

  //Setup Ausgabe
  lcd.setCursor(0, 0);
  lcd.print("Set Clock Time:");
  lcd.setCursor(0, 1);
  lcd.print("    00");
  lcd.setCursor(6, 1);
  lcd.print(":");
  lcd.setCursor(7, 1);
  lcd.print("00");
  lcd.setCursor(9, 1);
  lcd.print(":");
  lcd.setCursor(10, 1);
  lcd.print("00");
  
  do  //Zeit eintragen
  {
    char key = keypad.getKey();
    int digit = key - '0';

    //Nummerntasten
    if (key >= '0' && key <= '9') 
    {
      switch (pos) 
      {
        case 4:
          hour = digit * 10;
          if (hour > 23) hour = 23;
          lcd.setCursor(4, 1);
          pos = 5;
          break;
        case 5:
          hour += digit;
          if (hour > 23) hour = 23;
          lcd.setCursor(5, 1);
          pos = 7;
          break;
        case 7:
          minutes = digit * 10;
          if (minutes > 59) minutes = 59;
          lcd.setCursor(7, 1);
          pos = 8;
          break;
        case 8:
          minutes += digit;
          if (minutes > 59) minutes = 59;
          lcd.setCursor(8, 1);
          pos = 10;
          break;
        case 10:
          second = digit * 10;
          if (second > 59) second = 59;
          lcd.setCursor(10, 1);
          pos = 11;
          break;
        case 11:
          second += digit;
          if (second > 59) second = 59;
          lcd.setCursor(11, 1);
          pos = 12;
          break;
        case 12:
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("  mit '#' ");
          lcd.setCursor(0, 1);
          lcd.print("bestaetigen     ");
      }
      //Anzeigen der Zeiten
      lcd.print(digit);
    }
    //Zeichentasten
    switch (key) 
    {   
      case '#':       //Save
        stunde = hour;
        minute = minutes;
        sekunde = second;
        tru1 = false;
        return;
    }
  } while (tru1);
}

/*------------------------------------------------------------------*/
void setup() 
{
  lcd.init(); //LCD und Hintergrundbeleuchtung anschalten 
  lcd.backlight();
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  DCF.Start();
  setSyncInterval(30);
  setSyncProvider(getDCFTime);
}

/*------------------------------------------------------------------*/
void loop() 
{
  key = keypad.getKey();
  ausgabe1();
  delay(982);   //Sekunden zählen 
  wecken();
  sekunde++;

  //UHRZEIT
  if (sekunde == 60)
  { 
    sekunde = 0;
    lcd.setCursor(0, 0);     
    lcd.clear();               //clear
    minute += 1;

    if (minute == 60)
    {
      stunde += 1;
      
      if  (timeStatus()== timeNotSet) 
      {           
        Serial.print("-");
      } 
      else 
      {
        time = now();
        Serial.print("+");
      }
      if (count==20) 
      {
        count=0;
        Serial.println("");       
      }   
      
      minute = 0;

      if (stunde == 24)
      {
        stunde = 0;
        tag += 1;              //TAG +1
        datum();
      }
    }
  }

  if (key != NO_KEY)
  {
    if (key == '*') 
    {
      lcd.clear();
      lcd.print("     Setup");
      setweck();
      lcd.clear();
    }
    if (key == '#') 
    {
      lcd.clear();
      setclock();
      lcd.clear();
    }
  }
  
  Serial.print("H ");
  Serial.print(weckzeith);
  Serial.print(weckzeitm);
  Serial.print(weckzeits);
  Serial.print(" = ");
  Serial.print(stunde);
  Serial.print(minute);
  Serial.print(sekunde);
  Serial.print("  ");
}