C Program Arduino Wake Up Light

#include <Wire.h>
#include <RTClib.h>
#define ALR_HOUR 6
#define ALR_MIN 0
#define LCD_BACKLIGHT_TIME 3000L
#define FADE_EXTRA_TIME 600000L
#define RED_PIN 3
#define GREEN_PIN 5
#define BLUE_PIN 6
#define BUTTON_PIN 2
RTC_DS1307 RTC;
typedef struct {
  byte red;
  byte green;
  byte blue;
  unsigned int seconds;
} color_seq_item;
color_seq_item col0 = {  12,   1,    0,  300};
color_seq_item col1 = {  50,   1,    0,  300};
color_seq_item col2 = {  80,   10,   0,  300};
color_seq_item col3 = { 255,   60,   0,  180};
color_seq_item color_seq[] = {col0, col1, col2, col3};
int color_seq_size = sizeof(color_seq) / sizeof(color_seq_item);
void set_color(byte red, byte green, byte blue) {
  analogWrite(RED_PIN, red);
  analogWrite(GREEN_PIN, green);
  analogWrite(BLUE_PIN, blue);
}
void lcd_init() {
  Serial.write(0x7C);
  Serial.write(0x0D); // 9600 bauds
  delay(5);
  Serial.write(0x7C);
  Serial.write(0x04); // 16 char
  delay(5);
  Serial.write(0x7C);
  Serial.write(0x06); // 2 lines
  delay(5);
}
void lcd_clear() {
  Serial.write(0xFE);
  Serial.write(0x01);
  delay(5);
}
void lcd_back_on() {
  Serial.write(0x7C);
  Serial.write(157);
  delay(5);
}
void lcd_back_off(){
  Serial.write(0x7C);
  Serial.write(128);
  delay(5);
}
void update_lcd_time() {
  static enum {WAITING, UPDATING} state = WAITING;
  static unsigned long prev_millis = millis();
  DateTime time;
  switch(state) {
    case WAITING:
      if (millis() - prev_millis >= 1000) {
        prev_millis = millis();
        state = UPDATING;
      }
      break;
    case UPDATING:
      time = RTC.now();
      Serial.print("Hora: ");
      if (time.hour() < 10) Serial.print("0");
      Serial.print(time.hour());
      Serial.print(":");
      if (time.minute() < 10) Serial.print("0");
      Serial.print(time.minute());
      Serial.print(":");
      if (time.second() < 10) Serial.print("0");
      Serial.print(time.second());
      Serial.print("  ");
      Serial.print("Alarma: ");
      if (ALR_HOUR < 10) Serial.print("0");
      Serial.print(ALR_HOUR);
      Serial.print(":");
      if (ALR_MIN < 10) Serial.print("0");
      Serial.print(ALR_MIN);
      Serial.print("   ");
      state = WAITING;
      break;
  }
}
void update_lcd_backlight() {
  static enum {OFF, ON, DELAYING} state = OFF;
  static unsigned long prev_millis;
  switch(state) {
    case OFF:
      if (digitalRead(BUTTON_PIN) == LOW) {
        state = ON;
      }
      break;
    case ON:
      lcd_back_on();
      prev_millis = millis();
      state = DELAYING;
      break;
    case DELAYING:
      if (millis() - prev_millis >= LCD_BACKLIGHT_TIME) {
        lcd_back_off();
        state = OFF;
      }
      break;
  }
}
void update_wake_up() {
  static enum {WAITING, RUNNING, DELAYING, CANCELLED} state = WAITING;
  static unsigned long prev_millis = millis();
  static int seq_index;
  static int step_index;
  color_seq_item cur_item;
  color_seq_item next_item;
  unsigned long time_step_ms;
  int red, green, blue;
  DateTime time;

  switch(state) {
    case WAITING:
      if (millis() - prev_millis >= 1000) {
        prev_millis = millis();
        time = RTC.now();
      
        if ((time.hour() == ALR_HOUR) && (time.minute() == ALR_MIN) && (time.second() < 3)) {
          seq_index = 0;
          step_index = 0;
          state = RUNNING;
        }
      }
      break;
    case RUNNING:
      if (digitalRead(BUTTON_PIN) == LOW) {
        state = CANCELLED;
      } else {
        if (step_index == 256) {
          if (seq_index == (color_seq_size - 2)) {
            prev_millis = millis();
            state = DELAYING;
          } else {
            seq_index += 1;
            step_index = 0;
          }
        } else {
          cur_item = color_seq[seq_index];
          next_item = color_seq[seq_index + 1];
          time_step_ms = (cur_item.seconds * 1000UL) / 256UL;
        
          if (time_step_ms == 0) {
            set_color(cur_item.red, cur_item.green, cur_item.blue);
            step_index = 256;
          } else {
            if (millis() - prev_millis >= time_step_ms) {
              prev_millis = millis();
              red = ((cur_item.red * (255 - step_index)) + (next_item.red * step_index)) / 255;
              green = ((cur_item.green * (255 - step_index)) + (next_item.green * step_index)) / 255;
              blue = ((cur_item.blue * (255 - step_index)) + (next_item.blue * step_index)) / 255;
              set_color(red, green, blue);
              step_index += 1;
            }
          }
        }
      }
      break;
    case DELAYING:
      if (digitalRead(BUTTON_PIN) == LOW) {
        state = CANCELLED;
      } else {
        if (millis() - prev_millis >= FADE_EXTRA_TIME) {
          prev_millis = millis();
          set_color(0, 0, 0);
          state = WAITING;
        }
      }
      break;
    case CANCELLED:
      prev_millis = millis();
      set_color(0, 0, 0);
      state = WAITING;
      break;
  }
}
void setup() {
  Wire.begin();
  RTC.begin();
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Serial.begin(9600);
  lcd_init();
  lcd_clear();
  lcd_back_off();
  set_color(0, 0, 0);
  if (color_seq_size < 2) {
    while(1) {
      Serial.print("ERROR: color > 2");
      delay(1000);
    }
  }
}
void loop() {
  update_lcd_time();
  update_lcd_backlight();
  update_wake_up();
}


Learn More :