Smart Alarm Clock Using Magicbit(Arduino)
by magicbit in Circuits > Arduino
690 Views, 3 Favorites, 0 Comments
Smart Alarm Clock Using Magicbit(Arduino)
This tutorial shows how to make a smart alarm clock using OLED display in Magicbit dev board without using any RTC module.
Supplies
- Magicbit
- USB-A to Micro-USB Cable
Story
In this tutorial we will learn about how to make a smart Alarm clock using Magicbit.
HARDWARE SETUP
Plug your Magicbit to computer using USB cable.
SOFTWARE SETUP
Open your Arduino IDE and setup the board with Arduino IDE. The following link refers how to do that. So we recommend you to that first go to link and getting familiar with Magic bit.
https://magicbit-arduino.readthedocs.io/en/latest/...
Now select correct board type and port. In this case the board type is Magicbit. The libraries are already installed when the in Magicbit libraries.
Theory and Methodology
If you look at the first video, you can see the display have 2 screens.
- clock screen which showing time detail
- alarm screen which showing alarm details
For toggle between these two screen we used any push button of two in Magicbit. These buttons are connected to 35(left button) and 34(right button) pins of the ESP32 in Magicbit. To show the time and other details we used builtin OLED display in magicbit.
Lets talk about how does these graphic screens are working.
The clock screen has analog clock, digital clock, date, month and year texts.
For creating analog clock we use some graphics functions which are available in graphics library called Adafriut GFX. By using circle function and line function we create analog clock face. Simple geometrical functions called sin and cos are use to the position of the clock hands. So we only input the angle which correspond to time for for rotate hands. for that we first converts the time to angle as follows.
- angle of minute hand=minutes*(360/60)
- angle of hours hand=hours*(360/12)
The angle measured with respect to line between center of the clock face and number 12 in clock face.Using sin and cos functions we can calculate the x and y coordinates of the ends of hour and minutes lines. The below picture describe how it is doing.
According coordinates we print hour and minute hand by draw lines. There is also have text print function in Adafruit GFX library. It helps to print other details (date, month and time show in digits) on display. You can change the analog clock position and text positions by changing parameters in the code.
As like as clock screen we used text print function in the Adafruit GFX library for print numbers on OLED display at appropriate places.
Getting the Local Time
The most important part of the clock is how we get the local time accurately. For that purpose you can use external RTC clock module or inbuilt RC clock in ESP32 in Magicbit. In this project we used second method. In this method we use NTP (network time protocall ) client for gets the local time from internet. For access internet we used inbuilt WIFI facility in the ESP32. Therefor at the first stage we use WIFI for access the internet by providing SSID and password. Then we should configure the gmtOffset and daylightOffset in variables in seconds. The values of these variables are differ from region to region in the world. gmtOffset means number of seconds you differ from the GMT..For most ares daylightOffset is 3600. You can found it in the internet. After we got the current local time we not longer used WIFI. Because then we calculate local time from inbuilt RC clock in ESP32. This is done by using time.h library. There is simple example in Arduino( Arduino>Examples> ESP32> Time>simpletime) for you to learn about how this works further. Also these links are you can use for further knowledge about NTP client.
After getting the local time correctly, we change our time showing texts and angle according to that time information in every loop.
Setting Up the Alarm
By clicking the left and right buttons you can change the alarm date and time selection. Make sure turn off the alarm when you changing the alarm date and time. After set up the date and time turn on the alarm. Because if the alarm is on and when alarm time is equal to your current time while you setting up it, the alarm buzzer will ring. In the main loop always checks the current local time and alarm information are equal. If those are equal, then buzzer and built in green LED in Magicbit will work during one minute.
Setting Up the Buzzer
We use PWM pulse to create the buzzer sound by using analogCwrite() function in the code. Because of the all library functions are in ESP32 is valid for Magicbit. You can change the beep sound of the buzzer from change it's frequency and PWM value in the code.
https://techtutorialsx.com/2017/06/15/esp32-arduin...
This page describes about how buzzer works with ESP32.
Setting Up Buttons
For changing the all states we used two built in push buttons in Magicbit. Main loop always check the state of two buttons. Because they pulled up internally, there normal state is high signal. So you can see the digital read of those pins are 1. At the default stage the display shows clock interface. At that time, when any of the two button is pressed, then it change screen to alarm screen. Also we count the time in seconds from the last time when button is pressed. If that count is larger than some predefined duration then the display will show the clock screen.
The code is written by using basic functions for beginners. So the code is simple to understand and you can learn the method how it works by referring the code.
Troubleshooting
Some times the clock is start bit later or it don't display the graphics properly. Following tips help to solve situation.
- Make sure you gave the right SSID and password
- Change the NTP server (you can find many servers from internet which relates to your region).
- Changes the internet connection.(mobile hotspot can also possible).
Also you can troubleshoot everything by using the serial monitor. In addition to the OLED display serial monitor shows time information.
Arduino Code
//libraries for OLED display
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define OLED_RESET 4 #include <WiFi.h>//wifi library for connect #include "time.h"//library for use RC clock //define input and output pin names #define RightButton 34 #define LeftButton 35 #define GreenLED 16 #define Buzzer 25 int preTime = 0; int counts = 0; int currentTime = 0; struct tm timeinfo; const char* ssid = "YOUR SSID";//wifi details const char* password = "YOUR PASSWORD"; int alarmDateTime[5] = {1, 1, 2020, 0, 0};//alarm varibles int dateIndex = 0; int timeIndex = 0; int selectIndex = -1; bool buzzerOn = 0; int rect[6][4] = {{5, 0, 118, 16}, {1, 22, 30, 22}, {37, 22, 30, 22}, {73, 22, 55, 22}, {31, 44, 30, 20}, {67, 44, 30, 20}};//selection rectangle const char* ntpServer = "asia.pool.ntp.org";//server detais const long gmtOffset_sec = 19800; const int daylightOffset_sec = 0; Adafruit_SSD1306 display(128, 64);//OLED size define byte clockCenterY = (display.height() + 16) / 2;//analog clock face details byte clockCenterX = (display.height() - 16) / 2; byte clockRadius = 23; bool state = 0;//screen on or off boolean Alarm = 0;//alarm current state String alarmState = "Alarm ON";//alarm on or off //varibles stored time data char dayName[10]; char daynumber[3]; char month[10]; char year[5]; char hours[3]; char minutes[3]; char monthnumber[3]; char seconds[3]; //button variables bool RightState = 1; bool LeftState = 1; //buzzer variables int channel = 0; int Frequency = 2000; int PWM = 200; int resolution = 8; void setup() { //set input and ouputs pinMode(RightButton, INPUT); pinMode(LeftButton, INPUT); pinMode(GreenLED, OUTPUT); pinMode(Buzzer, OUTPUT); display.begin(SSD1306_SWITCHCAPVCC, 0x3C);//intialize display display.display(); delay(3000); display.clearDisplay(); ledcSetup(0, Frequency, resolution);//configure pwm parameters ledcAttachPin(Buzzer, 0); Serial.begin(115200);//intilize serial communication //connect to WiFi Serial.printf("Connecting to %s ", ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(" CONNECTED"); //init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); getTime(); //disconnect WiFi as it's no longer needed WiFi.disconnect(true); WiFi.mode(WIFI_OFF); display.clearDisplay(); } void loop() { getTime();//get current time //store right and left pushbutton states RightState = digitalRead(RightButton); LeftState = digitalRead(LeftButton); //chaeck the buttouns are pressed if (RightState == 0 || LeftState == 0) { ledcWrite(0, 200);//when button is pressed the buzzer emit beep sound delay(100); if (state == 0) {//change to alarm screen frame state = 1;//change state to alarm state RightState = LeftState = 1;//we only need change sceern } counts = 0;//reset counter } if (state == 1 && (counts) < 5) {//if in alarm screen and no timeout calculateAlarm();//calculate time values of alarm informaton showAlarm();//show values } else {//if in clock screen state = 0; display.clearDisplay(); clockFace();//analog clock face printLocalTime();//print time in clock face and print other details } onAlarm();//compare alarm timewith local time and turn on the alarm delay(100);//delay for alarm on and off } void clockFace() { //caalog clock face display.drawCircle(clockCenterX, clockCenterY, clockRadius, WHITE);//print watch circle for (int digit = 0; digit < 12; digit++) { //print watch digits float digitAngle = digit * 30.0 * PI / 180.0; display.drawLine(clockCenterX + (clockRadius - 3)*sin(digitAngle), clockCenterY - (clockRadius - 3)*cos(digitAngle), clockCenterX + (clockRadius)*sin(digitAngle), clockCenterY - (clockRadius)*cos(digitAngle), WHITE); } display.fillCircle(clockCenterX, clockCenterY, 2, WHITE);//print watch center } void calculateAlarm() { //set alarm date and time display.clearDisplay(); if (LeftState == 0) { //left button to change selction selectIndex++; } if (selectIndex >= 5) { //only have 5 selctions.so reset to -1(-1= is alarn on or off) selectIndex = -1; } dateAndTimeSelection(selectIndex);//change selction } void dateAndTimeSelection(int index) { if (index == -1) { //alarm on or off if (RightState == 0) { //togle between on and off alarm if (alarmState == "Alarm ON") { alarmState = "Alarm OFF"; } else { alarmState = "Alarm ON"; } } } else { if (RightState == 0) { //in other selctions icrement the relate date or time in array alarmDateTime[index] = alarmDateTime[index] + 1; //index is the selection } } int compare[4] = {12, 2030, 23, 59}; //upper limits of the dates and years int comparemonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //upper limi of the months int resetValue[4] = {1, 2020, 0, 0}; //starting values for (int i = 1; i < 5; i++) { //reset vlaues if dates or years are larger than their limis if (alarmDateTime[i] > compare[i - 1]) { alarmDateTime[i] = resetValue[i - 1]; } } if (alarmDateTime[0] > comparemonth[alarmDateTime[1] - 1]) { //reset vlaues if months are larger than their limits alarmDateTime[0] = 1; } } void showAlarm() { //print alarm details String alarmDateTime0 = String(alarmDateTime[0]); //convert stings to show String alarmDateTime1 = String(alarmDateTime[1]); String alarmDateTime2 = String(alarmDateTime[2]); String alarmDateTime3 = String(alarmDateTime[3]); String alarmDateTime4 = String(alarmDateTime[4]); //if values have one 1 digita the add "0" to them. if (alarmDateTime[0] < 10) { alarmDateTime0 = "0" + String(alarmDateTime[0]); } if (alarmDateTime[1] < 10) { alarmDateTime1 = "0" + String(alarmDateTime[1]); } if (alarmDateTime[3] < 10) { alarmDateTime3 = "0" + String(alarmDateTime[3]); } if (alarmDateTime[4] < 10) { alarmDateTime4 = "0" + String(alarmDateTime[4]); } //select position and print the details display.setTextSize(2); // Normal 1:1 pixel scale display.setTextColor(WHITE); // Draw white text display.setCursor(15, 0); display.println(alarmState); display.setCursor(5, 25); display.println(alarmDateTime0 + ":" + alarmDateTime1 + ":" + alarmDateTime2); display.setCursor(35, 48); display.println(alarmDateTime3 + ":" + alarmDateTime4); display.drawRect(rect[selectIndex + 1][0], rect[selectIndex + 1][1], rect[selectIndex + 1][2], rect[selectIndex + 1][3], WHITE); display.display(); } void onAlarm() { //turn on and of the alarm if ((alarmState == "Alarm ON") && (String(daynumber).toInt() == alarmDateTime[0]) && (String(monthnumber).toInt() == alarmDateTime[1]) && (String(year).toInt() == alarmDateTime[2]) && (String(hours).toInt() == alarmDateTime[3]) && (String(minutes).toInt() == alarmDateTime[4]) ) //comapare with local time { ledcWrite(0, PWM * buzzerOn); digitalWrite(GreenLED, 1 * buzzerOn); buzzerOn = !buzzerOn; //turn on and off buzzer Alarm = 1; } else { ledcWrite(0, 0); //if not on alarm Alarm = 0; digitalWrite(16, LOW); } } void printLocalTime() { Date(dayName, daynumber, month, year); int minuteAngle = String(minutes).toInt() * 6; int hourAngle = (String(hours).toInt() + (minuteAngle / 360.0)) * 30.0; Minute(minuteAngle); Hour(hourAngle); digitShow(String(hours) + ":" + String(minutes)); display.display(); } void Hour(float hourAngle) { //calculate angles arrow head float delta = (PI * hourAngle / 180.0); float delta1 = (PI * (hourAngle - 10) / 180.0); float delta2 = (PI * (hourAngle + 10) / 180.0); int trangleX0 = clockCenterX + (clockRadius - 10) * sin(delta); int trangleX1 = clockCenterX + (clockRadius - 15) * sin(delta1); int trangleX2 = clockCenterX + (clockRadius - 15) * sin(delta2); int trangleY0 = clockCenterY - (clockRadius - 10) * cos(delta); int trangleY1 = clockCenterY - (clockRadius - 15) * cos(delta1); int trangleY2 = clockCenterY - (clockRadius - 15) * cos(delta2); display.drawLine(clockCenterX, clockCenterY, clockCenterX + (clockRadius - 10)*sin(delta), clockCenterY - (clockRadius - 10)*cos(delta), WHITE); //print hour hand display.fillTriangle(trangleX0, trangleY0, trangleX1, trangleY1, trangleX2, trangleY2, WHITE); //print arrow head } void Minute(float minuteAngle) { float delta = (PI * minuteAngle / 180.0); //calculate angle of minute hand(minute hand dont have arrow head) display.drawLine(clockCenterX, clockCenterY, clockCenterX + (clockRadius - 5)*sin(delta), clockCenterY - (clockRadius - 5)*cos(delta), WHITE); //print minute hand } void digitShow(String Time) { //print time in digits display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(57, 30); display.print(Time); } void Date(String dateName, String date, String month, String year) { //print date/month/year display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0, 0); display.print(dateName + " "); display.print(date); display.print(" / "); display.print(month); display.print(" / "); display.println(year); } void getTime() { if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); return; } //get time informations seperatly strftime(dayName, 4, "%A", &timeinfo); strftime(daynumber, 3, "%d", &timeinfo); strftime(month, 4, "%B", &timeinfo); strftime(year, 5, "%Y", &timeinfo); strftime(hours, 3, "%H", &timeinfo); strftime(minutes, 3, "%M", &timeinfo); strftime(monthnumber, 3, "%m", &timeinfo); strftime(seconds, 3, "%S", &timeinfo); currentTime = String(seconds).toInt(); //conevert string to intiger if (currentTime != preTime) { counts++; } preTime = currentTime; Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");//print time in serial monitor }