Magicbit
Published

Smart Alarm Clock Using Magicbit (ESP32)

This tutorial shows how to make a smart alarm clock using OLED display in Magicbit dev board without using any RTC module

BeginnerProtip2,241
Smart Alarm Clock Using Magicbit (ESP32)

Things used in this project

Hardware components

Magicbit
×1
USB-A to Micro-USB Cable
USB-A to Micro-USB Cable
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

Arduino code of smart alarm clock based on Magicbit

Arduino
//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

}

Credits

Magicbit

Magicbit

57 projects • 34 followers
Magicbit is an integrated development platform based on ESP32 for learning, prototyping, coding, electronics, robotics, IoT and more.

Comments