Overview

An alarm clock that reminds you to get ready for bed, and gives advice for how to improve your sleep.

The alarm clock after you turn off the morning alarm. It displays the date, time, and a message based on the amount of sleep you got that night.

The inside of the alarm clock

The light turns on to signify that the user should get ready for bed. It can be turned off with a button, that also tells the clock the user is going to bed.

Pressing the button again turns off the morning alarm and tells the clock the user has woken up. It then displays a message based on the amount of sleep it tracked for that night.

Process

One of the big decisions I made was not having a way to change the alarm times. I originally planned to have two buttons that when pressed, would allow you to change the alarms with a potentiometer. I quickly realized, however, that I wouldn’t have enough time to implement this and instead decided to just have the alarms hard coded.

Another decision I made was to use an lcd screen to display the messages for how to improve your sleep. I was debating whether to use an lcd screen or receipt printer, and decided to use the lcd screen since it was big enough to display the messages I had in mind and I knew how to use one so I knew it wouldn’t take much time to add.

The final breadboard version on my clock, with two lcd screens.

Highlights:

This was the first version of my alarm clock. It had a real time clock, LED, piezo buzzer, a button, and one lcd screen that displayed the time.

The final version, with everything soldered to a protoboard. The final version had a second lcd screen, another button, a barrel jack, a speaker instead of a buzzer, and used an arduino nano instead of an uno.

The laser cut box I made for the clock, before I but the electronics in. The original top had holes that were too small for the buttons, so I had to recut the top.

Discussion

One of the critiques I received was, “I think that it would be more effective if you could change the sleep interval w/o having to reprogram the entire device.” I agree that this is something that would greatly improve the clock, since when you need to wake up or go to bed changes over time. As I mentioned earlier, I originally planned to include a way to change the alarms but didn’t have enough time to implement it.

Another critique was, “It might be cool to have this track sleep statistics over the course of the week.” I also agree with this critique. I think having advice given based on a pattern of sleep rather than just one night of sleep would be more useful. 

I think it did satisfy my main goals, and I am happy with how it came out. All of the features work the way I intended them to. I did the best I could in the time given, but there is still a lot of room for improvement. I think that the box is a bit big and bulky. I had designed it that way to make sure everything fit inside it, but it is bigger than it needs to be.

I learned a lot from this project, like that I don’t know how to use interrupts. I ran into a problem where the alarms stopped working correctly all of a sudden, so I tried switching to a different library to see if there was a problem with the library I was using. However, I couldn’t figure out how to use the interrupt that the library relied on to set alarms. There are still a lot of things you can do with the arduino that I have yet to learn.

I really enjoyed being able to just make something on my own.  This is the first time I’ve made a device, so it’s really satisfying to have taken an idea and made it into a reality. Since I had come up with the project idea and it was something I could actually use, I was really motivated and excited to work on the project.

If I could have done anything differently, I would have spent more time researching libraries for the real time clock. I went the library used in the first tutorial I found, but there might have been better libraries out there that I could have worked better for my project that I just didn’t know about.

If I have time this semester, I would like to make another iteration. I would add a way to change the time and the alarms, probably with buttons to indicate you want to change an alarm and a potentiometer to change the time. I would also like to make a more complicated sleep tracker that gives advice after a week of tracking your sleep. I would also make the physical clock smaller, since it’s bulky and takes up a lot of room when it isn’t necessary for it to be so big.

Technical Information

Schematic

 

/*
 * Project 2
 * Karen Abruzzo (kabruzzo)
 * Time: two weeks
 *
 * Collaboration:
 * I used code from the example SetAlarms from the DS3231M library as a staring point.
 * https://github.com/SV-Zanshin/DS3231M
 * 
 * Summary: The code sets two alarms that can be turns off with a button. One alarm turns on 
 * an LED to remind you to go to bed, the other plays a sound to wake you up in the morning.
 * There is also a snooze button. The code also tracks your sleep and outputs the current date,
 * time, and advice onto lcd screens.
 * 
 * Inputs:
 * real time clock              | PIN A4, A5
 * button                       | PIN 2
 * button                       | PIN 5
 * 
 * Outputs:
 * lcd screen    | PIN A4, A5
 * lcd screen    | PIN A4, A5
 * speaker       | PIN 4
 * LED           | PIN 3
 */

#include <DS3231M.h>//library for the rtc
#include <Wire.h>//library for i2c communications on analog pins
#include <LiquidCrystal_I2C.h>//library for the lcd screens

//setup the screens
LiquidCrystal_I2C screen1(0x27, 16, 2);
LiquidCrystal_I2C screen2(0x20, 20, 4);
const uint32_t SERIAL_SPEED        = 115200;

//set up pin numbers
const int ALARM_BUT_PIN = 2; 
const int SNOOZE_BUT_PIN = 5;
const int LED_PIN = 3;
const int BUZ_PIN = 4;

//set up global variables
//time you go to bed
int SLEEP_HOUR;
int SLEEP_MIN;
int SLEEP_SEC;
//time you wake up
int WAKE_HOUR;
int WAKE_MIN;
int WAKE_SEC;
//# of snoozes
int SNOOZES = 0;
//amount of time you slept
int HOURS_SLEPT;
int MINS_SLEPT;
int SECS_SLEPT;

DS3231M_Class DS3231M;
const uint8_t  SPRINTF_BUFFER_SIZE =     32; //this is for displaying the time and date properly
char inputBuffer[SPRINTF_BUFFER_SIZE];
bool ALARM = true; //this variable keeps track of which alarm (day or night) is set to go off next. True means the night alarm is set up.
DateTime SETUP_TIME = DateTime(2019, 10, 10, 11, 23, 0);//current time
DateTime NIGHT_ALARM = DateTime(0, 0, 0, 23, 0, 0);//time you want to go to bed
DateTime NIGHT_ALARM2 = DateTime(0, 0, 0, NIGHT_ALARM.hour() - 1, 30, 0);//time nigh alarm will go off
DateTime DAY_ALARM = DateTime(0, 0, 0, 8, 20, 0);//time day alarm will go off

void setup() {
  // put your setup code here, to run once:

//setup pins
  pinMode(ALARM_BUT_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUZ_PIN, OUTPUT);
  Serial.begin(SERIAL_SPEED);

  //setup lcd screens
  screen1.init();
  screen2.init();

  // turn on the backlight to start
  screen1.backlight();
  screen2.backlight();

  // set cursor to home position, i.e. the upper left corner
  screen1.home();
  while (!DS3231M.begin()) {
    Serial.println(F("Unable to find DS3231MM. Checking again in 3s."));
    delay(3000);
  }
  //DS3231M.adjust(SETUP_TIME); //uncomment this line to set the time on the rtc
  DS3231M.setAlarm(minutesHoursMatch, NIGHT_ALARM2); //start the alarm
  //display the date and time
  DateTime now = DS3231M.now();
  sprintf(inputBuffer, "%04d-%02d-%02d", now.year(), now.month(), now.day());
  screen1.clear();
  screen1.home();
  screen2.clear();
  screen2.home();
  screen1.print(inputBuffer);
  Serial.print(inputBuffer);
  Serial.print(" ");
  sprintf(inputBuffer, "%02d:%02d", now.hour(), now.minute());
  screen1.setCursor(0, 1);
  screen1.print(inputBuffer);
  Serial.println(inputBuffer);

}

void loop() {
  // put your main code here, to run repeatedly:
  DateTime sleepTime; //time you go to bed
  DateTime wakeTime; // time you wake up
  DateTime timeSlept; //how long you slept
  DateTime now = DS3231M.now();
  static uint8_t mins;
  if (mins != now.minute()) //every minute, change display so it displays current time
  { 
    sprintf(inputBuffer, "%04d-%02d-%02d", now.year(), now.month(), now.day());
    screen1.clear();
    screen1.home();
    screen1.print(inputBuffer);
    Serial.print(inputBuffer);
    Serial.print(" ");
    sprintf(inputBuffer, "%02d:%02d", now.hour(), now.minute());
    screen1.setCursor(0, 1);
    screen1.print(inputBuffer);
    Serial.println(inputBuffer);
    mins = now.minute();
  }
  if (digitalRead(ALARM_BUT_PIN)) //if the alarm off button is pressed
  {
    delay(200); //debounces button
    SNOOZES = 0; //reset snoozes
    if (ALARM) { //if the alarm that went off was the night alarm
      //turn off alarm, set alarm time to the morning alarm, turn off the LED,
      //set the sleep time and turn off backlight on second lcd screen
      DS3231M.clearAlarm(); 
      DS3231M.setAlarm(minutesHoursMatch, DAY_ALARM);
      ALARM = !ALARM;
      digitalWrite(LED_PIN, 0);
      sleepTime = DS3231M.now();
      SLEEP_HOUR = sleepTime.hour();
      SLEEP_MIN = sleepTime.minute();
      SLEEP_SEC = sleepTime.second();
      screen2.clear();
      screen2.noBacklight();

    }
    else { //if morning alarm just went off
      //turn off alarm, set alarm time to the night alarm, turn off the speaker,
      //set the wakeup time, calculate and display time slept, 
      //display advice depending on amount of time slept
      DS3231M.clearAlarm();
      DS3231M.setAlarm(minutesHoursMatch, NIGHT_ALARM2);
      sprintf(inputBuffer, "%02d:%02d", NIGHT_ALARM.hour(), NIGHT_ALARM.minute());
      ALARM = !ALARM;
      noTone(BUZ_PIN);
      wakeTime = DS3231M.now();
      WAKE_HOUR = wakeTime.hour();
      WAKE_MIN = wakeTime.minute();
      WAKE_SEC = wakeTime.second();

      HOURS_SLEPT = WAKE_HOUR - SLEEP_HOUR;
      MINS_SLEPT = WAKE_MIN - SLEEP_MIN;
      SECS_SLEPT = WAKE_SEC - SLEEP_SEC;

      //account for any negative numbers from the subtraction
      if (SECS_SLEPT < 0)
      {
        MINS_SLEPT -= 1;
        SECS_SLEPT += 60;
      }
      if (MINS_SLEPT < 0)
      {
        HOURS_SLEPT -= 1;
        MINS_SLEPT += 60;
      }
      if (HOURS_SLEPT < 0)
      {
        HOURS_SLEPT += 12;
      }
      Serial.println("time slept:");
      screen2.clear();
      screen2.backlight();
      screen2.home();
      screen2.print("time slept: ");
      sprintf(inputBuffer, "%02d:%02d:%02d", HOURS_SLEPT, MINS_SLEPT, SECS_SLEPT);
      Serial.println(inputBuffer);

      screen2.print(inputBuffer);
      if (HOURS_SLEPT < 8)
      {
        if (HOURS_SLEPT < 5)
        {
          screen2.setCursor(0, 1);
          screen2.print("Try going to bed");
          screen2.setCursor(0, 2);
          screen2.print("early today, you got");
          screen2.setCursor(0, 3);
          screen2.print("very little sleep.");
          Serial.println("Try going to bed early today, you got very little sleep.");
        }
        else
        {
          screen2.setCursor(0, 1);
          screen2.print("You got less than");
          screen2.setCursor(0, 2);
          screen2.print("8 hours, try to get");
          screen2.setCursor(0, 3);
          screen2.print("more sleep.");
          Serial.println("You slept less than 8 hours, try to get more sleep.");
        }
      }

      else if (SLEEP_HOUR != NIGHT_ALARM.hour())
      {
        screen2.setCursor(0, 1);
        screen2.print("You didn't go to bed");
        screen2.setCursor(0, 2);
        screen2.print("on time, try to stay");
        screen2.setCursor(0, 3);
        screen2.print("on schedule.");
        Serial.println("You didn't go to bed on time, try to stay on schedule.");
      }
      else
      {
        screen2.setCursor(0, 1);
        screen2.print("You got a good");
        screen2.setCursor(0, 2);
        screen2.print("amount of sleep,");
        screen2.setCursor(0, 3);
        screen2.print("good job!");
        Serial.println("You got a good amount of sleep, good job!");
      }
    }

  }
  if (digitalRead(SNOOZE_BUT_PIN)) //if snooze button is pressed
  {
    if (DS3231M.isAlarm()) //if an alarm is going off
    {
      if (SNOOZES < 3) //if snooze button has been hit less than 3 times
      {
        delay(200); //debounce button
        //turn off alarm for ten seconds
        DS3231M.clearAlarm(); 
        DS3231M.setAlarm(minutesHoursMatch, (0, 0, 0, now + TimeSpan(0, 0, 10, 0)));
        digitalWrite(LED_PIN, 0);
        noTone(BUZ_PIN);
        SNOOZES += 1;
      }
      else //if snooze button has been hit 3 or more times
      {
        if (ALARM)
        {
          screen2.clear();
          screen2.home();
          screen2.print("You need to go to");
          screen2.setCursor(0, 1);
          screen2.print("bed!");
        }
        else
        {
          screen2.clear();
          screen2.backlight();
          screen2.home();
          screen2.print("You need to go get");
          screen2.setCursor(0, 1);
          screen2.print("up!");

        }

      }


    }
  }
  if (DS3231M.isAlarm()) //if the alarm is going off
  {

    if (ALARM)
    {
      digitalWrite(LED_PIN, 1); //turn on led
    }
    else
    {
      tone(BUZ_PIN, 1000); //play a loud annoying sound
    }


  }
}