#include <LiquidCrystal.h>
#include <Wire.h>
#include <RTClib.h>


const int timbreLargo = 8000;
const int timbreCorto = 4000;
const int timbreCorto1 = 2500;
unsigned long t = 0;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define NOP __asm__ __volatile__("nop\n\t") //62.5ns en 16MHz

//RTC_DS3231 rtc;
RTC_DS1307 rtc;

const char daysOfTheWeek [7][4] = {"Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab"};
byte rx = 0, offset = 0;
byte datos[6];
bool Timbre = false;

struct timbre_e {
  byte hora;
  byte minutos;
  uint32_t duracion;  // en mseg
};

// datos de hora, minutos y duracion en mseg de disparo del timbre
const timbre_e datosTimbre[] = {
                          {7, 0, timbreLargo}, 
                          {7, 40, timbreCorto}, 
                          {8, 20, timbreLargo}, 
                          {8, 30, timbreLargo},
                          {9, 0, timbreCorto1}, 
                          {9, 10, timbreCorto}, 
                          {9, 30, timbreCorto1}, 
                          {9, 50, timbreLargo},
                          {10, 0, timbreLargo}, 
                          {10, 40, timbreCorto}, 
                          {11, 20, timbreLargo}, 
                          {11, 30, timbreLargo},
                          {12, 10, timbreCorto}, 
                          {12, 23, timbreCorto}, 
                          {12, 33, timbreLargo}, 
                          {12, 36, timbreCorto},
                          {14, 20, timbreLargo}, 
                          {14, 30, timbreLargo}, 
                          {15, 10, timbreCorto1}, 
                          {15, 40, timbreCorto1},
                          {15, 50, timbreLargo}, 
                          {16, 00, timbreLargo}, 
                          {16, 40, timbreCorto}, 
                          {17, 20, timbreLargo},
                          {17, 30, timbreLargo}, 
                          {22, 15, timbreLargo}
                         };

byte timbreIndex = 0;
byte numTimbres = sizeof(datosTimbre) / sizeof(datosTimbre[0]);

// ------------------------------------------------------------
// verifica cual es la siguiente alarma (por si hubo un reset o ajuste de hora)
void verificar_proxima_alarma() {
  DateTime now = rtc.now ();
// pasa hora y minutos actual a minutos para facilitar la comparación 
  int tmp = now.hour() * 60 + now.minute();
  byte i = 0;
  while (i < numTimbres) {
    if(datosTimbre[i].hora * 60 + datosTimbre[i].minutos > tmp) {
      break;
    }
    i++;
  }
  timbreIndex = i;
  if (timbreIndex == numTimbres) timbreIndex  = 0;
}
// ------------------------------------------------------------


void setup() {
  Serial.begin(115200);

  lcd.begin (16, 2);
  delay (3000);

  if (!rtc.begin()) {
    Serial.println (F("Opssss!!!... no encuentro el RTC!!!"));
    while (1);
  }
  pinMode (2, OUTPUT);
  digitalWrite (2, LOW);
  verificar_proxima_alarma();
  
  lcd.clear();
}

void loop() {

  if (Serial.available()) {
    Timbre = true;
    rx = (uint8_t) Serial.read();
    datos [offset] = rx;
    offset ++;
    if (offset == 6 ) {
      rtc.adjust (DateTime (datos[0] + 2000, datos[1], datos[2], datos[3], datos[4], datos[5]));
      offset = 0;
      Timbre = false;
      verificar_proxima_alarma();
    }
  }
  DateTime now = rtc.now ();

  lcd.setCursor (0, 0);
  lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
  lcd.print (" ");
  if (now.day() < 10) lcd.print(0);
  lcd.print(now.day());
  lcd.print('/');
  if (now.month() < 10) lcd.print(0);
  lcd.print(now.month());
  lcd.print('/');
  lcd.print(now.year());
  lcd.setCursor(0, 1);
  if (now.hour() < 10) lcd.print(0);
  lcd.print(now.hour());
  lcd.print(':');
  if (now.minute() < 10) lcd.print(0);
  lcd.print (now.minute());
  lcd.print(':');
  if (now.second() < 10) lcd.print(0);
  lcd.print(now.second());

  if (now.dayOfTheWeek() == 0 || now.dayOfTheWeek() == 6) { //chequea sabado y domingo
    Serial.println (F("Sabado o domingo"));
  } else {  //si es dia de semana
    //********************************************************************************************************
    if (Timbre == false) {
      if (now.hour() == datosTimbre[timbreIndex].hora && now.minute() == datosTimbre[timbreIndex].minutos && now.second() <= 1) { 
        //Activar timbre
        Serial.println(F("Timbre ON"));
        digitalWrite(2, HIGH);
        Timbre = true;
        t = millis();
      } 
    } else {
        if ( millis() - t > datosTimbre[timbreIndex].duracion ) {
          Serial.println(F("Timbre OFF"));
          digitalWrite (2, LOW);
          Timbre = false;
          timbreIndex++;
          if (timbreIndex == numTimbres) timbreIndex  = 0;
        }
    }
  }
  //##################################################################################################

  delay(1000);
}
GND5VSDASCLSQWRTCDS1307+
NOCOMNCVCCGNDINLED1PWRRelay Module