PHYS S-12: Introduction to Digital Fabrication
About Me

Final Project Documentation


Demo Video


To set the alarm from a website via Firebase from anywhere with internet access, here's the link.

Table of Contents:

-Demo Video/Memory Alarm Website
-Introduction
-Project Development
-Initial Proposal
-3D Modeling
-Hardware/Circuit
-Programming
-Alarm (Firebase)
-Time (NTP Client)
-Memory Game
-Combining Everything
-Future Goals
-Downloads

Introduction


My goal was to create an alarm without a snooze button that would require the user to complete a memory game to turn off the alarm. This would force them to wake up their brain, which would make it more likely for them to actually get out of bed.

The alarm utilizes an LCD display to show the time and has four different colored LED arcade buttons on the top that are used during the memory game. Internally, the alarm has a buzzer that beeps for the alarm and also makes sounds for the memory game. There are speaker grills cut into the left and right side to allow for louder sound from the buzzer.

The time on the LCD display is fetched from an NTP Client that updates without delay every second as long as the alarm is not ringing. The alarm time is set via a Firebase website, which can also edit the amount of memory game rounds that the user is required to complete to turn off the alarm. The memory game initiates when the previously set alarm time is equal to the time via the NTP Client. When playing the memory game, the alarm is momentarily stopped, but if the player presses the wrong button in the sequence or waits more than three seconds between button presses, the alarm will resume beeping, and the player will have to restart the memory game. If the player successfully makes it through the set number of rounds, the alarm is turned off and a short victory jingle is played.


Initial Final Project Proposal: Simon Says Alarm Clock

June 23, 2020

Proposal: I have a bit of trouble waking up in the mornings (to the point where I usually have to set several alarms five minutes apart to even wake up). I was thinking of designing an alarm clock that would work like those old Hasbro Simon Says games, forcing me to use my memory to turn off the alarm sound. It could use 4 different color LED lights that could light up in a specific pattern with specific sounds, and I would have to repeat the pattern to turn off the alarm.

I have absolutely no programming or fabrication experience, so I hope that this project is feasible.

Simon Says


3D Modeling

July 13, 2020

Today I modeled the enclosure of my Simon Says alarm clock in Fusion 360! This file would be laser-cut on either plywood or acrylic. Here's my process in designing the alarm clock box.

First, I drew a sketch by hand of my alarm clock. I intend to buy light-up arcade buttons in 4 different colors which have a diameter of 30 mm to use as the Simon Says buttons. These will be located on the top of the clock. Then I will use an LCD display to show the time and mount it on the front of the box. Finally, both the left and right sides of the clock will have speaker grills for the Piezo buzzer.

Alarm Clock Sketch

I used Makercase to design a 120x120x120 mm box with finger joints and then imported that .stl file into Fusion 360 to make some modifications. I started with designing the top of the box by sketching out holes for the arcade buttons to fit into and then extruding the surrounding area.

Buttons Sketch

The next side I designed was the front of the box with the LCD display. Victoria helped me by measuring her own LCD display with a caliper and writing down the dimensions for me, which I used in sketching out the display and mounting holes.

LCD Display Sketch

Lastly, and probably the most difficult, was designing the speaker grills. I ended up sketching four hexagons and using the rectangular pattern feature to spread the pattern across the entire diameter of the circle where I wanted the speaker grills. This took a lot of trial and error, and my Fusion 360 actually crashed twice because of how complex the pattern was. Luckily, I finally managed to get the right dimensions of the hexagons and the space between hexagons.

Speaker Grill Sketch

I extruded the honeycomb pattern and the space around the speaker cut-out to finish that side. Then, I made that side into a component. I copied and pasted the component for the opposite side. And after extruding the back and bottom of the alarm clock box without making any modifications, I finished my preliminary design!

Finished Box

Download my .dxf file here!

Download my 3D model file here!

Edit: Initially, I exported the .dxf file from Fusion 360 but found that this would only export my sketches, including my sketch lines that I didn't want. To fix this, I had to create a sketch on the xy-plane and project all of the lines of my sides onto the sketch, then I saved that sketch as a .dxf. This seemed to solve the problem!


Hardware/Circuit

July 28, 2020

Most of my progress on my final project this week was hardware-wise. Since my buttons and LCD display for my final project finally came in the mail, I was able to solder the components for my final project this week. I've never soldered before, so I was very nervous when handling the soldering iron and solder. However, after watching several YouTube videos on how to solder, I finally gathered up the courage to solder my components.

I started with the LCD display. The display came with 16 pins that I had to solder onto the 1602 LCD display. To do this, I first inserted the pins into the sockets on the display and propped it up on the table to solder it. Since I was using 60/40 solder which contains lead, I was really worried about the health risks, so I ended up wearing safety googles, gardening gloves, and a face mask while soldering, and I set up a table outside so that there would be good circulation while I was soldering. You can never be too safe! When I started to solder, I realized that I should have followed Victoria's advice and gotten a pointed tip instead of using the included chisel tip in the box since it was really hard to precisely press the soldering iron onto the joint since the tip was so big.

Me Soldering

When soldering, I made sure to clean the soldering iron with the sponge and tin it occasionally. To melt the solder, I pressed the soldering iron onto the joint and pressed the solder to the other side of the joint rather than the iron. Although my soldering does not look perfect, I checked the connections with my multimeter afterwards and made sure that the LCD display worked by using some sample code from the SunFounder website.

LCD Soldered

Next, I soldered wires onto the arcade button terminals. Since the laser-cut parts that I sent to be printed arrived in the mail, I was able to screw in the buttons to allow for the buttons to stay in place better while I was soldering. Before soldering, I twisted the wires into the terminals to make better connections. I also connected the ground wires for the switch and LED in each button to minimize the amount of wires coming out from the buttons. This was easier than the LCD display to solder since the chisel tip was not too big to perform the task, but I realized that sometimes I wasn't careful with my wires and accidentally touched them to the hot metal rod while I was soldering the joints. As a result, some of the rubber burnt off, but the metal wire was only exposed on one wire, so hopefully this will not pose any problems.

Buttons Soldered

With my LCD display soldered, I was able to finish adding it to my original circuit with my Huzzah board and buzzer. In order to allow for the adjustment of the contrast on the LCD display, I hooked a potentiometer into the circuit as well. Since my box will not fit the long breadboard, I used one of the smaller breadboards.

Circuit

Here's how the clock looks before being mounted onto the box.

Working Clock

I had some trouble mounting the LCD display since I didn't account for the backlight when designing my 3D parts, so I didn't cut out a space for it. The backlight prevents the display from sitting flush against the wood, but I was still able to screw in the other side, and the LCD display luckily stays in place.

The buttons were very easy to mount since they came with adapter rings that pretty much acted like nuts that keep the buttons in place. After mounting the buttons and LCD display, I used tape to hold the box together while still working on the circuit.

Initially, I didn't know if the Huzzah would have enough pins for my buzzer, LCD display, and arcade buttons, but luckily there were enough. I was worried I would have to connect another Huzzah and use serial communication between the boards to get more pins, but I didn't have to in the end. However, I had to spend a lot of time analyzing the pinout guide for the Huzzah since some of the pins were input-only or didn't have pull-up resistors, which I needed for my arcade buttons. Some of the GPIO pins are also not recommended for input or output. Nevertheless, eventually I finally picked the right pins and connected everything! It's a bit messy, but as long as it works, appearance doesn't matter since the circuit will be inside the alarm box anyways. I had to create myself a table to keep track of all the pins I was using, and here's a picture of the circuit (it's pretty messy).

Final Circuit

Since the circuit picture is pretty messy, I will explain it. First, the LCD display, which takes up quite a lot of pins. I put a potentiometer in the breadboard and connected the left pin to power and the right pin to ground. For the LCD display, I connected VSS to the ground strip, VDD to the power strip, VO to the middle pin of of the potentiometer, RS to pin 32, RW to the ground strip, E to 15, D4 to 33, D5 to 27, D6 to 14, D7 to 13, A to the power strip, and K to ground. I connected a piezzo buzzer with a 1K resistor to pin 5. Then I connected each of the ground wires from the buttons to the ground strip. I connected the red LED to pin 17, green LED to pin 26, blue LED to pin 25, and yellow LED to pin 16. I connected the control for the red button to pin 23, the green button to pin 19, the blue button to 22, and the yellow button to 18.

Once I finished building the circuit, I used Elmer's glue to stick the pieces together. Here's the finished product!

Final Product


Programming

Alarm (Firebase)

July 21, 2020

I needed a way to set alarms by making sure my Huzzah can receive instructions from an external website to know when to ring the alarm. During class, we learned about IoT, so I decided to use Firebase to control my Huzzah from a website coded in HTML/Javascript. I created a realtime database, and since Firebase sends data in a string format to the Huzzah, I made a variable called alarmString which stored the data received from Firebase so that I would be able to compare that variable with another variable that would represent the actual time.

Although I could manually change the ALARM_TIME value in Firebase to set the alarm, I wanted to create a website where I would be able to do so. I used an input tag in HTML whose type was text so that I would be able to type something into the text box and call on it to get a string value. I haven't written code in JavaScript before, so I had to learn a few things to make a function that would take the value of that input and make it into a JavaScript variable which would update the ALARM_TIME value in Firebase. I also added an alert so that whoever sets the alarm will know that they successfully set the alarm. Here's what the initial website looked like:

Website

And here's the code.

Later on, I decided to also use Firebase to change the number of Simon Says rounds that a player would have to complete to turn off the alarm. I named a new variable called rounds which would be changed in the same way as the alarm time by manually typing in a number. However, I needed this value to be an integer value. I tried to get the integer from Firebase but ran into lots of problems, so I instead opted to get the value as a string value from Firebase and parse an integer from the string in Arduino IDE.


  Firebase.get(firebaseData, "/rounds"); //get # of Simon Says rounds from firebase
  roundsString = firebaseData.stringData();
  rounds = roundsString.toInt(); //convert string into integer

I also wanted to display the set alarm time and number of rounds to the player on the website, which I was easily able to accomplish by using document.getElementById("alarmtimes").innerHTML = alarmTime and assigning an id called alarmtimes to the space where I wanted the updated alarm time to appear. Once this was done, I cleaned up my website and added some CSS design to make it have a better interface. Here is how it looks!

Final Website


Time (NTP Client)

July 21, 2020

Since my final project is an alarm clock, I need a way to use the Huzzah as a web client and get the time from an API.

To start off, I followed a tutorial to get accurate date and time information from an NTP Client-Server. Since I live in the PST time zone, I had to offset the time given by the server by -25200 milliseconds, or -8 hours. However, I had a lot of trouble with converting the time info from the NTP Server into a string data type, getting error after error whenever I tried to upload the sketch onto the Huzzah.

Eventually, I decided to start from scratch with a different method. Instead of just calling the NTP Client-Server, I installed the NTPClient library. This library had a function called timeClient.getFormattedTime(), which I was able to set a string called FormattedTime equal to, although the formatted time came in the format "HH:MM:SS". Since I didn't care about seconds, I used a substring to only include the relevant "HH:MM" information in the string.


FormattedTime = timeClient.getFormattedTime(); //get formatted time string in format "HH:MM:SS"
int splitT = FormattedTime.indexOf("T");
actualTime = FormattedTime.substring(splitT + 1, FormattedTime.length() - 3); //split FormattedTime string to format "HH:MM"
delay (1000);
  

This method allowed me to finally make a comparison between the string of data from Firebase and the string of data representing the time from the NTP server. I connected a buzzer in my circuit with a 1K resistor on pin 5 which would buzz if the two strings were equal. I used this if-statement to compare the two strings:


if (alarmString == actualTime) {                    // compare the alarm string from Firebase to the string representing the actual time from the NTP server
  Serial.println("Alarm Turned ON");
  myTone(buzzerPin, 262, 500); // sound the buzzer alarm
  delay(1000);
} else {             // if the strings don't match, then there will be no alarm
  Serial.println("Alarm Turned OFF");
}  

This finally worked! However, I soon realized that I had no way to turn off the alarm. Thus, I added a button into my circuit on pin 21 with a pull-down resistor. I modified the myTone function with an if statement which would keep the buzzer buzzing unless the button was pressed. I haven't yet gotten the button to work how I want it to. Ideally, I would want the button to turn off the buzzer after being pushed, but my code only allows for the buzzer to stop if the button is continuously pushed down, and the buzzer automatically stops once the time changes by a minute. When I actually make my final project, I will try to have this issue solved. Nevertheless, here's the code:


void myTone(int pin, int frequency, int duration) {
  int buttonState = digitalRead (button);
  int startTime = millis();
  int period = 1000000 / frequency;
  if (buttonState == LOW) { //button is not pressed, so buzzer sounds
    while ((millis() - startTime) < duration) {
      digitalWrite(pin, HIGH);
      delayMicroseconds(period / 2);
      digitalWrite(pin, LOW);
      delayMicroseconds(period / 2);
    }
  } else {
    digitalWrite(pin, LOW); //button is pressed, so buzzer stops
  }
}

Here's the clock in action!

Later on when I received my LCD display in the mail, I figured out how to use it to display the time. Since I already had a variable that gives the actual time, I just had to call on that variable in led.print and set the cursor to the middle of the screen to center the time. I put the calculations for finding the actual time as well as the LCD displaying the time in a while loop that would function as long as the board was connected to Wifi since the time on the display needs to update when the time gotten from the NTP server changes. Here is the code for that:


while (WiFi.status() == WL_CONNECTED) {
  FormattedTime = timeClient.getFormattedTime(); //gives current PST time in HH:MM:SS
  int splitT = FormattedTime.indexOf("T");
  actualTime = FormattedTime.substring(splitT + 1, FormattedTime.length() - 3); //splits current PST time string to HH:MM
  Serial.println (actualTime);
  lcd.setCursor(5, 0); //begin display on line 1, space 5
  lcd.print(actualTime);
  }
  

Memory Game

July 30, 2020


I knew I needed to create functions which would light-up the buttons when they were pressed, so I initially created state machines for every single button color.


 int blueButton = 22;
int greenButton = 19;
int redButton = 23;
int yellowButton = 18;

int blueLed = 25;
int greenLed = 26;
int redLed = 17;
int yellowLed = 16;

int buzzerPin = 5;

void setup(){
  Serial.begin(115200);
  pinMode(blueButton, INPUT_PULLUP);
  pinMode(greenButton, INPUT_PULLUP);
  pinMode(redButton, INPUT_PULLUP);
  pinMode(yellowButton, INPUT_PULLUP);
  pinMode(blueLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(redLed, OUTPUT);
  pinMode(yellowLed, OUTPUT);
}
void bluePress(){
  int blueVal = digitalRead(blueButton);
  if (blueVal == HIGH) {
    digitalWrite(blueLed, LOW);
  } else {
    digitalWrite(blueLed, HIGH);
  }
}
void greenPress(){
  int greenVal = digitalRead(greenButton);
  if (greenVal == HIGH) {
    digitalWrite(greenLed, LOW);
  } else {
    digitalWrite(greenLed, HIGH);
  }
}
void redPress(){
  int redVal = digitalRead(redButton);
  if (redVal == HIGH) {
    digitalWrite(redLed, LOW);
  } else {
    digitalWrite(redLed, HIGH);
  }
}
void yellowPress(){
  int yellowVal = digitalRead(yellowButton);
  if (yellowVal == HIGH) {
    digitalWrite(yellowLed, LOW);
  } else {
    digitalWrite(yellowLed, HIGH);
  }
}
void loop(){
  bluePress();
  greenPress();
  redPress();
  yellowPress();
}
  

However, after class today where Rob introduced Object Oriented Programming and C++ classes, I attempted to repackage the code as a C++ class. This made the code a lot cleaner and simpler. Here is the code:


class buttonPress{
  int ledPin;
  int buttonPin;
  int buttonVal; 
public:
buttonPress(int button, int led){
buttonPin = button;
ledPin = led;
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);

}
void Update(){
  int buttonVal = digitalRead(buttonPin);
  if (buttonVal == HIGH) {
    digitalWrite(ledPin, LOW);
  } else {
    digitalWrite(ledPin, HIGH);
  }
}
};

buttonPress blue(22, 25);
buttonPress red(23, 17);
buttonPress yellow(18, 16);
buttonPress green(19, 26);


void setup(){
}
void loop(){
  blue.Update();
  red.Update();
  yellow.Update();
  green.Update();
}
  

Here's the buttons in action!

Button Presses


July 31, 2020

Today I wanted to try to program the Simon Says mechanism. I used this sparkfun tutorial sample code to learn how to create the mechanism.

It seems as if my code from yesterday with the light-up buttons is not needed, but I am still glad that I learned more about OOP through that code.

This Simon Says code works by defining an array called gameBoard and using random() to generate a byte from 0 to 3 corresponding to certain colored buttons that are added to the game sequence. A function called playMoves() plays back the current game board and then another function called wait_for_button returns a byte called choice that is compared to the current move on the array. If the player presses the correct color, then they move onto the next round. A boolean called play_memory contains the functions related to game play and returns a boolean value once the player either wins or loses. Since the original code had a lot of extra features such as two other game modes, I modified the code to take up less memory.

I took out the extra two game modes and defined different pins corresponding to my output devices. Instead of defining the number of rounds, I made it into an integer that I intend to be able to control from Firebase. I also removed the time-out function of the game. In addition, since I need to use the buzzer to play the alarm sound, I removed the sounds associated with the Simon Says game. Here is the code of the Simon Says mechanism before I attempted to merge it with my alarm code.


Combining Everything

August 1-5, 2020


Now that all of the separate components were ready, I needed to combine my alarm code with my Simon Says code. I knew that I would need to use millis to get the time from the NTP server without delay, and I also wanted to use millis with my alarm code and Simon Says code so that the time would keep updating even when playing the game.

Little did I know just how difficult it would be to convert everything to millis. Since the Huzzah can't use the tone function, I had initially made it buzz using Nathan's myTone function, but it used delays. However, he gave me a modified version of the myTone function that used classes and allowed buzzing without delay. Except this code was very difficult to integrate with my Simon Says mechanic. Luckily, Rob helped me figure out how to sound the buzzer with PWM, and I was able to use PWM and modify the blink without delay code to get my buzzer working without delay! I'm glad that both my time display and buzzer are now working simultaneously, although the Simon Says mechanism will be the hardest to get working without delay. Here's the code for the buzzer without delay!


if (alarm_condition == 1) { //function for alarm buzzing
    if (currentMillis - alarmMillis >= beep) {
      alarmMillis = currentMillis;
      if (buzzerState == LOW) {
        ledcWriteTone(buzzerChannel, 1500);
        ledcWrite (buzzerChannel, 125);
        buzzerState = HIGH;
      } else {
        ledcWriteTone(buzzerChannel, 1500);
        ledcWrite(buzzerChannel, 0);
        buzzerState = LOW;
      }
    }
  }
  

Converting the Simon Says game to use no delays was a nightmare. It uses both while loops and for loops for its main gameplay mechanics, which are both blocking. I spent so much time trying to convert all of the various delays in the game and almost ran out of time to finish my programming before final presentations. I had to create some code that would turn off the alarm with a press of a button without the Simon game in case I couldn't figure out the Simon game in time.

However, I had a breakthrough two days before final presentations. I realized that there was really no reason for me to have the time display, beeping, and Simon game running simultaneously as I originally thought. The time display only needed to run until the alarmString was equal to actualTime, which would activate the buzzer's beeping. By replacing the time on the LCD display with a basic statement of "Memory Game!", I didn't need to deal with the NTP Client running simultaneously with the buzzer or Simon game. As long as the NTP Client updated right after the player turned off the alarm, it would work! Even the buzzer didn't need to run at the same time as the Simon Game and could restart if the player failed or timed out of the game. Thus, the Simon Game could be blocking with no problem! Once I realized this, my approach to the programming changed drastically.

It was easy to add variables that make sure the time display is not updated when the alarm starts ringing. While the alarm was ringing, the LED arcade buttons would flash until the player pressed a button, which would initiate the Simon game and momentarily turn off the time display and alarm beeping functions. I pretty much used the original Simon Says code that I wrote, but I put back the sounds of the buttons and changed the winner sound to use PWM. I replaced the winner sound with the victory fanfare from FFVII since I'm a nerd.I also handled the simon boolean a bit differently. If the player lost, two variables would be set to true, which would stop the Simon function and start the alarm beeping function. I also added more actions if the player completed the Simon game, which would ensure that the Simon and alarm beeping functions would be false and shut down, leaving only the time display function to update without delay until the alarmString=actualTime condition was met again.

The only problem left was that the buzzer's beeping wasn't consistent due to a delay somewhere in the code. However, with Nathan's help, I realized that this was due to the time client and Firebase updating every second. To remedy this, I just had to make sure that the function which fetched these was not active during the period in which the alarm was beeping. This was super easy to fix by just adding an extra condition to the function which fetched these strings.

At last, here is the final Arduino sketch for my Memory Alarm!


Future Goals


I am extremely pleased with the final product. It works almost exactly as I had wanted, and I'm amazed that I was able to create such a product having started off with literally zero experience in 3D design, Arduino, Javascript, etc.

If I could redesign the laser-cut parts, I would only make sure I cut out an indentation in the front piece for the backlight of the LCD display so it would mount better. However, the rest of my design is fine.

Since the Huzzah uses 3 volts instead of 5 volts like is suggested for the LCD display, the LCD display does not have a very good contrast between the background and characters, even if I set the potentiometer to its maximum value. I experimented a little with trying to remove the potentiometer and manually set both the backlight and contrast, but this requires two analog out pins, and I didn't have enough of these pins on the Huzzah to plug in two more wires. Perhaps if I reworked the circuit, I might be able to do so.

Programming-wise, the only problem that the program seems to have is that if the player completes the Simon game in less than a minute before the time has changed to make alarmString != actualTime, the alarm will not shut off and it will continue beeping until the minute changes and the user completes the Simon game again. If I had more time, I would refine this.

Another thing I would add if I could would be different victory songs after completion of the Simon game, although it would be more difficult than using the tone function since I would have to use PWM and account for delays for note durations as well as short delays in between notes. Ideally if I could add songs, the user's preferred victory song could be assigned on the Firebase website.

Speaking of the Firebase website, I also wish that I could make the inputs more user-friendly and less prone to error if the time is inputted the wrong way, but this will most likely require javascript, and I am inexperienced with that. Perhaps in the future, I can improve the alarm setting interface once I learn more javascript.


Downloads


DXF file

3D model file

Arduino sketch

Alarm-setting Website HTML

Alarm-setting Website CSS