Natural Wakeup

Aiden Magee

Reflective (chrome) acrylic surface with "Natural Wakeup" engraved in the top, an LCD screen with the current time and wakeup time in the middle, and a cutout for the LED below the screen.

Front view of the device with the power on and the wakeup time not set. 

This project serves as an assistive wakeup device. On the side, there are buttons and dials to enter the desired wakeup time.  Thirty minutes before that time is reached, this device will flood my room with light, starting dim and brightening over the thirty-minute period to simulate a sunrise. 

View from above of clear acrylic box, which is housing many small circuit boards in the top and a large heatsink in the center. Everything is taped down with black electrical tape and multicolored wires are scattered overtop.

Rear view (with the back panel detached). Almost all of the components were taped down. The Real Time Clock module is in the top right, the LCD is to its left, and below that is the LED. The LED requires a large heatsink, as seen in the center, and a high-current LED driver, which is vertical and on top of the heatsink (if you look closely you can see its copper coil). 

Green circuitboard taped down do clear acrylic housing with black electrical tape. Multicolored wires soldered into the board coming from all directions. Resistors soldered into the board as well.

All of the components were soldered to a small protoboard for robustness. 

Right side view of the clock interface. The red button in the middle and the toggle switch below are surface mounted using their threads and accompanying nuts. 

amagee_NaturalWakeup.mp4

In this video, I show the operation of the device.  When the clock starts up, there will be no wakeup time.  When I flip the toggle switch on the bottom middle, the device enters its "time setting state". The potentiometer is used to skim through the times and the red button is used to cycle through the time scale (hours, minutes, or seconds). Once the desired time is inputted, I flip back down the toggle switch to lock it in. Once the wakeup sequence begins and the LED is on, a simple press of the red button will turn off the LED and reset the wakeup time.

Process

The LCD is in the foreground. On it reads the current time and the wakeup time. A breadboard and an Arduino are in the background with wires connected everything together. .

I began with just an Arduino,  a Real Time Clock module, and an LCD display. I hardcoded in values for the wakeup time. 

Breadboard with clock module on it in the center. Turned off LCD screen below it. To the left there is an LED attached to a heatsink and to the top there is an Arduino.

I next added the LED, its high-current LED driver, and its heatsink. 

Looking through the glass of a large laser-cutter you can see my clear acrylic housing being cut.

Laser cutting the housing out of acrylic.

View from above of my housing. Some components are fastened to the box, while most are scattered throughout. Multicolored wires are running all over the place in the box.

Beginning assembly. Managing all the wires and individual components while ensuring that they didn't get unplugged from the Arduino was a struggle. 

The LED in particular presented a challenge. Given that I wanted a light bright enough to simulate a sunrise, I needed to choose a high-power LED. The high-power demands necessitate different components, such as a high-current motor driver to ensure the current is stable and great enough to produce the desired brightness. In addition, the LED needed thermal paste and a heatsink to prevent it from burning out. 

In the future, I will think more about what material I make my housing out of.  At the time of construction, I thought the clear acrylic was cool as it would allow me to see the inner workings of my device. While that was achieved, I probably should have thought twice about whether this would have been a pure novelty or whether it would take away from the aesthetics of my final product. Given my lack of forethought into how I wanted to fasten down my components, I chose to strap down many of them with electrical tape.  As a result, the final circuity wasn't exactly the prettiest, and an opaque housing would have disguised this. 

Discussion

While I was proud of my final product, I wasn’t fully satisfied with it and I recognize that I have a lot of room to improve in the domain of physical computing. 

Most of the critiques I received pertained to my light, such as, “(The) Light is so bright” and “Consider the color temperature for the light (this looks like blue light) and warmer could be nicer.” While I don’t agree that my light is too bright, I think the issue lies in the fact the LED produces a very concentrated stream of light. As another piece of feedback noted, “(an) LED is a raw emitter… Maybe add something to diffuse the light or filter to make the (direct) brightness more tolerable.” Given that I want a light bright enough to flood my room with light, I believe that my light is the right brightness. I just need to modulate the stream of light which is inherently very concentrated, and as mentioned above I believe that a diffuser would achieve that. Regarding my light temperature, I do agree that the LED is cooler than I would have hoped despite being listed as a “warm” LED. 

I am quite happy with how my project turned out given that about halfway through I thought that I had a real challenge in choosing an LED. I feared that the LEDs I had on hand wouldn’t be bright enough, and I delved deep into the world of high-power LEDs, and even considered using a conventional lightbulb with a complex dimming circuit. Fortunately, I felt that the LEDs I had access to were bright enough so this additional complication was avoided. 

I believe the biggest flaw with my project involves my use of electrical tape to fasten down my LED and heatsink. As Professor Zach pointed out, my heatsink may not function properly given that I have covered a lot with tape. While this hasn’t presented any immediate issues, I am almost certain that I will be shortening the lifespan of my LED and project as a whole as a result. 

I learned quite a bit about my limitations during the project, namely my poor fabrication skills. Given my experience as an engineer, for example in electronics labs, I have always strove for functionality over aesthetics. This often meant producing large and clunky circuits on breadboards that were good enough to give me the desired reading. What I now know is that design and aesthetics go hand in hand with functionality when you are trying to produce a product for repeated use. Going forward I will think much more carefully beforehand about my design rather than trying to throw everything in a box. Forethought will prevent small mistakes waiting to happen such as components getting shorted or unplugged or such as my heatsink which is covered in electrical tape. 

I do believe that I will revisit this project. I hope to make a more compact version that features a diffuse light and other features such as a built-in speaker which will which will take my product from a device that functions in conjunction with my phone alarm clock to a standalone alarm clock. I would likely construct my device out of an opaque material such as wood and carefully design my box with designated spots for certain components and screw holes so that I can properly fasten them down. I think that by taking these measures, I will not only produce a device that is more aesthetically pleasing, but I believe that it will function better and last longer. 



Technical information

Block diagram of my circuit, featuring a green background and black blocks with descriptions on them.
Schematic of my circuit, featuring a green background and black components with descriptions on them.

/**

 Natural Wakeup code by Aiden Magee


 Code functions to operate a wakeup device. It uses a button, switch, and dial (potentiometer) to allow

 users to set a wakeup time. "wakeup_duration" seconds before the wakeup time is reached, the LED will

 start emitting light. The brightness of the light will increase until its max, which will occur at the

 set wakeup time. Once the device is in "waking up" state, the press of the red button on the side will

 reset the device to be in idle state with no wakeup time.


 pin mappings:       POWER_PIN = 4;

                     SWITCH_PIN = 6;

                     BUTTON_PIN = 5;

                     LED_PIN = 3;

                     DIAL_PIN = A0;


Credit to "DS3231_Serial_Easy"

Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved

web: http://www.RinkyDinkElectronics.com/


**/


#include <Wire.h>

#include <LiquidCrystal_I2C.h>

#include <DS3231.h>


#define POTENTIOMETER_MAX 950


const int POWER_PIN = 4;

const int SWITCH_PIN = 6;

const int BUTTON_PIN = 5;

const int LED_PIN = 3;

const int DIAL_PIN = A0;


int prevButtonState = 0;

int buttonState = 0;

int switchState = 0;

// in sec


const float wakeup_duration = 60.0*1.0;

String wakeup_time = "N/A";

enum State {IDLE, WAKING, SETTING_TIME};

enum Timeframe {HOUR, MIN, SEC};

State state = IDLE;

Timeframe currently_setting = HOUR;

String led_start = "N/A";

float wakeup_start;

float wakeup_end;




// Initialize clock module

DS3231  rtc(SDA, SCL);

// Initialize lcd module

LiquidCrystal_I2C lcd(0x27,20,4);



String get_wakeup_time(){

 unsigned int firstColon = wakeup_time.indexOf(":");

 unsigned int secondColon = wakeup_time.lastIndexOf(":");

 String hour = String(wakeup_time.charAt(firstColon-2)) + String(wakeup_time.charAt(firstColon-1));

 String min = String(wakeup_time.charAt(firstColon+1)) + String(wakeup_time.charAt(firstColon+2));

 String sec = String(wakeup_time.charAt(secondColon+1)) + String(wakeup_time.charAt(secondColon+2));

 int time[3];

 time[0] = hour.toInt();

 time[1] = min.toInt();

 time[2] = sec.toInt();

 switch(currently_setting){

   case HOUR:{

     time[0] = map(analogRead(DIAL_PIN), 0, POTENTIOMETER_MAX, 1, 23);

     break;

   }

   default:{

     time[currently_setting] = map(analogRead(DIAL_PIN), 0, POTENTIOMETER_MAX, 0, 59);

   }

 }

 time[0] = time[0] % 24;

 time[1] = time[1] % 60;

 time[2] = time[2] % 60;


 String led_start = String(time[0]) + ":" + String(time[1]) + ":" + String(time[2]);

 Serial.println("led start: " + led_start);

 return led_start;

}


String produce_time_string(String hr, String min, String sec){

 // we need to pad all single digit times

 if (hr.length() == 1){

   hr = "0" + hr;

 }

 if (min.length() == 1){

   min = "0" + min;

 }

 if (sec.length() == 1){

   sec = "0" + sec;

 }

 return hr + ":" + min + ":" + sec;

}

 // This function takes in the string of wakeup time in the form HH:MM:SS and return an array of floats [hour, min, sec]

String find_led_start(String wakeup_time){

 unsigned int firstColon = wakeup_time.indexOf(":");

 unsigned int secondColon = wakeup_time.lastIndexOf(":");

 String hour = String(wakeup_time.charAt(firstColon-2)) + String(wakeup_time.charAt(firstColon-1));

 String min = String(wakeup_time.charAt(firstColon+1)) + String(wakeup_time.charAt(firstColon+2));

 String sec = String(wakeup_time.charAt(secondColon+1)) + String(wakeup_time.charAt(secondColon+2));

 int time[3];

 time[0] = hour.toInt();

 time[1] = min.toInt();

 time[2] = sec.toInt();

 // if mins < wakeup duration (in mins), decrement the hour

 if (time[1] < wakeup_duration/60.0){

   time[0] = (time[0]-1) % 24;

 }

 time[1] = (time[1] - (int)(wakeup_duration/60.0)) % 60;

 time[0] = time[0] % 24;

 time[1] = time[1] % 60;

 time[2] = time[2] % 60;

 hour = String(time[0]);

 min = String(time[1]);

 sec = String(time[2]);

 String result = produce_time_string(hour,min,sec);


 return result;

}


void setup()

{

 // Initialize objects

 lcd.init();

 lcd.backlight();

 rtc.begin();

 Serial.begin(115200);

  pinMode(LED_PIN, OUTPUT); 

 pinMode(POWER_PIN, OUTPUT);

 pinMode(SWITCH_PIN, INPUT);

 pinMode(DIAL_PIN, INPUT);


 digitalWrite(POWER_PIN, HIGH);


 // The following lines can be uncommented to set the date and time

 //rtc.setDOW(MONDAY);     // Set Day-of-Week to SUNDAY

 //rtc.setTime(12, 5, 10);     // Set the time to 12:00:00 (24hr format)

 //rtc.setDate(19, 2, 2024);   // Set the date to January 1st, 2014

}




void print_clock(String time)

{

 lcd.clear();

 lcd.home();


 String row1 = "It is  " + time;


 //Serial.println(time);


 String row2 = "Wakeup " + wakeup_time;


 lcd.print(row1);

 lcd.setCursor(0,1);

 lcd.print(row2);

}




void loop(){

 // if lever switch flipped

 String curr_time = String(rtc.getTimeStr());

 prevButtonState = buttonState;

 buttonState = digitalRead(BUTTON_PIN);

 switchState = digitalRead(SWITCH_PIN);


 switch(state){

   case IDLE:{

     Serial.println("idle");

     if (switchState){

       state = SETTING_TIME;

       break;

     }

     if (curr_time == led_start){

       state = WAKING;

       wakeup_start = millis()/(1000.0);

       wakeup_end = wakeup_start + wakeup_duration;

       break;

     }

   }

   case SETTING_TIME:{

     if (!switchState){

       state = IDLE;

       break;

     }

     // button pressed

     if (prevButtonState == 0 && buttonState == 1){

       currently_setting = (currently_setting+1)%3;

     }

     wakeup_time = get_wakeup_time();

     led_start = find_led_start(wakeup_time);

     delay(250);

     break;

   }

   case WAKING:{

     Serial.println("waking");

     int brightness = map(millis()/1000.0, wakeup_start, wakeup_end, 0, 255);

     //Serial.println("LED brightness : " + brightness);

     analogWrite(LED_PIN, brightness);

     // if button pressed state = idle, wakeup time and all its tangent variable reset to base case

     if (prevButtonState == 0 && buttonState == 1){

       wakeup_time = "N/A";

       led_start = "N/A";

       state = IDLE;

       analogWrite(LED_PIN, 0);

     }

     break;

   }

   default:

     Serial.println("Error: unrecognized state " + state);

 }


 print_clock(curr_time);

 delay(250);

}