Silent Alarm Clock With OLED Display
by AH Electronics in Circuits > Gadgets
2129 Views, 13 Favorites, 0 Comments
Silent Alarm Clock With OLED Display
Waking up is hard, especially as a college student who barely gets any sleep. For me alarms are absolutely necessary, because left to myself I would sleep over 12 hours before waking up.
But I have non-scientifically come to the following conclusions after years of relying on alarm clocks:
- Loud alarms leave me with a headache, and a tendency to turn them off in my sleep the moment I hear it.
- If I lower the alarm volume, I automatically tune out the alarm noise after a while.
- People sharing dorm with me, and especially roommates absolutely hate my alarm.
So I looked at alternate methods of waking up. Alarms on vibrate mode works well, since they are much gentler on my ears and head and wake me up over the span of a longer time. But I have to leave my phone right under me, or my pillow, otherwise I would miss the vibration.
But I liked the idea of using vibration as a method of waking up, and thus I came up with the idea to make the silent alarm clock which I can wear.
Obviously I wanted to be able to use it, but even if I couldn't use the first prototypes, I wanted to meet certain goals:
- Be inexpensive and use parts commonly used in hobbyist electronics projects.
- Power efficient, nobody likes charging gadgets for niche functions.
- Be modifiable, through code.
- Not be an absolute eyesore or pain to put on.
This Silent Alarm Clock costed me about 12$ to build. I used a 3d printer to print out a suitable case, but you could definitely go with a small box or any other makeshift solution you can find. The battery should theoretically last about a week, but I haven't been able to test it to that time limit. It can store alarms in flash memory of the microcontroller, and so it will remember the alarms even if power is disconnected. The Code is pretty modifiable, and doesn't require subtraction, only addition to the code to add new options.
The build was inexpensive and it was definitely functional, with some areas to be improved, which I will talk about later in the Instructable.
***********************************************
One more thing. I am a student at Stony Brook University, and I'm putting this Instructable in the Back to School: Student Design Challenge.
***********************************************
This Instructable is going to be divided into several parts, here is a breakdown:
1) Supplies
2) Implementation of the Silent Alarm Clock
3) Overview of the parts used: Step 2-4
4) Schematic and How the circuit works
5) Coding Overview
6) Code implementation: Step 7-10
7) Testing and Soldering Circuit: Step 11-12
7) 3d Design and Assembly: Step 13-14
8) Troubleshooting tips and files for the project (3d Model, Schematic, Code)
Supplies
Circuit components:
- Resistors : 470k, 100k.
- Rotary Encoder with Built in Switch: link
- Wemos D1 Mini based on ESP8266 : link
- Wemos D1 Mini battery shield with charging/boosting for LIPO battery: link
- 2N7000 N-Channel MOSFET X 2
- 0.96'' OLED Display with I2C display SSD1306 Driver : link
- Disc Vibrating Motors X 2 or 3: link
- Lithium polymer battery: I used 320 mAh one. Try to pick the physically smaller one.
Software:
- Arduino IDE
- Drivers/libraries for the device.
Testing supplies:
- Breadboard
- Jumper Cables
- Multimeter
- Micro-usb cable to upload the code
Prototyping:
- 3d Printer
- Flexible armband
- Soldering Station
- Hot glue
- Super glue
Circuit Prototyping:
- Printed Circuit Board from JLCPCB or PCBway or homemade one.
If PCB printing is not an option, then consider the following:
- Perfboard
- Single row female header connectors with long leads
- Wires for connections
- Electrical tape
- Soldering Helping hands
Silent Alarm Clock: Implementation
This device is built using the Wemos D1 Mini which is based on the ESP8266 module, which lets it connect to the internet. The D1 Mini also has 11 digital I/O pins and an Analog I pin, which was more than enough for than enough for me. Although it is not as robust as a dedicated Arduino with a ESP8266 module, it was plenty for me. I used a MOSFET and Disc shaped vibrating motors for the alarm ringing.
I used an OLED display that is widely used for the display and a rotary encoder with a switch for navigating through the interface, and selecting things.
When it comes to power, the D1 mini requires 5V and the ESP8266 module requires 3.7 Volts. Small Li-po batteries provide 3.7V which is not enough for the D1 mini. Also since its not completely stable output (3.3-4.2V) I didn't want to fry the ESP8266 by connecting it directly. So I bought a battery shield for the D1 Mini which can both charge the Li-Po battery and boost its voltage from 3.7V to 5V.
Finally, I used a MOSFET to implement Deep Sleep in the device for when it is idle to save power and extend its life by magnitudes.
A 3d Printed case will be used to place the build. It will be made wearable by using an elastic Armband. I included some early choices of design.
**************************************************
Here's how to use the device:
Clicking on the encoder button causes the device to wake up from sleep, and display time. This is main menu. You can scroll using the rotary encoder to the other menu options, Alarms, Battery, Shut down. Going into Alarms will allow you to Edit or Delete alarms. Battery will show the battery percentage, and shut down will put the device into deep sleep.
Scroll to the desired option and click to enter. Modify the alarms, and when it rings, click on the encoder button again to close the alarm and delete it.
A gif of the interface and some design drawings have been included in the pictures of this step.
Component Overview: Wemos D1 Mini
Device Overview:
This project was the first time I used this microcontroller, so instead of taking my word on the device it would be better to crosscheck things from the sources linked below:
Visit this link for an overview of Wemos D1 Mini: Overview
This link here is the official website which contains everything from datasheet, tutorials, their Github and other useful information. So go there for in depth dive.
In this build I used 8 of the 11 Digital pins, 1 Analog pin. The best part of this device is that it can be programmed with the Arduino software, which is what I am familiar with and many others know to use as well.
1 important thing to note. While the RST pin is connected to a pin or voltage source, the device can not be flashed. In my build, I used a detachable wire to connect the connection from MOSFET to RST pin, otherwise I wouldn't be able to flash the code to the device.
***********************************************
Power consumption:
The Wemos D1 Mini draws about 67 mA of current when it is searching for WiFi connections or is connected to a WiFi. This makes it much more power consuming than other microcontrollers. Thankfully the D1 Mini has 3 different sleep modes to reduce power consumption.
-Modem Sleep : 15 mA
-Light Sleep : 0.4 mA
-Deep Sleep : ~20 uA
Check the picture and this link for more information on the sleep modes.
The sleep mode that is useful for us in this project is the Deep Sleep mode, which consumes the least amount of power. When the device goes into Deep Sleep, it turns off the CPU and Wifi. When the RST pin is pulled LOW, the device wakes up from sleep. This could be done using an external switch or from an internal timing signal generated from pin D0. I used both Pin D0 for the timing signal and the encoder switch for an external stimuli to wake up the D1 Mini from deep sleep.
Light sleep was worth considering because of the availability of GPIO interrupts, but it was too buggy for the timed wakeup.
Component Overview: OLED Display
The first picture shows the proper connection of the I2C interface based OLED display with D1 Mini. By Default pins D1 and D2 are set to be the I2C enabled pins. However with some internal coding magic beyond my understanding, it can easily be set to any of the other Digital Pins (link). Which is what I did, and the new connection is shown in the second picture, which is much more compact in terms of connecting by soldering.
It uses the Adafruit GFX library and Adafruit SSD1306 Library for the coding, and here's a great Instructable with lots of examples of different graphics functions you can make to display different things on the display. Instructable by Tonygo2
Be careful to note which type of Display you bought. Some of these displays are single color (white) while others are blue and yellow. Depending on that you would have to set the color in the code.
Component Overview: Rotary Encoder Switch
The rotary encoder switch has 5 pins. 2 pins for the switch, and 3 for the rotary encoder.
On the side with the pins for the rotary encoder the middle pin is connected to Ground. The two outputs pins A and B have two contacts placed inside the encoder. When we rotate the encoder, there is a rotating plate that is always connected to ground, which momentarily makes contact with the Output contacts A or B or both. Since the output pins are pulled High at other times, when the contacts make contact with ground plate, the output signal goes Low, and based on the voltage at the output pin we can determine the direction of rotation and change in rotational position.
It might seem complicated to figure out how to decipher the proper rotation and direction, but Arduino has libraries to make it possible and I used one such library to do the rotation tracking for me.
Visit this link for more information on rotary encoders: link
Circuit Schematic and How It Works
Here is the schematic of the whole circuit.
In the second picture you can see that I highlighted a box covering the Micro Usb+ Charge+Boost shield. That is because I could not find a schematic diagram of the Wemos D1 Mini Battery shield. But the battery shield has all of those components built in. But in case you can not use the battery shield, you easily replace it with a micro usb, and a TP4056 based LiPo charging and boosting module.
In the third picture you can see there is a MOSFET with Pin D7 connecting to its gate. This is used to control the "wake up" signal that connects to RST. Providing a Low Pulse to the RST pin resets the device and wakes it up from deep sleep. This is generally sent by the pin D0 which has a timer for the deep sleep. But I wanted to be able to wake it up with a button press as well. So I wanted both D0 and switch input to go to the RST pin. But the problem is once the device wakes up, and I use the switch to interact with the device for other purposes it will unknowingly activate the RST pin and reset the device. That is why the MOSFET is important. When the device is turned on, pin D7 provides a Low level signal to the MOSFET, turning it off, and not conduction any Voltage pulse from D0 or Switch to RST Pin. But when the device goes to sleep, D7 is pulled high internally by default, and the MOSFET begins conducting, and so you can use D0 or the switch to reset.
As I mentioned earlier, while the RST pin is connected to a pin or voltage source, the device can not be flashed. In my build, I used a detachable wire to connect the connection from MOSFET to RST pin, otherwise I wouldn't be able to flash the code to the device.
In the final image you can see the MOSFET connection with the vibrating motors. I used two but you could use more. Depending on the motor and how much current you are consuming you might want to try to change the way they are connected, but for me the motors didn't draw too much current or heat up at all.
Coding Overview: Idea
So the main goal of the device is to display time and ring an alarm when the time matches the alarm.
The things the code needs to do to achieve that:
-Get the time using Wifi
-Have a method to change or set alarms
-Compare current time to all of the alarms
To use the device, the code also needs to provide a user interface. And to control the device power usage, it needs to know when to sleep.
My code is based on State machines, where it has a function for current state and next state. In the current state function it will do tasks based on the input and the current state. In the next state function, it will calculate what the next state should be based on the current state and inputs.
Hopefully the diagrams will describe the basic flow of the program.
Code Implementation: Preparation
First thing we need to do is to prepare our Arduino IDE to be able code and flash the Wemos D1 Mini. For that once again this tutorial is extremely helpful, but I will give a small rundown.
Go to Arduino IDE > Menu > File > Preferences > Additional Boards Manger Urls - Insert the following link : http://arduino.esp8266.com/stable/package_esp8266com_index.json
Close the box. Go back to Arduino IDE>Tools> Board> Board Manager> In the search box type : Node MCU. Select ESP8266 and Install.
Now under Tools>Board>Esp8266> Lolin Wemos D1 R2 & Mini.
You should be able to start compiling for and flashing the Wemos D1 Mini board.
Secondly install the libraries shown in the picture above by searching for them.
File > Sketch > Include Library > Manage Library> Search for the libraries you want.
Here are the exact names of the libraries and their authors:
RotaryEncoder by Matthias Hertel
Adafruit GFX Library by Adafruit
Adafruit SSD1306 by Adafruit
NTPClient by Fabrice Weinberg
The others I believe should be installed by default or from adding the boards above.
Next I will briefly go over some of the codes, and where to get more info on using them. The full code will be linked in the final step with all the files.
Code Implementation: Wifi and Time Using NTP
Right after the library inclusions in the code, there are two lines declaring the character array for the wifi SSID and Password. Make sure to change the value inside the quotation marks to whatever wifi you have to connect to.
const char *ssid = "Wifi"; //Enter the ssid of your wifi
const char *password = "Password"; //Enter the password of your wifi
We are using NTP client to get the time for the device. More info. The following code shows how to get the time:
NTPClient timeClient(ntpUDP, "north-america.pool.ntp.org"); // choose server to get the time from,
//ideally choose the ones closer to your region
timeClient.begin();
timeClient.update(); //updates time from the timeclient
int hour= timeClient.getHours();
int min= timeClient.getMinutes(); // timeClient.get Whatever you want, so hour min sec epoctime day etc.
Code Implementation: Current State
To implement the state machine, I had a function for current state calculation, and another function for next state calculation. The switching of one state to the next is done inside the current state calculation.
The current state function is a simple switch statement, where the selection is the the value of the rotary encoder.
switch(state) {
case 0 : // first get the state, then the selection and do some action based off of it
if(selectMenu == 0){
//Do whatever is needed for selection 0
}
if(nextState == 1 ){ //using if statement because some states were buggy while coding
state = 1; //switches state to the next state
}
break;
The next state function switches based on the current state and based on the press of a button selects next state:
switch(currentState) {
case 0 :
if((selection == 1) && (buttonState == HIGH)){
pressRead(); // indicates the button press has been read
return 1; // 1 here is the next state
}
Code Implementation: Sleep and Write to EEPROM
The call to deep sleep is pretty simple. It is one line of code:
ESP.deepSleep(sleepTimeMicroSeconds); // to write in seconds put "sec"e6, so ESP.deepSleep(10e6); for 10s
After that specific amount of time pin D0 sends a Low pulse which should reach the RST pin and reset the program, and it starts back from setup(). If you want to make it sleep without a timer, and just dependent on external input:
ESP.deepSleep(0); //it will never wake up until you externally provide a Low pulse to RST
For more information on deep sleep and light sleep, go here: link
One problem with using Deep Sleep is that it restarts from setup again, and any temporary memory in SRAM is erased. So if I set an alarm and the device went to sleep, then the alarm would be gone when the device wakes up again. So I needed to write it permanently to memory. Writing to EEPROM would save it and have it there even after waking up from sleep.
In ESP8266 chip, EEPROM is simulated in the Flash memory. It basically creates a Cache in the Ram, and stores whatever value you want to write, and then you have to call the function EEPROM.commit() to write it into the flash memory. You can read from the EEPROM as many times as you want, but writing to it has a lifespan of about 100000, which is more than enough for this device to last a long time.
EEPROM.begin(512); //opens a 512 byte array to store the EEPROM stuff
EEPROM.put(3, integerValue); // it takes 4 bytes to store int, so address goes from 0-3, 4-7 etc.
EEPROM.commit(); //writes the value into the "EEPROM"
Go to this link for more information.
The rest of the code has lots of comments throughout and is very simple in its writing (I am a noob at coding, so I can't do any fancy stuff). So take a look through the code for a better understanding of the rest.
Soldering the Circuit- Part 1
It would be best to print out a PCB to put the device together but I didn't. So I just did it the old fashioned way.
I took a small perfboard and started soldering the circuit. First I put tape on electronics that could get shorted on the board. I put the Battery shield and the D1 Mini on opposite sides of the board, and used a Female row connector with long pins to connect through the D1 Mini, board and the Battery shield. Then I soldered it.
I went according to the design I planned earlier, and placed the rotary encoder right next to the board, and soldered the components around it. Refer to the schematic for the connections.
Soldering the Circuit- Part 2
One important thing to note is that if there there is a detachable wire that connects to the connector on the RST pin (refer to first picture). If there is a Voltage source connected to the RST pin, I had issues flashing code into the D1 Mini. I wanted to be able to change the code even after soldering, so made the connection from the MOSFET drain to the RST pin detachable.
The rest of the connections were not that complex other than the MOSFETS. Refer to the 2N7000 pinout diagram for the proper connections. Use a two pin connector for the battery. Make sure to not connect the battery the wrong direction and burn your battery shield. You should hopefully have a working device.
3D Model and Design
The case truly depends on the way you solder your circuit. My design was pretty compact so I made a 80X50X30 mm case in Fusion 360. I used only the extrusion, and fillet feature to keep it simple.
The top was a sliding piece, and there was a piece at the bottom that would glue in an elastic band to the case.
Build Assembly
Secure the device with enough hot glue to ensure there wouldn't be any shorts. Pay special attention to hot glue the connection of the thin wires of the vibrator for support. Peel off the sticker from the vibrator and stick it to the bottom or the side of the case. Put hot glue over it and then put the alarm clock. Then slide in the top piece. Make sure the ports are accessible from the sides. Take the elastic band and slide it into the bottom piece and then glue the bottom piece to the bottom of the case. Make sure you can still move the elastic band after gluing the bottom piece.
Now take a step back and look at the amount of effort you put in and the result of your effort.
Tips and Files
So here's the final product. It is not too uncomfortable to wear. If you are not someone who rolls around in their sleep it should be fine. So far I have used this to wake up from naps, but for longer sleeps I am waiting to make some modifications to the bottom plate so it doesn't itch my arm. Two vibrating motors are a bit overwhelming at 5V, but its not too bad, just worried about the longevity of the motors. Overall I am happy with the result. But here are some things I would like to improve on this:
Make the device use a sliding potentiometer instead of a tall rotary encoder to make it thinner. I would also like to make it look better. I would like to switch the thick lithium polymer battery and have a battery shield with reverse polarity protection.
I would also like to try alternate methods of calculating time, since connecting to Wi-Fi for time is pretty demanding on energy consumption. The code could be reduced to 200-300 lines if I didn't use a billion if-else statements, and if the OLED displaying functions didn't require manual instructions for cursor placement and such.
*****************************************************
Troubleshooting:
If you are having trouble flashing code into the device, check whether or not you have accidentally connected something to RST pin.
If you OLED keeps writing jumbled lines on top of previous lines, make sure to clear the display.
If your encoder is not working in the code, try flipping it around. My code sets a limit on the lower limit of the encoders rotation data.
Try to print out stuff to serial monitor to see which part of the code is giving you issues. Also remember there is a 4-5 second delay when you first turn on the device, because it has to search for the wifi and connect to it. There are ways to reduce that reconnect time which I couldn't implement but you might want to look into.
Check the datasheet and pin diagram for all the inputs while working with them. The analog input can not take more than 3.2 volt input, which is why I used the resistor to create a voltage divider. But if you feed a voltage signal larger than 3.2 volts without the additional resistor you could have burned up your Analog input port.
Some ports are internally set as pullups, keep track of those.
If you have any other issues let me know in the comments.
Feel free to take whatever from the code here that you want. If I made any mistakes, please let me know. Wish you the best of luck in your building endeavors.
**************************************************
Anyway, if you managed to make it here, thank you for reading!
If you managed to skim to here, thank you for skimming!
If you managed to jump to here, thank you still!
See you on my next build.